Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JPA实体仅在方法完成后更新_Jpa_Asynchronous_Merge_Entity - Fatal编程技术网

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

JPA实体仅在方法完成后更新,jpa,asynchronous,merge,entity,Jpa,Asynchronous,Merge,Entity,我有一个异步带注释的方法,它通过method参数接收一个实体。在此方法中,我尝试设置变量三次: @Inject EntityDao entityDao; @Asynchronous public Future<String> doSomething (MyEntity p_myEntity) { MyEntity myEntity = entityDao.merge(p_myEntity); // change from detached to attached

我有一个异步带注释的方法,它通过method参数接收一个实体。在此方法中,我尝试设置变量三次:

@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");
}
@injectentitydao EntityDao;
@异步的
公共未来剂量(MyEntity p_MyEntity){
MyEntity MyEntity=entityDao.merge(p_MyEntity);//从分离更改为附加
//em.contains(myEntity)返回true
myEntity.setName(“Joe 1”);//数据库中较新的集合
//System.out.println(myEntity.getName())会说“Joe1”
试一试{
线程。睡眠(20*1000);
}捕获()…等
myEntity.setName(“Joe 2”);//数据库中较新的集合
//System.out.println(myEntity.getName())会说“Joe2”
试一试{
线程。睡眠(20*1000);
}捕获()…等
myEntity.setName(“Joe 3”);//数据库中只有一个集合
返回新的异步结果(“完成”);
}
编辑:多亏了佩德罗科瓦尔斯基,我对这个问题有了更好的理解,我将重新制定

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

  • 在sleep()期间,如果名称值发生更改,我将检查数据库
  • 在网页上显示MyEntity对象列表(带有名称),该列表每2秒更新一次
上述两种方法都表明“Joe 1”和“Joe 2”的值在数据库中较新。只有在doSomething()方法完成后,才会将姓氏集(Joe3)放入数据库中


因此,我的问题是:为什么值“Joe 1”和“Joe 2”没有放在数据库中,而只有最后一个值放在数据库中?

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

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

这就是为什么您不会从T1以外的任何事务中看到“Joe1”(该值仅在T1中更改)。只有在方法结束(T1提交)时才能看到“Joe2”

将数据与基础数据库同步,但不会提交数据。有关更多详细信息,请参见以下线程:

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

  • 乐观锁定可以避免两个事务T1和T2更改相同数据(相同实体)的情况。在没有锁定的情况下,只有最后提交的事务更改才会反映在数据库中(因此前一个事务所做的更改将丢失)。通过锁定,您将在最后提交的事务中获得异常,因此不会丢失任何数据

  • 悲观锁定可以在修改时锁定数据。在这种情况下,事务T2在T1完成之前不会对数据进行操作

  • 最后,最简单的情况是(如果可能的话)将您的方法分成更小的块

  • 所以我的问题是:为什么“Joe1”和“Joe2”的值没有放进去 数据库,并且只将最后一个值放入数据库

    • em.flush()期间,数据写入数据库。提交事务时,数据对其他用户/持久性上下文可见

    • 您不会通过em.flush()手动刷新数据库,因此在提交事务时会自动调用em.flush()

    • 事务在方法末尾提交,因此在刷新发生时提交,这意味着“Joe3”被写入数据库并提交


    这是同一交易的另一种方法吗?合并发生后是否尝试显式刷新EM?否,不是同一事务。你是说每次在EntityDao中merge()之后刷新?你说的“我正在调用myEntity.getName()方法”是什么意思。这是您传递给“doSomething”方法的同一个实例,还是使用EntityManager#findById(-)查找MyEntity的实例?不,在控制器类的其他地方,我通过调用entityDao.findAll()检索所有MyEntity,并将它们显示在网页上。每5秒进行一次。为了清楚说明:异步方法和控制器彼此无关,您可以设置所有需要的值,并在方法末尾合并。您还可以在方法的开头进行合并,并在方法之后设置所有需要的值(在从merge()实例返回的对象实例上)。不过,这并不重要,您至少需要调用一个合并操作,因为您在这个方法中对分离的实体进行操作?唯一与JTA相关的代码在my persistence.xml中:。我不会独自开始/提交任何交易。OP中描述的方法没有被事务包围。您展示的相关部分是JTA用法声明。因为您使用JTA,所以没有任何事务的启动/提交代码。如果要使用RESOURCE_LOCAL事务类型,则需要显式使用start/commit设置事务的边界。如上所述,默认情况下,JTA事务从方法开始,在提交时结束。谢谢:)如果有人想添加信息,请继续。同时,我会将此设置为答案。您是否有一个指向说明JTA事务从方法开始到提交结束的文档的链接