【问题标题】:ApplicationException - Java - Hibernate - rollback relatedApplicationException - Java - Hibernate - 回滚相关
【发布时间】:2011-01-03 00:29:02
【问题描述】:

我的问题与事务和异常有关

要求:

我有 10 条记录要插入到数据库表中。插入每条记录后,我将数据插入另一个表。因此,如果插入第二个表失败,我想回滚该记录。

例如。 假设一次处理 10 人的现金转账(从一个帐户到另一个帐户)。

伪代码: ------------- EJB 方法的开始

for(int i = 0; i < TransferRecords.length; i++)
{
    try
    {
          //Deduct cash from TransferRecord.accountFrom --- Includes use of Hibernate Session
          //Add cash in TransferRecord.accountTo -- Includes use of Hibernate Session
     } catch(AppException exception)
     {
            //Rollback the transaction only for this particular transfer (i)
            // But here when I go for next record it says session is closed
     }
}

---------EJB方法结束

这里 AppException 是使用 @ApplicaitonException(rollback=true) 注释创建的。

我们想要的功能是:即使 TransferRecord 的事务失败(比如 2),我希望为记录 0、记录 1、记录 3、记录 4 提交数据(等等......但不是记录2)

但这里的问题是:当 TransferRecord 2 失败并且当我移动到 TransferRecord 3 时,我收到“Session Closed”错误。

我的疑问是: 1. 这是一个正确的方法吗?或者我应该在 EJB 之外运行 for 循环(对于每个 TransferRecord) 2.如何确保会话没有关闭但事务回滚(仅针对特定失败的事务)

提前谢谢你。

我正在使用 EJB3、Hibernate 3.x、Jboss 4.2.x 并且我正在使用容器托管事务。

【问题讨论】:

    标签: java hibernate orm jpa jta


    【解决方案1】:

    这是一个正确的方法吗?

    不,对于 CMT,您的方法就是您的交易单位。所以在这里,你所有的TransferRecord 都在同一个唯一的事务中处理。

    顺便问一下,你如何回滚事务?你传播RuntimeException 还是调用setRollbackOnly()?我只是好奇。

    或者我应该在 EJB 之外运行 for 循环(针对每个 TransferRecord)吗?

    为什么在外面?没有什么能强迫你这样做。如果您想在自己的事务中处理每个TransferRecord,您应该将它们传递给另一个 EJB 方法(下面的代码受this answer 启发):

    // supposing processRecords is defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
    @Stateless
    @TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
        @EJB
        private MyStatelessLocal1 myBean;
    
        public void processRecords(List<TransferRecord> objs) {
            // No transactional stuff so no need for a transaction here
            for(Object obj : objs) {
                this.myBean.process(obj);
            }
        }
    
        @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
        public void process(TransferRecord transferRecord) {
            // Transactional stuff performed in its own transaction
            // ...
        }
    }
    

    如何确保会话未关闭但事务回滚(仅适用于特定失败的事务)

    我想我已经涵盖了那部分。

    【讨论】:

    • 谢谢帕斯卡。顺便问一下,你如何回滚事务?您是传播 RuntimeException 还是调用 setRollbackOnly()?我只是好奇。我们只抛出 RuntimeException。我们试图从整体上避免用户交易。但是您的代码很有希望。再次感谢。
    • 我不确定伪代码,但我没有要添加的内容:)
    【解决方案2】:

    您在这里唯一的选择是使用用户事务而不是 bean 外部循环的容器管理事务,以便每次进入 bean 时都会获得具有关联事务和连接(基本上是会话)的新实体管理器

    【讨论】:

    • 您可以使用 CMT 并在 bean 内循环。
    • Pascal,您的意思是:使用:@TransationAttribute(TransactionAttributeType.REQUIRES_NEW) public void process(TransferRecord transferRecord) { 一种方法并在另一个方法中循环遍历所有 TransferRecords。?谢谢。
    【解决方案3】:

    我认为您可以创建两个单独的事务,第一个用于 TransferRecord(1)(一切正常后进行提交),然后为所有 TransferRecord(i+1) 启动其他 TX。

    另一种方法是使用保存点,能够回滚并丢弃超过该保存点的所有内容(但我更喜欢第一种方法)。

    问候。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-17
      • 1970-01-01
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-06
      相关资源
      最近更新 更多