JPA与JTA如何在一个事务中持久化许多实体

时间:2013-02-20 21:25:51

标签: jpa-2.0 jta

我有一个对象列表。他们是JPA“位置”实体。

List<Location> locations;

我有一个无状态的EJB,它通过列表循环并持久化每个。

public void createLocations() {
    List<Locations> locations = getListOfJPAManagedLocationEntities(); // I'm leaving out the details of this because it has nothing to do with the issue

    for(Location location : locations) {
        em.persist(location);
    }
}

代码工作正常。我没有任何问题。 但问题是:我希望这是一个全有或全无的交易。目前,每次通过for循环时,persist()方法都会在数据库中插入一个新行。假设我有100个位置对象,第54个对象有错误,并抛出异常。将有53条记录插入数据库。我想要的是:在他们任何成功之前,所有人都必须成功。

我正在使用最新的&amp;最佳版本的Java EE6,EJB 3.x.和JPA 2.我的persistence.xml使用JTA。

<persistence-unit name="myPersistenceUnit" transaction-type="JTA">

我喜欢JTA。 我不想停止使用JTA。 90%的时间JTA完全符合我的要求。但在这种情况下,我似乎没有。

我对JTA的理解必须是不准确的,因为我一直认为EJB方法的开头和结尾都标记了JTA事务的边界(假设只有一个方法正如我上面所示)。根据我的逻辑,在for循环完成并且方法返回之前,事务不会结束,然后在那时记录被保留。

我正在为SqlServer 2008使用JTDS驱动程序。也许数据库不希望在没有立即提交的情况下插入记录。实体ID的定义如下:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)

我已经检查了规范,并且在JTA环境中调用各种“UserTransaction”或“getTransaction()”方法是不合适的。

那我该怎么办? 感谢。

3 个答案:

答案 0 :(得分:0)

如果使用JTA和容器管理的事务,则会话EJB方法调用的默认行为是在事务中运行(就像用@TransactionAttribute(TransactionAttributeType.REQUIRED)注释它。这意味着您的代码已在事务中运行并且将做你期望的事情:如果在第54行发生异常,所有先前插入的行都将被回滚。你可以继续通过在循环中的某个点抛出异常来测试它。注意,如果你抛出一个已检查的异常声明通过您的方法,您可以指定容器在发生异常时应该执行的操作。您需要使用@ApplicationException (rollback=true)注释异常类。

答案 1 :(得分:0)

如果在循环时有重复的条目,那么它将继续没有问题,并且当循环后编译器到达此行em.flush();时,它将抛出异常并回滚事务。

答案 2 :(得分:0)

我正在使用JBoss。在standalone.xml或domain.xml中设置数据源 <datasource jta="true" ...> 看起来显而易见,但很明显我很久以前就把它弄错了,忘了它。