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.