Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - JPA - @Version annotation

People also ask

What is @version in JPA?

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.

What is the use of @version annotation?

The @Version annotation in hibernate is used for Optimistic locking while performing update operation.

What is @version in hibernate?

@Version is used to implement Optimistic locking with Hibernate, which means that no two transactions override the data at the same time with a conflict.

How do I fix optimistic lock exception?

Solution To resolve this error we have two ways: Get the latest object from the database and set the old object values if you need those values to be persisted to the new object and merge it. For the old object set the latest version from Database.


But still I am not sure how it works?

Let's say an entity MyEntity has an annotated version property:

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

On update, the field annotated with @Version will be incremented and added to the WHERE clause, something like this:

UPDATE MYENTITY SET ..., VERSION = VERSION + 1 WHERE ((ID = ?) AND (VERSION = ?))

If the WHERE clause fails to match a record (because the same entity has already been updated by another thread), then the persistence provider will throw an OptimisticLockException.

Does it mean that we should declare our version field as final

No but you could consider making the setter protected as you're not supposed to call it.


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:

  1. Optimistic locking won't work if field annotated with @Version is accidentally set to null.
  2. As this special field isn't necessarily a business version of the object, to avoid a misleading, I prefer to name such field to something like 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).


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"