I have a situation with DB2 isolation levels I cannot explain.
I have a transaction with isolation level REPEATABLE_READ, which in DB2 corresponds to READ_STABILITY.
I have basic understanding on DB2 S-, U-, and X-locks.
When I execute the following Spring transaction in parallell, I can cause a deadlock (error from DB2 is FILE IN USE):
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRES_NEW)
public long getNext(int x) {
final Stuff stuff = entityManager
.createQuery("from Stuff where type = :type", Stuff.class)
.setParameter("cardType", cardType)
.getSingleResult();
stuff.setData(stuff.getData() + x);
return stuff.getData()+1;
}
I would expect that REPEATABLE_READ isolation would set a DB2 U-lock on the row returned so the parallell transaction gets queued up.
Instead, to get it working, I need to add a pessimistic write lock:
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRES_NEW)
public long getNext(int x) {
final Stuff stuff = entityManager
.createQuery("from Stuff where type = :type", Stuff.class)
.setParameter("cardType", cardType)
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getSingleResult();
stuff.setData(stuff.getData() + x);
return stuff.getData()+1;
}
The above query generates the correct locking SQL and transactions work without deadlock:
select * from .... for update with rs;
The question is, why use REPEATABLE_READ when I still need to do manual locking? My understanding is that REPEATABLE_READ must handle necessary row locking on its own to ensure repeatable reads.