When it comes to enterprise applications, it is essential to properly manage concurrent access to a database. This means that we should be able to manage multiple transactions efficiently and, above all, without risk of error.
In addition, we must ensure that the data remains consistent between readings and simultaneous updates.
To do this, we can use the optimistic locking mechanism provided by the Java Persistence API. This means that multiple updates to the same data at the same time do not interfere with each other.
How to use optimistic locking?
To use optimistic locking, we need to have an entity including property with
@Version annotation. When in use, each transaction that reads data contains the value of the version property.
Before the transaction wants to update, it checks the version property again.
If the value has changed in the meantime, an
OptimisticLockException is thrown. Otherwise, the transaction validates the update and increments a value version property.
Optimistic locking Vs Pessimistic locking?
It is good to know that, unlike optimistic locking, JPA gives us pessimistic locking. This is another mechanism for managing concurrent access to data.
As we said before, optimistic locking relies on detecting entity changes by checking their
Version attribute. If a simultaneous update takes place,
OptimisticLockException occurs. After that, we can try to update the data again.
We can imagine that this mechanism is suitable for applications that read much more than updates or deletes. In addition, it is useful in situations where entities have to be detached for a certain period of time and locks cannot be held.
On the other hand, the pessimistic locking mechanism involves locking entities at the database level.
Each transaction can acquire a data lock. As long as it maintains the lock, no transaction can read, delete or update the locked data. We can assume that pessimistic locking can lead to blockages. However, this guarantees greater data integrity than optimistic locking.
Optimistic locking in details
Like we said before, to use optimistic locking we need to add
version attribute in the entity. So we’re going to have something like this.
When we declare the version attribute, there are several rules to follow :
- each entity class must have only one version attribute.
- the type of the version attribute must be one of the following: int, Integer, long, Long, short, Short, java.sql.Timestamp
We should know that we can retrieve a value from the version attribute via an entity, but we should neither update nor increment it. Only the persistence provider can do this, so the data remains consistent.
Note that persistence providers are capable of supporting optimistic locking for entities that do not have version attributes. It is, however, a good idea to always include version attributes when working with optimistic locking. If we try to lock an entity that does not contain this attribute and the persistence provider does not support it, this will cause a
- Optimistic: is to check the locked entity version towards the end of the current running transaction, to make sure we don’t use a stale entity state.
- Optimistic increment: it’s like the first mode but in addition, it increments the value of the version attribute.
Explicit use of optimistic locking
Even that, an optimistic lock is available by default, there are several ways to request it explicitly.
To request an optimistic lock, we can pass the appropriate
LockModeType as an argument to find the
Another way to activate locking is to use the
setLockMode method of the
We can call the
refresh method in the same way as the previous method:
And the last option is to use
@NamedQuery with the
In this article, we have become familiar with a tool that can help us orchestrate simultaneous transactions. Optimistic locking uses version attributes included in entities to control simultaneous changes to them.
Therefore, it guarantees that updates or deletions will not be overwritten or lost in silence. Unlike pessimistic locking, it does not lock entities at the database level and, therefore, is not vulnerable to database crashes.
We learned that optimistic locking is enabled for versioned entities by default. However, there are several ways to explicitly request it using different types of lock modes.
Another fact that we must remember is that whenever there are conflicting updates on entities, we should expect an exception.