n0weak
n0weak

Reputation: 750

Locking mutual transactions execution

I want to describe the issue using following example:

Let's assume that we are developing application (based on Hibernate JPA and Spring) that allows its users to perform two kind of transactional operations that have to be executed in serializable mode for each user. As far as application has to be robust and well-performing at the same time, we can use some kind of the wrapper around ReentrantLock for syncronization:

void operation1(user) {
    userLockWrapper.lock(user.id); //gets ReentrantLock for specified id from internal map and locks it
    try {   
        //start transaction 
        //perform operation
        //commit transaction    
    } finally {
        userLockWrapper.unlock(user.id).
    }   
}
void operation2(user) {
    userLockWrapper.lock(user.id); //same wrapper instance as in operation1
    //same logic as in operation1   
}

Now let's assume that in order to improve scalability we divided our system in two stand-alone modules that run in different VMs and use same database, where first one is responsible for operation1 and second – for operation2. First decision that comes into mind is using pessimistic locks, e.g.:

@Transactional
void operation1(user) { //same goes for operation2
    //firing extra select for update sql statement here
    entityManager.find(User.class, user.id, LockModeType.PESSIMISTIC_WRITE) 
    //performing operation      
}

I am wondering whether there are more preferable solutions for that. Hope to get some advices from the community.

Upvotes: 0

Views: 386

Answers (1)

JB Nizet
JB Nizet

Reputation: 691755

Yes there is. Use optimistic locking. You just have to add an @Version annotated persistent field to your entities, and understand how it works. Read http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#transactions-optimistic

Each time Hibernate writes an entity to the database, it checks that the stored version is still the same as the one in memory, and it increments this version. If the versions don't match, it throws an which makes the transaction rollback.

This is what will allow the best throughput, and it's also the only system which can be used across two transactions: first transaction loads the object, user modifies it (which can takes minutes), the second transaction merges the object.

Upvotes: 2

Related Questions