为什么没有阅读 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(),只要没有真正充分的理由使用它们。