我遇到了无法解释的 DB2 隔离级别的情况。
我有一个隔离级别为 REPEATABLE_READ 的事务,它在 DB2 中对应于 READ_STABILITY。
我对 DB2 S-、U-和 X-locks 有基本的了解。
当我并行执行以下 Spring 事务时,可能会导致死锁(来自 DB2 的错误是 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;
}
我希望 REPEATABLE_READ 隔离会在返回的行上设置 DB2 U 锁,以便并行事务排队。
相反,为了让它工作,我需要添加一个悲观的写锁:
@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;
}
上面的查询生成正确的锁定 SQL 并且事务工作没有死锁:
select * from .... for update with rs;
问题是,当我仍然需要手动锁定时,为什么要使用 REPEATABLE_READ 呢?我的理解是 REPEATABLE_READ 必须自己处理必要的行锁定以确保可重复读取。