I have a very simple domain model, one entity which has a version field in order to use the optimistic locking capabilities provided from JPA (api v2.2). The implementation i use is Hibernate v5.3.10.Final.
@Entity @Data public class Activity { @Id @SequenceGenerator(name = "gen", sequenceName = "gen_seq", allocationSize = 1) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "gen") private Long id; @Column private String state; @Version private int version; } Then there are simple operations with that entity, like for example temporarily changing its stage:
@Transactional public Activity startProgress(Long id) { var entity = activityRepository.findById(id).orElseThrow(RuntimeException::new); if (entity.getState() == "this") { // or that, or else, etc // throw some exceptions in some cases } entity.setState("IN_PROGRESS"); return activityRepository.saveAndFlush(entity); } The outcome of this, what i'd like to achieve, is to have a way to update the entity, and that update should also increment the version. If there is a mismatch, i'd expect a ObjectOptimisticLockingFailureException or OptimisticLockingException to be thrown. I'd also like to have the updated value of the version field in the object, as i'm returning it to the client.
Several options which i've tried:
- simply call
save- the version field gets updated, but the new value is not returned and the client gets the old one, which makes the next request hit the locking exception - call
saveAndFlush- in this case i get the update statement on the client executed twice, which weirdly returns version X which in the database the version is X+1. Then again the next client request hits the locking exception. - Create a
@Modifyingquery, mark it as clear automatically (to auto flush the change) and use the hqlcreate versionedsyntax. Then i get the following query executed:update activities set version=version+1, state=? where id=?, but this doesn't seem to do the optimistic lock check (where version = :version_from_entity). I also don't think it will raise the appropriate exception.
So, in the end what i'd like to achieve is quite simple and i don't think i have to write it on my own - have a way to update one or more fields on a versioned entity, rely on JPA for the optimistic locking and get the latest version so the client can do further operations with the entity. I read quite a lot of similar issues but most use the entity manager directly, which is not what i'm striving for.
@Versionannotation fromjavax.persistence?javax.persistenceand not the one from spring data commons.saveAndFlush()in my local and cannot reproduce your mentioned problem. It works as expected and no more double update happen......So in your case, what are these two UPDATE SQL look like ? Are they the same ?