我知道这个问题已经存在一些问题,但我认为这个问题不同。
假设我有这门课程:
@Entity
public class foo{
@Id
@GeneratedValue
private long id;
@Version
private long version;
private String description;
...
}
他们使用JPA add()创建了一些对象并将它们保存到数据库中。
稍后,我使用JPA all()从存储库中获取所有内容; 从该列表中我选择一个对象并更改描述。
然后我想使用JPA merge()更新存储库中的那个对象(参见代码)。
这里的问题是它第一次尝试更改描述时工作(版本值现在为2)。 第二次,引发了一个OptimisticLockException,说同时改变了该对象。
我正在使用H2在嵌入模式下有数据库。
合并代码:
//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
}
哪里可能出错?
谢谢。
编辑(更多代码)
//通过使用JPA all()从db获取所有对象获得Foo b,然后从该列表中选择一个对象
b.changeDescription(“Something new!”);
//调用更新方法(已发布合并代码)
答案 0 :(得分:1)
我认为您正在从不同的客户端或不同的线程更改列表中的元素。这是导致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();
第二个客户端在更新其更改时获得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;
}
}
答案 1 :(得分:0)
Here are时发布一个帖子,该文章在抛出OptimisticLockException时完全解释。
另外,为了将来参考,您可以让JPA在更新实体时避免对实体进行内存中验证,但是想要在此事务结束时使用' detach'更改数据库端。 EntityManager上的方法:
em.detach(employee);
答案 2 :(得分:0)
您是否正确初始化版本字段?
如果没有,它不应该与null
一起使用,请尝试为其添加默认值:
@Version
private Long version = 0L;