我正在使用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规范的每个实现?
非常感谢任何信息或指导。
答案 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();