JPA / EclipseLink:EntityManager.getTransaction()是创建新事务还是返回活动事务?

时间:2012-06-12 21:48:05

标签: jpa transactions eclipselink

我正在使用EclipseLink 2.3.0。我有一个方法,我从单元测试(因此在容器之外,没有JTA)调用,看起来像这样:

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

这些更改没有被持久化到数据库,并且查看了很长时间,最后意识到EntityManager.getTransaction()实际上返回了一个新的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规范的每个实现?

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

3 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:1)

JPA规范(参见第7.5.4节)有明确的示例,显示使用getTransaction()来开始和提交事务。所以你的代码应该没问题。

您的测试表明您获得了两个不同的对象,但这并不意味着不使用相同的事务。也许返回的对象只是一个真实的事务对象的代理。

或者可能在// make some changes下隐藏的代码中提交或回滚事务。

答案 2 :(得分:0)

您是否曾尝试使用persist before commit:

  Employee employee = new Employee("Samuel", "Joseph", "Wurzelbacher");
  em.getTransaction().begin();
  em.persist(employee);
  em.getTransaction().commit();