Optimistic locking lets concurrent transactions process simultaneously, but detects and prevent collisions, this works best for applications where most concurrent transactions do not conflict. JPA Optimistic locking allows anyone to read and update an entity, however a version check is made upon commit and an exception is thrown if the version was updated in the database since the entity was read. In JPA for Optimistic locking you annotate an attribute with @Version as shown below:

public class Employee { @ID int id;@Version int version;

The Version attribute will be incremented with a successful commit. The Version attribute can be an int, short, long, or timestamp. This results in SQL like the following:

“UPDATE Employee SET ..., version = version + 1 WHERE id = ? AND version = readVersion”

The advantages of optimistic locking are that no database locks are held which can give better scalability. The disadvantages are that the user or application must refresh and retry failed updates.

Optimistic Locking Example

In the optimistic locking example below, 2 concurrent transactions are updating employee
e1. The transaction on the left commits first causing the
e1 version attribute to be incremented with the update. The transaction on the right throws an OptimisticLockException because the e1 version attribute is higher than when
e1 was read, causing the transaction to roll back.

Additional Locking with JPA Entity Locking APIs

With JPA it is possible to lock an entity, this allows you to control when, where and which kind of locking to use. JPA 1.0 only supported Optimistic read or Optimistic write locking. JPA 2.0 supports Optimistic and Pessimistic locking, this is layered on top of @Version checking described above.

JPA 2.0 LockMode values :

OPTIMISTIC (JPA 1.0 READ):

perform a version check on locked Entity before commit, throw an OptimisticLockException if Entity version mismatch.

OPTIMISTIC_FORCE_INCREMENT (JPA 1.0 WRITE)

perform a version check on locked Entity before commit, throw an OptimisticLockException if Entity version mismatch, force an increment to the version at the end of the transaction, even if the entity is not modified.

PESSIMISTIC:

lock the database row when reading

PESSIMISTIC_FORCE_INCREMENT

lock the database row when reading, force an increment to the version at the end of the transaction, even if the entity is not modified.

There are multiple APIs to specify locking an Entity:

EntityManager methods: lock, find, refresh

Query methods: setLockMode

NamedQuery annotation: lockMode element

OPTIMISTIC (READ) LockMode Example

In the optimistic locking example below, transaction1 on the left updates the department name for
dep , which causes
dep's version attribute to be incremented. Transaction2 on the right gives an
employee a raise if he's in the "Eng" department. Version checking on the employee attribute would not throw an exception in this example since it was the
dep Version attribute that was updated in transaction1. In this example the employee change should not commit if the department was changed after reading, so an OPTIMISTIC lock is used :
em.lock(dep, OPTIMISTIC). This will cause a version check on the
dep Entity before committing transaction2 which will throw an OptimisticLockException because the
dep version attribute is higher than when
dep was read, causing the transaction to roll back.

OPTIMISTIC_FORCE_INCREMENT (write) LockMode Example

In the OPTIMISTIC_FORCE_INCREMENT locking example below, transaction2 on the right wants to be sure that the dep name does not change during the transaction, so transaction2 locks the
dep Entity
em.lock(dep, OPTIMISTIC_FORCE_INCREMENT) and then calls em.flush() which causes
dep's version attribute to be incremented in the database. This will cause any parallel updates to
dep to throw an OptimisticLockException and roll back. In transaction1 on the left at commit time when the
dep version attribute is checked and found to be stale, an OptimisticLockException is thrown

Pessimistic Concurrency

Pessimistic concurrency locks the database row when data is read, this is the equivalent of a (SELECT . . . FOR UPDATE [NOWAIT]) . Pessimistic locking ensures that transactions do not update the same entity at the same time, which can simplify application code, but it limits concurrent access to the data which can cause bad scalability and may cause deadlocks. Pessimistic locking is better for applications with a higher risk of contention among concurrent transactions.
The examples below show:

reading an entity and then locking it later

reading an entity with a lock

reading an entity, then later refreshing it with a lock

The Trade-offs are the longer you hold the lock the greater the risks of bad scalability and deadlocks. The later you lock the greater the risk of stale data, which can then cause an optimistic lock exception, if the entity was updated after reading but before locking.
The right locking approach depends on your application: