0

我正在尝试理解 Spring Transaction 概念。如下所示,我必须将数据插入两个不同的数据库(iSeries 和 DB2),但我们的 iSeries 版本不支持两阶段提交。要求是,仅当两个插入都成功时才应提交事务,否则应回滚。

如果我将传播用作 REQUIRED 或 REQUIRES_NEW,我会收到错误消息“非法尝试使用现有的两阶段资源提交单阶段资源”。

但是,如果我使用 NOT_SUPPORTED 或 SUPPORTS,它可以正常工作(即,如果其中一个插入失败,则事务回滚,否则如果两个插入都成功,它就会提交)。

我的理解是,如果 Propagation = SUPPORTS / NOT_SUPPORTED,那么在下面的场景中甚至不会启动 Transaction。因此,两个插入都可能在两个不同的数据库中独立发生,如果其中一个失败,整个事务不应该回滚。

但是 Propagation = SUPPORTS / NOT_SUPPORTED 根据我的要求工作。有人可以解释一下吗?提前致谢。

@Resource
private SessionFactory db2SessionFactory = null;

@Resource
private SessionFactory iSeriesSessionFactory = null;

@Transactional(propagation = Propagation.REQUIRED)
public void insert()
{
   insertDB1();
   insertDB2();
}

insertDB1()
{
   db2SessionFactory .getCurrentSession().saveOrUpdate(obj1);
}

insertDB2()
{
   iSeriesSessionFactory.getCurrentSession().saveOrUpdate(obj2);
}
4

2 回答 2

2

好的,我会尽力解释我认为正在发生的事情。我强调,这是我的假设。可能我完全错了。

首先,我从来不需要为@Transactional注释指定传播。要求是一个很好的标准。如果您遇到异常,通常是因为您没有正确操作数据库。然而,这里可能并非如此,因为我以前从未使用过多个会话工厂。

当您指定 SUPPORTS 或 NOT_SUPPORTED 时,我认为发生的情况是保存是非事务性的仅仅因为保存是非事务性的,并不意味着如果发生某种类型的错误,整个会话不会回滚,因为这显然是正在发生的事情。

当您使用 REQUIRED 或 REQUIRES_NEW 时,您正在创建一个新事务,每个事务都有自己的 JDBC 连接(显然)但使用相同的事务会话。这就是为什么你得到你的illegal attempt例外。已transactional为两阶段资源创建会话,但您正尝试使用同一会话保存到单阶段数据库。

@Transactional只有当您有 2 个方法注释,其中一个方法调用另一个方法时,传播才真正发挥作用,如下所示:

@Transactional
public void method1(){
    method2();
}

@Transactional
public void method2(){
    //do some transactional stuff here
}

您的传播级别将确定是否为方法 1 创建了新会话,是否为方法 2 使用现有会话,是否为方法 2 创建新会话,或者整个事物是否以非事务方式执行。

于 2014-05-06T04:12:31.977 回答
0

JTA支持两阶段提交事务。检查您是否使用JtaTransactionManager.

它在您使用时可以正常工作,NOT_SUPPORTED或者SUPPORTS因为它以非事务方式工作。请参阅org.springframework.transaction.annotation.Propagationjavadoc。

于 2015-10-03T18:25:24.720 回答