Model structure:
@MappedSuperclass
public class BaseModel<K extends Comparable> implements Serializable, Comparable<Object> {
private static final long serialVersionUID = 1L;
@Id
private K id;
@Version
private Integer version;
// getter/setter
}
@Entity
public class MyEntity extends BaseModel<String> {
// some fields and it's getter/setter
}
Record in my database for my_entity
:
id: 1 version: 1 ...
Below is my update method:
void update(String id, Integer currentVersion, ....) {
MyEntity myEntity = myRepository.findOne(id);
myEntity.setVersion(currentVersion);
// other assignments
myRepository.save(myEntity);
}
Below is the query being fired when this method is invoked.
update my_entity set version=?, x=?, y=?, ...
where id=? and version=?
I am expecting OptimisticLockException when currentVersion
passed in above method is other than 1
.
Can any body help me why I am not getting OptimisticLockException? I am using spring-boot for my webmvc project.
Section 11.1.54 of the JPA specification notes that:
From experience, I can advise that some JPA providers (OpenJPA being one) actually throw an exception should you try to manually update the version field.
While not strictly an answer to your question, you can re-factor as below to ensure both portability between JPA providers and strict compliance with the JPA specification:
Assuming your
update(...)
method is running in a transaction however you still have an issue with the above as section 3.4.5 of the JPA specification notes:Essentially then, 2 users can submit concurrent modifications for the same Entity. Both threads can pass the initial check however one will fail when the updates are flushed to the database which may be on transaction commit i.e. after your method has completed.
In order that you can catch and handle the OptimisticLock exception, your code should then look something like the below:
Use EVICT before updating when using JPA. I did not get the @Version to work either. The property was increased but no exception was thrown when updating an object that had the wrong version-property.
The only thing I have got to work is to first EVICT the object and then save it. Then the HibernateOptimisticLockingException is thrown if the Version properties does not match.
Set the hibernates ShowSQL to 'true' to verify that the actual update sql ends with "where id=? and version=?". If the object is not evicted first, the update statement only has "where id=?", and that will (for obvious reasons) not work.