Optimistic locking not throwing exception when manually setting version field

前端 未结 4 478
太阳男子
太阳男子 2020-12-08 17:03

I have a Spring Boot 1.3.M1 web application using Spring Data JPA. For optimistic locking, I am doing the following:

  1. Annotate the version column in the entity:
4条回答
  •  萌比男神i
    2020-12-08 17:20

    Unfortunately, (at least for Hibernate) changing the @Version field manually is not going to make it another "version". i.e. Optimistic concurrency checking is done against the version value retrieved when entity is read, not the version field of entity when it is updated.

    e.g.

    This will work

    Foo foo = fooRepo.findOne(id);  // assume version is 2 here
    foo.setSomeField(....);
    
    // Assume at this point of time someone else change the record in DB, 
    // and incrementing version in DB to 3
    
    fooRepo.flush();  // forcing an update, then Optimistic Concurrency exception will be thrown
    

    However this will not work

    Foo foo = fooRepo.findOne(id);  // assume version is 2 here
    foo.setSomeField(....);
    foo.setVersion(1);
    fooRepo.flush();  // forcing an update, no optimistic concurrency exception
                      // Coz Hibernate is "smart" enough to use the original 2 for comparison
    

    There are some way to workaround this. The most straight-forward way is probably by implementing optimistic concurrency check by yourself. I used to have a util to do the "DTO to Model" data population and I have put that version checking logic there. Another way is to put the logic in setVersion() which, instead of really setting the version, it do the version checking:

    class User {
        private int version = 0;
        //.....
    
        public void setVersion(int version) {
            if (this.version != version) {
                throw new YourOwnOptimisticConcurrencyException();
            }
        }
    
        //.....
    }
    

提交回复
热议问题