Wednesday, April 13, 2011

How to write the Hibernate Transaction code on READ COMMITTED isolation level ?

I guess writing transaction codes with hibernate on READ COMMITTED isolation level is a well-tried combination. However why there isn't a good document for tips? Since the READ COMMITTED means Transaction is not atomic, we must care how transactions affect each other.

For example, if several concurrent transactions touch the same row and increment or decrement a value of a column, the value becomes inconsistent if I use save.
@Transactional
public void inc(Long id){
    E e = eDao.get(id);
    int val = e.getCount();
    e.setCount(val+1);
    eDao.save(e);
}

Since on the following sequence:

ThreadA: val = e.getCount();
ThreadB: val = e.getCount();
ThreadA: e.setCount(val+1);
ThreadB: e.setCount(val+1);
ThreadA: eDao.save(e);
ThreadB: eDao.save(e);

The "count" column is just +1 not +2.

I think there are two solutions, though I only tried the first.

First, use an "update" hcl statement. I add following methods at eDao class, and replace above codes to eDao.incCount(id);.
public void incCount(Long id) {
    getSession().createQuery("update E e set e.count = e.count + 1 where e.id=:id")
        .setParameter("id",id)
        .executeUpdate();
}
Since the update statement is an atomic operation (I guess), the above problem does not happen.

Second, replace eDao.save(e) to eDao.update(e).
@Transactional
public void inc(Long id){
    E e = eDao.get(id);
    int val = e.getCount();
    e.setCount(val+1);
    eDao.update(e); // not save!
}
It will cause "StaleStateException" when above sequence happens. Then retry transaction when the exception happens. For example,
int retry=0;
while(retry < MAX_RETRY){
    try {
        eAccessServices.inc(id);
        break;
    } catch (StaleStateException e) {
        retry++;
    }
}
The above code should be written where eAccessServices.inc(id) is called.

I guess there should be better way to solve the issue. If you know it, please let me know.

Updated (04/26/2011):
This is not related to READ COMMITTED isolation level.

Thanks.

No comments:

Post a Comment