Java EntityManager不需要的后台提交

Java EntityManager不需要的后台提交,java,jpa,transactions,glassfish,Java,Jpa,Transactions,Glassfish,我的一个glassfish服务器出现了一个奇怪的问题。看看这段代码: userTransaction.begin(); MyEntity实体=新MyEntity(12345); //设置值。。 entityManager.persist(实体); MyEntity persistedEntity=entityManager.createQuery(“从MyEntity p中选择p,其中p.idpk=12345”).getSingleResult(); //... 提交()//OK=>元组在数据库

我的一个glassfish服务器出现了一个奇怪的问题。看看这段代码:

userTransaction.begin();
MyEntity实体=新MyEntity(12345);
//设置值。。
entityManager.persist(实体);
MyEntity persistedEntity=entityManager.createQuery(“从MyEntity p中选择p,其中p.idpk=12345”).getSingleResult();
//...
提交()//OK=>元组在数据库中
现在出现了业务问题,需要回滚事务

userTransaction.begin();
MyEntity实体=新MyEntity(12345);
//设置值。。
entityManager.persist(实体);
MyEntity persistedEntity=entityManager.createQuery(“从MyEntity p中选择p,其中p.idpk=12345”).getSingleResult();
//...
//业务问题=>回滚
userTransaction.rollback()//ERROR=>元组12345在数据库中!
即使回滚似乎有效(没有引发异常或奇怪的日志输出),元组也已在数据库中提交。。。 为了查找问题所在,我尝试了以下代码:

userTransaction.begin();
MyEntity实体=新MyEntity(12345);
//设置值。。
entityManager.persist(实体);
//业务问题=>回滚
userTransaction.rollback()//OK=>元组12345不在数据库中!
使用此代码(不检索实体),元组不会提交到数据库,这是正确的行为。让我们更进一步:

userTransaction.begin();
MyEntity实体=新MyEntity(12345);
//设置值。。
entityManager.persist(实体);
MyEntity persistend=entityManager.find(MyEntity.class,12345);
//...
//业务问题=>回滚
userTransaction.rollback()//OK=>元组12345不在DB中
在最后一种情况下,结果仍然正确,并且没有提交到数据库的元组。当使用查询检索实体时,EntityManager似乎做出了一个神奇的[不需要的]提交。。。 我还尝试在另一个表上进行查询,这不会导致错误的提交(回滚工作)。此外,我试图在自己的服务器上重现这个问题,但没有问题:所有回滚都正常工作。因此,这实际上应该是一个服务器配置问题

作为参考,它是一个在linux上运行的glassfish v2.1.1。EntityManager处于FlushModeType.AUTO状态

有人有主意吗


谢谢并致以最良好的问候

发现一些讨论似乎可以解释您看到的一些内容:

通过EJB3行动手册的p-331:

默认情况下,数据库刷新模式设置为自动。这意味着 实体管理器根据需要自动执行刷新操作。 通常情况下,这发生在的事务结束时 事务范围的EntityManager,以及当持久性上下文为 已为应用程序管理或extendedscope EntityManager关闭In 此外,如果在查询中使用具有挂起更改的实体,则 持久性提供程序将在之前刷新对数据库的更改 执行查询。如果刷新模式设置为提交,则 持久性提供程序仅在 事务提交。但是,您应该注意这一点,因为它 您将负责将实体状态与 在执行查询之前访问数据库。如果你不这样做 EntityManager查询从数据库返回过时的实体 应用程序可能会处于不一致的状态

p-353 EJB3行动手册规定:

如果查询设置为FlushModeType.COMMIT,则更新的效果 对持久性上下文中的实体所做的更改不由 而实际行为是特定于实现的

也许可以尝试在由返回的查询上切换刷新模式

entityManager.createQuery(“从MyEntityP中选择p,其中p.idpk=12345”).getSingleResult()

或者在实体管理器本身上,看看这是否会改变什么

在此进行进一步讨论:

为什么不这样做:

MyEntity persisted = entityManager.persist(entity);

我终于找到了问题所在:在JDBC连接池中,有一个“Transaction”部分启用了“Non-Transactional Connections”选项。。。只需删除此选项即可使整个过程正常运行:)

您使用的是什么数据库?出现问题的表在两个数据库上具有相同的DDL(如果它们不同的话)?问题发生在MySQL 5.0.51a上(在Debian x64上)。我还使用Weblogic/Oracle10g在另一台服务器上进行了测试,没有问题:事务已正确回滚。DDL在服务器上完全相同(此外,我使用相同的数据在本地进行了测试)。在我的例子中,它可以工作,但会导致其他问题(特别是在FlushModeType.COMMIT中,更新查询的行为未指定)。我认为问题其实不在于FlushModeType,而在于服务器的配置……是的,这会起作用,但是应用程序非常大,持久化是在另一个部分完成的,我无法直接检索实体……是的。问题实际上是“为什么事务的回滚在这种情况下不起作用”。我猜是有一些配置(MySQL或Glassfish)导致了这种情况。我不明白为什么不能使用从
em.persist()
返回的实体。如果使用AOP/OOP或任何可能的方法正确地完成了应用程序,那么应用程序的大小无关紧要。