1

我已经编写了下面的代码来执行以下活动,我使用 Spring 类创建了一个事务。插入一行。创建了其他交易。插入另一行。提交的外部事务。回滚内部事务。

TransactionStatus trxstsOuter= dsTrxMngr.getTransaction(null);
    jdbcTemplate.update("insert into kau_emp values(6,'xyz' )");
    TransactionStatus trxstsInner= dsTrxMngr.getTransaction(null);
        jdbcTemplate.update("insert into kau_emp values(7,'pqr' )");

dsTrxMngr.commit(trxstsOuter);
System.out.println("trxstsOuter.isCompleted()" + trxstsOuter.isCompleted());
System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());
dsTrxMngr.rollback(trxstsInner);
    System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());

我观察到这两行都提交给 DB !输出是

trxstsOuter.isCompleted()true
trxstsInner.isCompleted()false
trxstsInner.isCompleted()true

这是正确的行为吗?在允许外部事务提交之前,不应该首先提交/回滚内部事务吗?如果外部事务被提交,内部事务的回滚是否应该抛出错误?

4

2 回答 2

4

在您的示例交易中Propagation.REQUIRED中用作默认值,并且所有逻辑事务都映射到单个物理事务

当传播设置为 PROPAGATION_REQUIRED 时,将为应用该设置的每个方法创建一个逻辑事务范围。每个这样的逻辑事务范围都可以单独确定仅回滚状态,外部事务范围在逻辑上独立于内部事务范围。当然,在标准 PROPAGATION_REQUIRED 行为的情况下,所有这些范围都将映射到同一个物理事务。因此,在内部事务范围内设置的仅回滚标记确实会影响外部事务实际提交的机会(正如您所期望的那样)。

因此,在您的示例中,两个逻辑事务映射到一个物理事务。

请参阅文档

于 2012-12-09T11:41:37.847 回答
2

在当前代码中,第二个 getTransaction 调用是 noop。此行为由名为 PropagationBehavior 的属性控制。默认传播行为是 PROPAGATION_REQUIRED - 这意味着如果不存在则启动新事务,否则加入现有事务。这就是您的情况。

如果您将第二个事务的传播行为属性更改为 PROPAGATION_REQUIRES_NEW - 您将获得预期的行为。一旦内部事务被提交/回滚,外部事务就会被挂起并创建一个新事务,外部事务会自动恢复。我已经修改了您的代码以包含此行为,当您尝试在内部事务之前提交外部事务时,您现在应该得到一个异常。如果您修复序列,则提交将独立发生。

TransactionStatus trxstsOuter= dsTrxMngr.getTransaction(null);
jdbcTemplate.update("insert into kau_emp values(6,'xyz' )");
    // start a new transaction.
    DefaultTransactionDefinition nestedTransDef = new DefaultTransactionDefinition();
    nestedTransDef.setPropagationBehavior(             
           TransactionDefinition.PROPAGATION_REQUIRES_NEW);
    TransactionStatus trxstsInner= dsTrxMngr.getTransaction(nestedTransDef);
     System.out.println("trxstsInner.isNewTransaction()"+ trxstsInner.isNewTransaction());  
        jdbcTemplate.update("insert into kau_emp values(7,'pqr' )");

dsTrxMngr.commit(trxstsOuter);
    System.out.println("trxstsOuter.isCompleted()" + trxstsOuter.isCompleted());
    System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());
    dsTrxMngr.rollback(trxstsInner);
    System.out.println("trxstsInner.isCompleted()" + trxstsInner.isCompleted());

顺便说一句,您应该使用注释来管理事务 - 这是在代码中合并事务的更清洁/更好的方式。程序化事务仅适用于需要更多控制的极少数情况。此外,建议在使用 TransactionTemplate 进行编程事务时。

于 2012-12-09T12:17:08.483 回答