How does @Version
annotation work in JPA?
I found various answers whose extract is as follows:
JPA uses a version field in your entities to detect concurrent modifications to the same datastore record. When the JPA runtime detects an attempt to concurrently modify the same record, it throws an exception to the transaction attempting to commit last.
But I am still not sure how it works.
Also as from the following lines:
You should consider version fields immutable. Changing the field value has undefined results.
Does it mean that we should declare our version field as final
?
This question is related to
java
jpa
jpa-annotations
Just adding a little more info.
JPA manages the version under the hood for you, however it doesn't do so when you update your record via JPAUpdateClause
, in such cases you need to manually add the version increment to the query.
Same can be said about updating via JPQL, i.e. not a simple change to the entity, but an update command to the database even if that is done by hibernate
Pedro
Every time an entity is updated in the database the version field will be increased by one. Every operation that updates the entity in the database will have appended WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE
to its query.
In checking affected rows of your operation the jpa framework can make sure there was no concurrent modification between loading and persisting your entity because the query would not find your entity in the database when it's version number has been increased between load and persist.
Version used to ensure that only one update in a time. JPA provider will check the version, if the expected version already increase then someone else already update the entity so an exception will be thrown.
So updating entity value would be more secure, more optimist.
If the value changes frequent, then you might consider not to use version field. For an example "an entity that has counter field, that will increased everytime a web page accessed"
Although @Pascal answer is perfectly valid, from my experience I find the code below helpful to accomplish optimistic locking:
@Entity
public class MyEntity implements Serializable {
// ...
@Version
@Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
private long version = 0L;
// ...
}
Why? Because:
@Version
is accidentally set to null
.optlock
rather than version
.First point doesn't matter if application uses only JPA for inserting data into the database, as JPA vendor will enforce 0
for @version
field at creation time. But almost always plain SQL statements are also in use (at least during unit and integration testing).
Source: Stackoverflow.com