Java 为什么没有';是否读取JPA find()方法未提交的更改?

Java 为什么没有';是否读取JPA find()方法未提交的更改?,java,jpa,eclipselink,wildfly-10,Java,Jpa,Eclipselink,Wildfly 10,我对JPA的行为感到困惑,这是我没有预料到的(使用Eclipselink) 我在Wildfly 10(JDK-8)上运行无状态会话EJB(3.2)。我的方法调用按默认值封装在事务中。 现在,在读取和更新实体bean时,我的业务方法无法识别更新,尤其是实体的版本号。所以我的电话结果是 org.eclipse.persistence.exceptions.OptimisticLockException 我的代码简化如下: public ItemCollection process(MyData w

我对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()方法形成服务层似乎不是一个好主意。我之所以这样做,是因为我想在离开业务方法将该id返回给客户机之前获取实体的新版本id。在这种情况下,我改变了策略,通过分离和刷新实体bean删除了所有“坏东西”。代码变得更加清晰,代码复杂度大大降低

当然,entityManager现在的行为是正确的。如果我在一个事务中多次再次查询同一个实体bean,entityManager将返回正确的更新版本


因此,我自己的问题的答案是:保留flush()和clear()方法,只要没有真正好的理由使用它们。

同一事务中的第二次调用?是的,这一切都在一个相同的无状态会话EJB方法中运行,我想我在另一个项目中使用过,类似的代码,有许多OneToMany关系,但行为似乎与现在不同。当我使用JPA提供程序(DataNucleus)运行类似的操作时,每次刷新都会更新数据存储中的版本和修改的字段,因此对getVersion()的调用会返回新版本。另一点是,同一对象上同一事务中的em.find()应该返回相同的对象,因此这些调用是无点的。如示例所示,我的代码更复杂。使用同一会话bean从不同的逻辑模块调用em.find()方法。您是对的,在其他情况下,重复的find()调用是没有意义的。