🗃️ JPA Q55 / 63

What is the difference between optimistic locking and pessimistic locking?

AI-Powered Answer ✓ Answered

Locking strategies in Java Persistence API (JPA) are crucial for managing concurrent access to shared data and ensuring data integrity. When multiple transactions attempt to modify the same data simultaneously, conflicts can arise, leading to lost updates or inconsistent states. JPA offers two primary locking mechanisms to address these issues: optimistic locking and pessimistic locking, each with distinct approaches to concurrency control.

Optimistic Locking

Optimistic locking assumes that conflicts are rare. Instead of preventing concurrent access, it detects conflicts at the time of committing a transaction. If a conflict is detected, the transaction is rolled back, and the client is typically notified to retry the operation. This mechanism usually involves a version column (e.g., an integer or timestamp) in the database table. When an entity is read, its version is also read. Before an update, the version in the database is compared with the version read earlier. If they differ, it means another transaction modified the entity, and an OptimisticLockException is thrown.

  • Mechanism: Uses a version column (e.g., @Version annotation in JPA) to detect changes.
  • Concurrency: Allows multiple transactions to read and potentially modify data concurrently.
  • Conflict Resolution: Conflicts are detected at commit time; throws OptimisticLockException.
  • Performance: Generally better for read-heavy or low-contention environments as it avoids database-level locks.
  • Scalability: More scalable as it doesn't hold locks for long durations.
  • Complexity: Requires client-side retry logic upon conflict.
java
@Entity
public class Product {
    @Id
    private Long id;
    private String name;
    private double price;

    @Version
    private int version; // Optimistic lock version

    // Getters and Setters
}

Pessimistic Locking

Pessimistic locking assumes that conflicts are frequent and prevents them by acquiring exclusive locks on data from the moment it's accessed until the transaction is complete. When a transaction acquires a pessimistic lock, no other transaction can read or modify that locked data until the lock is released. This approach relies on the underlying database's locking mechanisms (e.g., SELECT ... FOR UPDATE). JPA supports pessimistic locks via LockModeType, such as PESSIMISTIC_READ (shared lock) or PESSIMISTIC_WRITE (exclusive lock).

  • Mechanism: Uses database-level locks (SELECT ... FOR UPDATE or similar) to prevent concurrent access.
  • Concurrency: Grants exclusive access to data; other transactions wait or fail if data is locked.
  • Conflict Resolution: Conflicts are prevented proactively by blocking access.
  • Performance: Can introduce contention and reduce throughput in high-contention scenarios due to blocking.
  • Scalability: Less scalable than optimistic locking due to held locks.
  • Complexity: Simpler client-side logic as conflicts are largely avoided by the locking mechanism.
java
// Example of acquiring a pessimistic write lock
Product product = entityManager.find(Product.class, productId, LockModeType.PESSIMISTIC_WRITE);

// Or within a query:
TypedQuery<Product> query = entityManager.createQuery("SELECT p FROM Product p WHERE p.id = :id", Product.class);
query.setParameter("id", productId);
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
Product product = query.getSingleResult();

Key Differences

FeatureOptimistic LockingPessimistic Locking
Conflict HandlingDetects conflicts at commit time; rolls back and retries.Prevents conflicts by blocking access.
MechanismVersion column (`@Version`)Database-level locks (`SELECT ... FOR UPDATE`)
ConcurrencyHigh (allows parallel reads/writes)Low (blocks parallel writes)
Performance (Contention)Better for low contention (less overhead)Worse for high contention (more blocking)
ScalabilityMore scalableLess scalable
Transaction AbortTransaction aborts on conflict (retries needed)Transaction waits for lock release
Database ResourceLess resource-intensive (no database locks held for long)More resource-intensive (database locks held)

When to Use Which?

The choice between optimistic and pessimistic locking depends heavily on the expected contention levels, transaction isolation requirements, and the specific use case:

  • Use Optimistic Locking when: Conflict rates are low, read operations are frequent, high scalability is required, and the application can handle transaction retries.
  • Use Pessimistic Locking when: Conflict rates are high, write operations are frequent, immediate consistency is paramount, and it's preferable for transactions to wait rather than retry upon detection of a conflict. It's often used for critical operations where even a brief inconsistency could be problematic, or when ensuring sequential processing of updates is crucial.