我的一个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。
有没有人有想法?
谢谢&最好的问候!
答案 0 :(得分:2)
找到一些讨论,似乎可以解释你所看到的一些内容:
通过EJB3的P-331在行动书中:
默认情况下,数据库刷新模式设置为AUTO。这意味着 Entity-Manager根据需要自动执行刷新操作。 通常,这发生在交易结束时 事务范围的EntityManagers以及持久化上下文 已关闭,适用于应用程序管理或扩展的EntityManagers。的在 此外,如果在查询中使用具有挂起更改的实体,则 持久性提供程序将在之前刷新对数据库的更改 执行查询。 如果刷新模式设置为COMMIT,则 持久性提供程序只会在与数据库同步时 事务提交。但是,你应该小心这一点 将您的责任与实体状态同步 数据库在执行查询之前。如果你不这样做而且 EntityManager查询返回数据库中的陈旧实体 应用程序可以处于不一致的状态。
P-353 EJB3在Action Book中说明:
如果查询设置为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
答案 1 :(得分:0)
为什么不这样做:
MyEntity persisted = entityManager.persist(entity);
答案 2 :(得分:0)
我终于找到了问题所在:在JDBC连接池中,有一个“事务”部分,其中启用了“非事务连接”选项...只需删除此选项就可以完成所有工作:)