Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.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
Java JPA版本实体合并_Java_Jpa_H2 - Fatal编程技术网

Java JPA版本实体合并

Java JPA版本实体合并,java,jpa,h2,Java,Jpa,H2,我知道关于这个问题已经有一些问题了,但我认为这个问题是不同的 假设我有一门课: @Entity public class foo{ @Id @GeneratedValue private long id; @Version private long version; private String description; ... } 我创建了一些对象,并使用JPA add()将它们持久化到数据库中 稍后,我使用jpaall()从存储库获取所有信息; 从该列表中,

我知道关于这个问题已经有一些问题了,但我认为这个问题是不同的

假设我有一门课:

@Entity
public class foo{
  @Id
  @GeneratedValue
  private long id;

  @Version
  private long version;

  private String description;
  ...
}
我创建了一些对象,并使用JPA add()将它们持久化到数据库中

稍后,我使用jpaall()从存储库获取所有信息; 从该列表中,我选择一个对象并更改描述

然后我想使用jpamerge()更新存储库中的该对象(请参见代码)

这里的问题是,在我第一次尝试更改描述时它就起作用了(版本值现在是2)。 第二次,一个OptimisticLockException被提出,表示该对象同时被更改

我在嵌入式模式下使用H2有DB

合并代码:

//First: persist is tried, if the object already exists, an exception is raised and then this code is executed
try {
     tx = em.getTransaction();
     tx.begin();
     entity = em.merge(entity);
     tx.commit();
   } catch (PersistenceException pex) {
              //Do stuff
            }
哪里会出什么问题

多谢各位

编辑(更多代码)

//foob是通过使用jpaall()从数据库获取所有对象获得的,然后从该列表中选择一个对象

b、 changeDescription(“新事物!”)

//调用更新方法(合并代码已发布)

当抛出
OptimisticLockException
时,这篇文章可以很好地解释

此外,仅供将来参考,您可以让JPA在更新实体时避免对实体进行这种内存验证,但要在事务结束时使用
EntityManager
上的
detach
方法在DB端进行更改:

em.detach(employee);

我假设您正在更改来自不同客户端或不同线程的列表中的元素。这就是导致出现
OptimisticLockException
的原因

一个线程,在它自己的
EntityManager
中,读取
Foo
对象,并在读取时获取
@Version

// select and update AnyEntity
EntityManager em1 = emf.createEntityManager();
EntityTransaction tx1 = em1.getTransaction();
tx1.begin();
AnyEntity firstEntity = em1.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult();
firstEntity.setName("name1");
em1.merge(firstEntity);
在第一个客户端将其更改提交到数据库之前,另一个客户端同时读取并更新
Foo
对象:

// select and update AnyEntity from a different EntityManager from a different thread or client
EntityManager em2 = emf.createEntityManager();
EntityTransaction tx2 = em2.getTransaction();
tx2.begin();
AnyEntity secondEntity = em2.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult();
secondEntity.setName("name2");
em2.merge(secondEntity);
// commit first change while second change still pending
tx1.commit();
em1.close();
现在,第一个客户端将其更改提交到数据库:

// select and update AnyEntity from a different EntityManager from a different thread or client
EntityManager em2 = emf.createEntityManager();
EntityTransaction tx2 = em2.getTransaction();
tx2.begin();
AnyEntity secondEntity = em2.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult();
secondEntity.setName("name2");
em2.merge(secondEntity);
// commit first change while second change still pending
tx1.commit();
em1.close();
当第二个客户端更新其更改时,它将获得一个
OptimisticLockException

// OptimisticLockException thrown here means that a change happened while AnyEntity was still "checked out"
try {
    tx2.commit();
    em2.close();
} catch (RollbackException ex ) {
    Throwable cause = ex.getCause();
    if (cause != null && cause instanceof OptimisticLockException) {
        System.out.println("Someone already changed AnyEntity.");
    } else {
        throw ex;
    }
}

参考:

是否正确初始化版本字段

如果不是,则不应使用
null
,请尝试向其添加默认值:

@Version
private Long version = 0L;

您是否尝试过使用em.persist而不是merge?合并方法在更新后继续跟踪对象。根据您的配置,更新可能已经进入数据库。请发布更多代码。相关的是如何加载和修改实体,以及如何调用发布的代码。@AlanHay我用一些表示我的situation@fhofmann我编辑了回答你问题的“合并代码”。