adam bien's blog

Why It Is Impossible To Automatically Handle javax.persistence.OptimisticLockException 📎

A field denoted with the javax.persistence.Version annotation represents the state of the database at read (select) time. At the end of transaction the actual value of the entity is compared with the current value in the database and the entity is only going to be written back to the database in case both values are matching. If both are not equal the update "fails" (no rows are going to be updated) and javax.persistence.OptimisticLockException is thrown at the end of transactions. The unchecked OptimisticLockException causes transaction's rollback.


@Entity
public class SomeEntity {

    @Id
    private String name;

    private String description;

    @Version
    private long version;


Each database write operation also changes the version column in the DB, entity manipulations on the other hand, do not change the @Version JPA-entity field. Optimistic locking effectively prevents overriding changed columns in the database with stale values.

An occurrence of OptimisticLockException usually is an indicator of "process bottlenecks". Several users compete for the same data set, the first update will succeed, all other attempts will raise exceptions. This is very similar to merge conflicts in a source code management tool like svn, git or hg. Although there is a strategy to automatically resolve conflicts called "Override and Commit", it is not considered as best practice.

The only feasible strategy in the SCM case is manual merging and testing. Use cases in enterprise applications have a more narrow scope, so you could choose from several strategies:

  1. First update wins
  2. Last update wins
  3. Manual merging

Each choice has a big impact on the business logic, so domain experts, end users or someone with business knowledge needs to be involved. Handling javax.persistence.OptimisticLockException generically (with e.g. repeating and reloading) is only viable for simple technical use cases (e.g. primary key generation).

Retrying business transactions as a generic recovery strategy for the OptimisticLockException is only feasible for simplistic cases. Sophisticated use cases usually require merging and so User Interface adjustments.

[See also an in-depth discussion in the "Real World Java EE Patterns--Rethinking Best Practices" book (Second Iteration, "Green Book"), page 21 in, chapter "Locking for Consistency"]

See you at Java EE Workshops at MUC Airport (particularly the Effective and Architecture Days)!

Thanks Johny Newald for his comment and so idea for this post.