为什么没有阅读 JPA find() 方法未提交的更改?
Why didn't read JPA find() method uncommitted changes?
我对 JPA 行为感到困惑,我没想到会以这种方式(使用 Eclipselink)。
我在 Wildfly 10 (JDK-8) 上 运行 无状态会话 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() 和 flush() 方法形成服务层似乎不是一个好主意。我这样做是因为我想在将我的业务方法 return 这个 id 留给客户端之前获取我的实体的新版本 id。在这种情况下,我改变了我的策略,并通过分离和刷新我的实体 bean 删除了所有 'bad stuff'。代码变得更加清晰,毕竟代码的复杂性大大降低了。
当然,entityManager 现在可以正常运行了。如果我在一个事务中多次查询同一个实体 bean,则 entityManager return 是正确的更新版本。
所以我自己的问题的答案是:保留方法 flush() 和 clear(),只要没有真正充分的理由使用它们。
我对 JPA 行为感到困惑,我没想到会以这种方式(使用 Eclipselink)。
我在 Wildfly 10 (JDK-8) 上 运行 无状态会话 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() 和 flush() 方法形成服务层似乎不是一个好主意。我这样做是因为我想在将我的业务方法 return 这个 id 留给客户端之前获取我的实体的新版本 id。在这种情况下,我改变了我的策略,并通过分离和刷新我的实体 bean 删除了所有 'bad stuff'。代码变得更加清晰,毕竟代码的复杂性大大降低了。
当然,entityManager 现在可以正常运行了。如果我在一个事务中多次查询同一个实体 bean,则 entityManager return 是正确的更新版本。
所以我自己的问题的答案是:保留方法 flush() 和 clear(),只要没有真正充分的理由使用它们。