Sunday, April 8, 2018

How will you block two concurrent web application users from modifying the same underlying database row?

There are essentially two methods to handle this situation in JPA - Optimistic Locking and Pessimistic Locking. Optimistic Locking is more scalable approach which should be preferred unless there is very high thread contention.

1. Optimistic Locking Approach

All users/threads can read the data concurrently, but when more than one thread tries to update it simultaneously, the first one will win and all others will fail with OptimisticLockException, they have to try executing the update once again.
All you need to do to enable Optimistic Locking on a particular entity is to add a version field in it.
@Entity
public class Product {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;

    private long price;

    @Version    
    private long version;

}
@Version annotation enables Optimistic Locking on Productentity.

2. Pessimistic Locking Approach

When using pessimistic locking, hibernate locks the record for your exclusive use until you commit the transaction. This is typically achieved using  SELECT …​ FOR UPDATEstatement at the database level. In this case, any other transaction trying to update/access the same record will be blocked until the first transaction releases the lock.
This strategy gives better predictability at the price of performance and does not scale much. Internally it behaves like sequential access to a single record by all threads (read and write), that’s why scalability is a problem.
Typically, if you just specify the appropriate Isolation Level at the transaction level (Serializable), database will handle it automatically for you. Hibernate gives you options to obtain a exclusive pessimistic lock at the start of a new transaction. Below LockMode can be used to obtain a pessimistic lock in hibernate session.
LockMode.UPGRADE
acquired upon explicit user request using SELECT …​ FOR UPDATE on databases which support that syntax.
LockMode.UPGRADE_NOWAIT
acquired upon explicit user request using a SELECT …​ FOR UPDATE NOWAIT in Oracle.
Please be noted that using above UPGRADE modes, you want to modify the loaded object and you don’t want any other thread to change it while you are in the process until you commit the transaction.
Isolation Levels affect what you see. Lock Modes affect what you are allowed to do.

What is difference between Transaction Isolation Level and LockModes?

Isolation Levels affect what you see. Lock Modes affect what you are allowed to do.

Why not to handle Concurrency at Java level rather than database/hibernate level?

When we work with databases that support transaction, the management of concurrency must move away from Java code, and should be handled by database transaction isolation level and locking strategy. The main reasons for this are -
  1. It makes our code simpler, handling concurrency at database level is easier.
  2. If you manage concurrency at JVM level, your application will break when moved to multiple distributed JVMs, so the solution will never scale. On the other hand, database is single point of entry that can handle concurrency even if multiple JVMs are invoking parallel requests.
  3. Even if you have single JVM setup, optimistic locking may yield higher performance compared to your own hand woven synchronized Java code.

Java Source Code

Example of Pessimistic Locking using Spring Data JPA
interface Flight extends Repository<Flight, Long> {

  @Lock(LockModeType.PESSIMISTIC_WRITE)
  Flight findOne(Long id);
}
Pessimistic Locking using Spring & Hibernate
tx.begin();
Flight w = em.find(Flight.class, 1L, LockModeType.PESSIMISTIC_WRITE);
w.decrementBy(4);
em.flush();
tx.commit();

For more such questions, you can get my ebook

Cracking Core Java Interviews
Buy from Shunya @ 250 ₹ (DRM Free) Buy from Pothi.com

No comments:

Post a Comment

Your comment will be published after review from moderator