У меня возникла ситуация с уровнями изоляции DB2, которую я не могу объяснить.
У меня есть транзакция с уровнем изоляции REPEATABLE_READ, который в DB2 соответствует READ_STABILITY.
У меня есть базовые знания о S-, U- и X-блокировках DB2.
Когда я параллельно выполняю следующую транзакцию 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 установит U-блокировку DB2 для возвращаемой строки, поэтому параллельная транзакция будет поставлена в очередь.
Вместо этого, чтобы заставить его работать, мне нужно добавить пессимистическую блокировку записи:
@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 должен самостоятельно обрабатывать необходимую блокировку строк, чтобы обеспечить повторяемость чтения.