JPA嵌套事务和锁定

ane*_*rgy 19 java jpa java-ee-6 jpa-2.0

考虑这种情况,在不同的无状态bean中存在两种方法

public class Bean_A {
   Bean_B beanB; // Injected or whatever
   public void methodA() {
    Entity e1 = // get from db
    e1.setName("Blah");
    entityManager.persist(e1);
    int age = beanB.methodB();

   }
} 
public class Bean_B {
  //Note transaction
  @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
   public void methodB() {

    // complex calc to calculate age  
  }

}
Run Code Online (Sandbox Code Playgroud)

由BeanA.methodA启动的事务将被挂起,并且将在BeanB.methodB中启动新事务.如果methodB需要访问由methodA修改的同一实体,该怎么办?这会导致死锁.是否可以在不依赖隔离级别的情况下阻止它?

ewe*_*nli 23

嗯,让我们列出所有案例.

REQUIRES_NEW并没有真正嵌套交易,但正如你所提到的暂停当前交易.然后只有两个事务访问相同的信息.(这类似于两个常规并发事务,除了它们不是并发但在同一执行线程中).

T1 T2          T1 T2
?              ?
|              |
               |
   ?           |  ?
   |           |  |
   |     =     |  |
   ?           |  ?
               |
|              |
?              ?
Run Code Online (Sandbox Code Playgroud)

然后我们需要考虑乐观悲观锁定.

此外,我们需要考虑刷新由奥姆斯操作.对于ORM,我们在写入时没有明确的控制,因为它flush是由框架控制的.通常,在提交之前发生一次隐式刷新,但是如果修改了许多条目,框架也可以进行中间刷新.

1)让我们考虑乐观锁定,其中读取不获取锁定,但写入获取独占锁定.

T1的读取不会获得锁定.

1a)如果T1确实冲破了这些变化,那么它获得了一个排他锁.当T2提交时,它会尝试获取锁定但不能.系统被阻止.这可能是一种特殊的僵局.完成取决于事务或锁定超时的方式.

1b)如果T1没有预先冲洗更改,则不会获得锁定.当T2提交时,它获取并释放它并且成功.当T1尝试提交时,它会注意到冲突并失败.

2)让我们考虑悲观锁定,其中read获取共享锁并写独占锁.

T1读取获取共享锁.

2a)如果T1正常冲洗,它会将锁扣转为专用锁.情况类似于1a)

2b)如果T1没有冲洗,T1保持共享锁.当T2提交时,它会尝试获取独占锁并阻塞.系统再次被阻止.

结论:如果没有发生过早冲洗,那么乐观锁定很好,你无法严格控制.