我写了下面的代码来做下面的活动,我使用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这是正确的行为吗?在允许外部事务提交之前,不应该先提交/回滚内部事务吗?如果提交了外部事务,内部事务的回滚是否应该抛出错误?
发布于 2012-12-09 19:41:38
在您的示例中,事务Propagation.REQUIRED被用作缺省值,并且所有逻辑事务被映射到单个物理事务
当传播设置为PROPAGATION_REQUIRED时,将为应用该设置的每个方法创建一个逻辑事务作用域。每个这样的逻辑事务作用域都可以单独确定仅回滚状态,外部事务作用域在逻辑上独立于内部事务作用域。当然,在标准PROPAGATION_REQUIRED行为的情况下,所有这些作用域都将映射到同一物理事务。因此,在内部事务作用域中设置的仅限回滚的标记确实会影响外部事务实际提交的机会(正如您预期的那样)。
因此,在您的示例中,两个逻辑事务映射到一个物理事务。
请参阅documentation
发布于 2012-12-09 20:17:08
在当前代码中,第二个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());另外,您应该使用注释来管理事务,-that是将事务合并到代码中的一种更干净/更好的方式。程序化事务只适用于需要更多控制的极少数情况。此外,在进行编程事务时,建议使用TransactionTemplate。
https://stackoverflow.com/questions/13786816
复制相似问题