事务中的Spring Programmatic事务

时间:2012-12-09 10:59:16

标签: spring transactions nested

我在下面的代码中写了以下活动 我使用Spring类创建了一个事务。 插入一行。 创建了其他交易。 插入另一行。 承诺外部交易。 Rolledback内部交易。

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

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

2 个答案:

答案 0 :(得分:3)

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

  

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

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

请参阅documentation

答案 1 :(得分: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进行编程事务。