First of all locking is intended for managing transactions.
If transactions can run serial, that means one after another,
nothing can go wrong:
The transaction fulfills the ACID properties:
- atomic
- consistent
- isolated
- durable
From database view a transaction should always have these properties:
It is executed as a whole or not - atomic.
It drives the state of the database from one consistent state to another state - consistent.
Transactions do not influence each other - isolated.
Transactions and there changes are saved durably in the database - durable.
From JPA or Hibernate view the easiest way is using the highest isolation level:
Serializable.
Serial transactions in high frequent systems have a bad performance and scalability.
Therefore the level of serialization of an application / system is reduced to increase performance and throughput.
You pay this by problems which occur on account of certain isolation levels:
- Dirty Reads: Changes are read by other transactions before they are committed. If a rollback takes place you have read something wrong.
- Non repeatable Reads: Rows are read, another transaction makes changes, rows are read again, other data exists as to begin of the transaction
- Phantom Reads: a query delivers different results during a transaction
How is transaction management done in JPA?
In JPA you normally have 2 scenarios:
- JEE - environment and existence of a JTA manager
- no JEE- environment and management of transactions by the application itself
the EntityTransaction- Interface, which is delivered by EntityManager.getTransaction().
Here you have the usually methods for transaction management defined:
- begin()
- commit()
- rollback()
@Transactional(isolation=Isolation.READ_COMMITTED, propagation=Propagation.REQUIRED)
If the method is stated with @Transactional you have the behaviour like above:
the isolation level is set by the database default(usually READ_COMMITTED) and a transaction is needed.
Locking -strategies
JPA behaves like you know it from Hibernate already:
If an entity is annotated with @Version optimistic locking takes place for this entity.
Optimistic locking is the mechanism where objects are not explicitly locked at the beginning of a transaction.
It assumes that optimistically no conflict will take place. Therefore at the moment of persisting/writing on commit a version check takes place:
Every update on an entity increments the version of an entity.
The version - property of an entity can only be written by the JPA-provider.
On commit the entity is checked if it has a different version value.
If so, an OptimisticLockException is thrown.
If not the entity with the new version number is persisted in the database.
The OptimisticLockException should be handled by the application.
This behaviour is delivered by using @Version.
With Hibernate as the JPA-provider and setting the isolation level of the transaction on Repeatable Read or Serializable, the version checking is done explicitly with a select for the Entity for retrieving the actual version used in the database. This is the Hibernate specific LockMode.READ.
If the cache is used for version checking this corresponds to LockMode.NONE.
LockMode.UPGRADE corresponds to the JPA mode LockModeType.READ.
A more restrictive OptimisticLocking - mechanism can be configured by selecting the isolation level.
For that the objects which should be locked are locked by:
EntityManager.lock(object, LockModeType t);
If LockModeType.READ is set, normally during commit the corresponding object is locked by select .... from table for update:
on row level an exclusive lock is set, which is set for a very short time span.
There is LockModeType.WRITE which increments the version - also if nothing has changed on the entity.
Pessimistic Locking, that means locking of objects on transaction begin and keeping the lock during transaction is done by these 2 PessimisticLockModes:
- LockModeType.PESSIMISTIC_READ -->
entity can be read by other transactions but no changes can be made
- LockModeType.PESSIMISTIC_WRITE -->
entity can not be read or written by other transactions