我需要什么Hibernate LockMode来读取和更新对象,同时阻止其他人这样做?

时间:2013-09-13 01:53:10

标签: java hibernate concurrency locking

在以下代码示例中:

   Session session = getSessionFactory().openSession();

   MyObject currentState = (MyObject) 
           session.get(MyObject.class, id, new LockOptions(LockMode.???));

   if (!statusToUpdateTo.equals(currentState.getStatus())) {
     tx = session.beginTransaction();

     currentState.setStatus(statusToUpdateTo);
     session.save(currentState);

     tx.commit();
   }

   session.close();

正如您可能希望从代码中解释的那样,我们的想法是检查我们的商店并找到具有给定ID的对象,然后将其更新为给定状态。如果我们发现对象已经处于我们想要更新的状态,我们就会放弃做任何事情。否则,我们会更新状态并将其保存回商店。

我担心的是,如果其中一些请求同时出现,并且所有请求都尝试读取和更新同一个对象,那该怎么办?透过doco看起来,Hibernate"通常会自动获得正确的锁定级别。" (LockMode.class)但我仍然热衷于确保只有一件事可以读取对象,做出更新它需要的决定,然后更新它 - 没有任何其他线程对同一个数据库做同样的事情条目。

从LockMode类我认为 PESSIMISTIC_WRITE就在我之后,但似乎无法找到证实这一点的文档资源。是否有人能够为我确认这一点,并且上述代码将执行我之后的操作?

1 个答案:

答案 0 :(得分:4)

所以我在原始代码中注意到,在会话关闭时,数据库上仍然存在锁定,因为后续调用删除我插入的行时,在调用tx.commit()时没有完成。

添加以下else块之后,我的测试通过了我推断的意思是锁已被释放(因为这些行现在正在被清理)。

   Session session = getSessionFactory().openSession();

   MyObject currentState = (MyObject) 
           session.get(MyObject.class, id, 
                       new LockOptions(LockMode.PESSIMISTIC_WRITE));

   if (!statusToUpdateTo.equals(currentState.getStatus())) {
     tx = session.beginTransaction();

     currentState.setStatus(statusToUpdateTo);
     session.save(currentState);

     tx.commit();
   } else {
     // Seems to clear lock
     tx = session.beginTransaction();
     tx.rollback();
   }

   session.close();

对我而言,这显然反映了我对Hibernate的锁定机制缺乏了解,但是看起来有点奇怪,人们可以使用session.get(...)或session.load(...)获得锁定然后不使用会话本身释放锁,而是仅通过创建事务并提交/回滚。

当然,我可能只是误解了观察到的行为:)