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

要求:

我有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时,出现“会话关闭”错误。

我的怀疑是:
1.这是正确的方法吗?还是应该在EJB之外运行for循环(对于每个TransferRecord)
2.如何确定会话未关闭但事务已回滚(仅适用于特定失败事务的事务)

先感谢您。

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

最佳答案

这是正确的方法吗?

不,对于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
        // ...
    }
}

如何确保会话未关闭但事务已回滚(仅针对特定失败的事务)

我想我涵盖了那部分。

10-04 14:36