我无法让SELECT FOR UPDATE在Hibernate和Oracle中工作。
当我有两个线程,每个线程有一个EntityManager时,第二个线程似乎能够读取与第一个相同的行。我可以通过添加跟踪来看到这一点,这些跟踪显示第二个线程读取同一行,而第一个线程在query.getSingleResult()
和entityManager.getTransaction().commit()
之间。我的期望是,一旦发出SELECT FOR UPDATE,其他任何人都不应该能够读取同一行,直到它被第一个线程提交。但这种情况并没有发生。
我可以使用替代实现。我想要实现的只是一个进程能够读取和更新Oracle表中的一行,以便它的行为就像一个队列,因为消费者进程可以在不同的机器上。
以下是我的代码的最小示例:
public MyMessage getNextMessage() {
String sql = "SELECT * FROM MESSAGE WHERE MESSAGE_STATUS = 'Pending' AND rownum=1 FOR UPDATE OF MESSAGE_STATUS";
entityManager.getTransaction().begin();
Query query = entityManager.createNativeQuery(sql, MyMessage.class);
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
MyMessage msg = null;
try {
msg = (MyMessage) query.getSingleResult();
} catch (NoResultException nodatafound) {
// Ignore when no data found, just return null
}
if (msg != null) {
msg.setMessageStatus("In Progress");
entityManager.persist(msg);
}
entityManager.getTransaction().commit();
return msg;
}