【问题标题】:JPA with JTA how to persist many entites in one transactionJPA 与 JTA 如何在一个事务中持久化多个实体
【发布时间】:2013-02-20 21:25:51
【问题描述】:

我有一个对象列表。它们是 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 条记录插入到数据库中。我想要的是:他们都必须先成功,然后才能成功。

我正在使用最新最好的 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()”方法是不合适的。

那我该怎么办? 谢谢。

【问题讨论】:

  • 那么,有什么问题呢?如果第 54 条记录导致抛出异常会怎样?你做过测试吗?您的假设是正确的:在运行时异常的情况下,您将有一个回滚。
  • 我想我最初的问题不够清楚。我已经对此进行了测试;一遍又一遍地。如果第 54 条记录失败,之前的 53 条记录仍会插入到数据库中。这是一个问题,因为我不希望将这 53 条记录插入到数据库中。
  • 第54条记录怎么失败?它会抛出异常吗?哪一个?
  • Location 对象包含许多必填字段,并且必须包含唯一名称。如果必填字段不存在或出现非唯一名称,则可能会发生故障。从理论上讲,这些类型的问题会在尝试插入之前被捕获(通过使用“前门”验证器类),但情况并非总是如此。

标签: jpa-2.0 jta


【解决方案1】:

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

【讨论】:

  • 正如我上面评论的那样,我已经对此进行了测试;多次。如果第 54 条记录失败,之前的 53 条记录仍会插入到数据库中。这是一个问题,因为我不希望将这 53 条记录插入到数据库中。
  • 如何获取EntityManager?如果没有注入,您将需要调用 joinTransaction 或自己管理整个事务(开始、回滚等)。我的建议是使用容器管理的事务和注入的 EntityManagers。
  • EntityManager 像这样注入:@PersistenceContext(unitName = "myPersistenceUnit") private EntityManager em;
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    我正在使用 JBoss。在您的standalone.xml 或 domain.xml 中设置您的数据源以拥有 &lt;datasource jta="true" ...&gt; 看起来很明显,但显然我很久以前就设置错了并且忘记了。

    【讨论】:

      猜你喜欢
      • 2017-02-17
      • 2012-06-17
      • 2011-07-16
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 2018-11-16
      • 1970-01-01
      • 2015-09-05
      相关资源
      最近更新 更多