3

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

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

MyEntity persistedEntity = entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
//...

userTransaction.commit(); //OK => the tuple is in the DB

现在出现业务问题,需要回滚事务。

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

MyEntity persistedEntity = entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();
//...

//Business problem => rollback
userTransaction.rollback(); //ERROR => the tuple 12345 is in the DB !

即使回滚似乎有效(没有引发异常或奇怪的日志输出),元组已经提交到数据库中......为了搜索问题所在,我尝试了以下代码:

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

//Business problem => rollback
userTransaction.rollback(); //OK => the tuple 12345 is NOT in the DB !

使用此代码(不检索实体),元组不会提交到数据库,这是正确的行为。让我们更进一步:

userTransaction.begin();

MyEntity entity = new MyEntity(12345);
//setting values..
entityManager.persist(entity);

MyEntity persisted = entityManager.find(MyEntity.class, 12345);
//...

//Business problem => rollback
userTransaction.rollback(); //OK => the tuple 12345 is NOT in DB

在最后一种情况下,结果仍然正确,并且没有提交给数据库的元组。似乎 EntityManager 在使用查询检索实体时做了一个神奇的 [不需要的] 提交......我还尝试在另一个表上进行查询,这不会导致错误的提交(回滚有效)。此外,我尝试在自己的服务器上重现该问题,并且没有问题:所有回滚都正常工作。因此,它确实应该是服务器配置问题。

有关信息,它是在 linux 上运行的 glassfish v2.1.1。EntityManager 在 FlushModeType.AUTO 中。

有人有想法吗?

谢谢和最好的问候!

4

3 回答 3

2

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

通过 EJB3 In Action Book 的 P-331:

默认情况下,数据库刷新模式设置为 AUTO。这意味着 Entity-Manager 会根据需要自动执行刷新操作。通常,这发生在事务范围的 EntityManager 的事务结束时,以及应用程序管理或扩展范围的 EntityManager 的持久性上下文关闭时。此外,如果在查询中使用了具有未决更改的实体,则持久性提供程序将在执行查询之前将更改刷新到数据库。 如果将刷新模式设置为 COMMIT,则持久性提供程序将仅在事务提交时与数据库同步。但是,您应该小心这一点,因为在执行查询之前将实体状态与数据库同步是您的责任。如果您不这样做并且 EntityManager 查询从数据库返回过时的实体,则应用程序可能会以不一致的状态结束。

P-353 EJB3 In Action Book 指出:

如果Query 设置为 FlushModeType.COMMIT,则对持久性上下文中的实体进行更新的效果不是由规范定义的,实际行为是特定于实现的。

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

entityManager.createQuery("SELECT p FROM MyEntity p WHERE p.idpk=12345").getSingleResult();

或实体管理器本身,看看是否改变了什么?

这里有一些进一步的讨论:

http://www.coderanch.com/t/475041/ORM/databases/EntityManager-setFlushMode-COMMIT-Vs-Query

于 2012-08-30T17:11:51.083 回答
0

为什么不这样做:

MyEntity persisted = entityManager.persist(entity);
于 2012-08-31T05:47:37.743 回答
0

我终于发现问题出在哪里:在 JDBC 连接池中,有一个“事务”部分,其中启用了“非事务性连接”选项......只需删除此选项即可使整个工作正常工作:)

于 2013-07-09T08:44:14.013 回答