13

我正在使用 EclipseLink 2.3.0。我有一个从单元测试中调用的方法(因此在容器之外,没有 JTA),如下所示:

EntityManager em = /* get an entity manager */;
em.getTransaction().begin();
// make some changes
em.getTransaction().commit();

这些更改没有被持久化到数据库中,并且看了很长时间,最终意识到 EntityManager.getTransaction() 实际上返回了一个 NEW EntityTransaction,而不是两个调用中的同一个。效果是第一个调用创建一个新事务并开始它,第二个调用创建另一个事务并提交它。因为从未提交过第一个事务,所以不会保存更改。我们这样验证:

log.info(em.getTransaction().toString());
log.info(em.getTransaction().toString());

这导致了这些日志消息:

INFO: org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl@1e34f445
INFO: org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl@706a4d1a

两个不同的对象 ID 验证存在两个不同的实例。将代码更改为:

EntityManager em = /* get an entity manager */;
EntityTransaction tx = em.getTransaction();
tx.begin();
// make some changes
tx.commit();

...解决了这个问题。现在,当我运行代码时,我看到为执行数据库工作而生成的 SQL 语句,并且查看数据库,数据已更改。

我对这个结果有点惊讶,因为我在网上看到了很多代码示例(一般针对 JPA,特别针对 EclipseLink),这些示例推荐了我们用于管理事务的代码。我专门搜索了有关此的信息,但没有找到任何信息。发生什么了?

我在 JPA 规范中查找了确切指定 getTransaction() 功能的内容,并且没有具体说明事务是新的还是相同的。persistence.xml 中是否有控制此设置的设置?行为是否特定于 JPA 规范的每个实现?

非常感谢您提供任何信息或指导。

4

3 回答 3

5

在 JPA 和 EclipseLink 中使用 getTransaction() 确实有效(这是我们自己的测试的工作方式)。

我的猜测是你正在做一些非常奇怪的事情。

您使用的是 Spring 还是其他层?请为您的测试包括整个代码和 persistence.xml。确保您没有在 persistence.xml 中使用 JTA。

于 2012-06-13T13:55:06.970 回答
1

The JPA spec (see paragraph 7.5.4) has explicit examples showing the use of getTransaction() to begin and commit the transaction. So your code should be fine.

Your test shows that you get two different objects, but that doesn't mean the same transaction is not used. Maybe the returned object is just some proxy to a single, real, transaction object.

Or maybe the transaction is committed or rollbacked inside the code hidden under // make some changes.

于 2012-06-12T21:58:23.610 回答
0

你有没有试过在提交之前使用持久化:

  Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher");
  em.getTransaction().begin();
  em.persist(employee);
  em.getTransaction().commit();
于 2017-04-04T07:06:37.407 回答