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.