加载实体而不锁定数据库中的行

时间:2015-10-21 15:48:01

标签: java hibernate jpa

JPA中是否有选项可以在不锁定数据库的情况下加载实体(或列表)? 我希望能够用几种方法来做到这一点。 JPA也可以在不锁定数据库的情况下加载实体,但是当该实体发生任何变化时,它会锁定数据库中的行吗?验证状态当然,如果实体已在数据库中更改,则抛出无效状态的异常。

1 个答案:

答案 0 :(得分:1)

  

JPA中是否有一个选项可以在不锁定数据库的情况下加载实体(或列表)?

可以通过不同的EntityManager调用来加载实体:

  • EntityManager.find
  • EntityManager.createQuery
  • EntityManager.createNamedQuery
  • EntityManager.createNativeQuery

您无需在这些调用中明确使用LockModeType.None。这是由LockModeType.None表示的JPA中的默认选项。

  

JPA也可以在不锁定数据库的情况下加载实体,但是当该实体发生任何变化时,它会锁定数据库中的行吗?

可以通过不同的电话锁定实体:

  • EntityManager.find
  • EntityManager.lock
  • EntityManager.refresh
  • Query.setLockMode

我认为JPA是可能的,但不能保证,因为它取决于持久性提供程序(特定于供应商)和使用的锁定类型。

无论如何,这种情况可能如下所示:

// begin tx
...
SomeEntity e = em.find(SomeEntity.class, id);
// change the entity
em.lock(e, LockModeType.OPTIMISTIC); // LockModeType.OPTIMISTIC_FORCE_INCREMENT
...
// commit tx

现在,它依赖于持久性提供程序,锁定是否会(在调用锁定时)或延迟(当tx完成时)。请记住,另一个事务可能会将实体锁定为第一个,并且最终会回滚。

JPA规范2.0 ,章节 3.4.4.1 OPTIMISTIC,OPTIMISTIC_FORCE_INCREMENT

  

如果交易T1在{a}上调用lock(entity, LockModeType.OPTIMISTIC)   版本化对象,实体管理器必须确保两者都没有   可能会出现以下现象:

     
      
  • P1(脏读):事务T1修改一行。然后另一个事务T2读取该行并获取修改后的值,   在T1提交或回滚之前。最终交易T2   成功提交; T1是否提交或滚动无关紧要   返回以及是否在T2提交之前或之后执行此操作。
  •   
  • P2(不可重复读取):事务T1读取一行。然后,另一个事务T2会在T1之前修改或删除该行   承诺。这两个事务最终都成功提交。
  •   
     

这通常由实体经理获得锁来实现   在底层数据库行上。 虽然乐观并发,   通常不会立即获得长期数据库读锁   允许兼容的实现获得立即锁定   (只要在提交完成之前保留它)。如果是锁   推迟到提交时间,它必须保留到提交   完成。任何支持可重复读取的实现   防止上述现象的方法是允许的

     

如果事务T1调用   版本化lock(entity,LockModeType.OPTIMISTIC_FORCE_INCREMENT)   对象,实体管理者必须避免现象P1和P2(如同   LockModeType.OPTIMISTIC)并且还必须强制更新(增量)   到实体的版本列。 强制版本更新可能是   立即执行,或者可以推迟到刷新或提交。