我对 JPA 行为感到困惑,这是我没有想到的(使用 Eclipselink)。
我在 Wildfly 10 (JDK-8) 上运行无状态 session EJB (3.2)。我的方法调用默认封装在事务中。 现在,我的业务方法在读取和更新实体 bean 时无法识别更新 - 特别是实体的版本号。所以我的通话结果是
org.eclipse.persistence.exceptions.OptimisticLockException
我的代码看起来简化如下:
public ItemCollection process(MyData workitem) {
....
// load document from jpa
persistedDocument = manager.find(Document.class, id);
logger.info("@version=" + persistedDocument.getVersion());
// prints e.g. 3
// change some data
....
manager.flush();
logger.info("@version=" + persistedDocument.getVersion());
// prints e.g. 4
....
// load document from jpa once again
persistedDocument = manager.find(Document.class, id);
logger.info("@version=" + persistedDocument.getVersion());
// prints e.g. 3 (!!)
// change some data
....
manager.flush();
// Throws OptimisticLockException !!
// ...Document@1fbf7c8e] cannot be updated because it has changed or been deleted since it was last read
...
}
如果我将代码(更改数据并刷新实体 bean)放在用
注释的方法中@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
一切都按预期进行。
但是为什么我的代码中第二次调用 find() 方法没有读取新的版本号?我期望在flush() 和find() 调用之后出现版本4。
最佳答案
毕竟看起来像是在打电话
manager.clear();
问题解决了。我认为分离对象应该做同样的事情,但在我的例子中,仅调用clear()确实解决了问题。
更多发现:
毕竟,在服务层中调用 detach() 和lush() 方法似乎不是一个好主意。我这样做是因为我想在离开业务方法以将该 id 返回给客户端之前获取实体的新版本 id。在这种情况下,我改变了我的策略,通过分离和刷新我的实体 bean 来删除所有“坏东西”。代码变得更加清晰,代码复杂度大幅降低。
当然,entityManager 现在行为正确。如果我在一个事务中多次查询同一个实体 bean,entityManager 将返回正确的更新版本。
所以我自己的问题的答案是:保留方法flush()和clear(),只要没有充分的理由使用它们。
关于java - 为什么没有读取 JPA find() 方法未提交的更改?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40317327/