JPA实体仅在方法完成后更新

Big*_*igJ 3 merge entity asynchronous jpa

我有一个Asynchronous注释方法,它通过方法参数接收实体.在这个方法中,我尝试设置一个变量三次:

@Inject EntityDao entityDao;

@Asynchronous
public Future<String> doSomething (MyEntity p_myEntity) {

    MyEntity myEntity = entityDao.merge(p_myEntity); // change from detached to attached
    // em.contains(myEntity) returns true

    myEntity.setName("Joe 1"); // newer set in database
    // A System.out.println(myEntity.getName()) does say "Joe 1"

    try {
        Thread.sleep(20*1000);
    } catch () ...etc

    myEntity.setName("Joe 2"); // newer set in database
    // A System.out.println(myEntity.getName()) does say "Joe 2"

    try {
        Thread.sleep(20*1000);
    } catch () ...etc

    myEntity.setName("Joe 3"); // only one set in database

    return new AsyncResult<>("done");
}
Run Code Online (Sandbox Code Playgroud)

编辑:感谢PedroKowalski,我对问题有了更好的理解,我将重新制定.

在执行上述方法的过程中,我有两种方法可以检查myEntity.setName()是否实际更改:

  • 在sleep()期间,我检查数据库是否更改了名称值
  • 在网页上显示MyEntity对象列表(带有名称),此列表每2秒更新一次.

上述两种方法都表明值"Joe 1"和"Joe 2"在数据库中较新.只有在完成doSomething()方法之后,才会将最后一个名称集(Joe 3)放入数据库中.

所以我的问题是:为什么值"Joe 1"和"Joe 2"没有放入数据库中,只有最后一个值放在数据库中?

Pio*_*cki 5

如果您使用JTA事务,则事务边界从方法的开始扩展到结束.

因此,在事务T2中不能看到在活动事务T1 中进行的更改.如果你考虑一下,这是非常合理的.假设T2可以对T1改变但未提交的数据进行操作.在T1回滚时,对T1中的实体所做的每个更改都必须无效.你已经结束了T2对无效数据进行操作的情况.

这就是为什么你不会从T1以外的任何交易中看到'Joe 1'(此值仅在T1中更改).当方法结束时(T1提交),您只能看到'Joe 2'.

所述的EntityManager#平齐()与下面的数据库同步中的数据,但不提交它.有关更多详细信息,请参阅此主题:http://www.java.net/node/665442#comment-678155

在这种情况下我可以看到三种解决方案:

  1. 乐观锁定可以使您免于两个事务T1和T2更改相同数据(同一实体)的情况.如果您没有锁定,则只有最后提交的事务更改将反映在数据库中(因此前一个事务所做的更改将丢失).使用锁定,您将在上次提交的事务中获得异常,因此不会丢失任何数据.

  2. 悲观锁定可能会在修改时锁定数据.在这种情况下,在T1完成之前,您的事务T2将不会对数据进行操作.

  3. 最后 - 最简单的情况是(如果可能的话)只是将方法分成较小的块.

HTH.