Spring SuspendedResourcesHolder

Spring的局部事务管理策略是基于PlatformTransactionManager(PTM)的, 这个接口比较单纯, 只有如下三个方法. 
    TransactionStatus getTransaction(TransactionDefinition definition) throws  TransactionException;
    void commit(TransactionStatus status) throws TransactionException;
    void rollback(TransactionStatus status) throws TransactionException;

    设想有个Service(A), 它采用声明式事务, 事务传播行为是PROPAGATION_REQUIRED. 同时使用DataSourceTransactionManager(DTM)作为事务管理器. 那么在调用Service(A)之前, TransactionInterceptor会构造TransactionInfo(A), 并把它绑定到当前线程上, 同时调用DTM.getTransaction方法, 以下是DTM.getTransaction方法调用完毕后一种可能的事务状态.
TransactionInfo(A)
  |->oldTransactionInfo = null
  |->TransactionStatus(A)
         |->newTransaction=true
         |->savepoint=null
         |->DataSourceTransactionObject(A)
                |->newConnectionHolder=true
                |->SuspendedResourcesHolder(A)
                |      |->suspendedResources=null
                |->ConnectionHolder(A)
                       |->connectionHandle=SimpleConnectionHandle(dataSource.getConnection())
                       |->transactionActive=true

    假设在Service(A)中调用了Service(B), 它的事务传播行为也是PROPAGATION_REQUIRED. 以下是为Service(B)调用了DTM.getTransaction方法后一种可能的事务状态.
TransactionInfo(B)
  |->oldTransactionInfo=TransactionInfo(A)
  |->TransactionStatus(B)
         |->newTransaction=false
         |->savepoint=null
         |->DataSourceTransactionObject(B)
                |->newConnectionHolder=false
                |->SuspendedResourcesHolder(B)
                |      |->suspendedResources=null
                |->ConnectionHolder(A)
    TransactionInfo(A)和TransactionInfo(B)是绑定到当前线程的, 而且从以上两个状态描述中可以看出来, TransactionInfo采用了单向链表结构, 表头永远是当前堆栈栈顶的方法对应的TransactionInfo对象. 由于Service(A)和Service(B)的事务传播行为都是PROPAGATION_REQUIRED, 所以TransactionStatus(B)的newTransaction属性是false, 也就是在对Service(B)的调用中并没有开启新的事务. 同时DataSourceTransactionObject(B)的ConnectionHolder引用是指向ConnectionHolder(A)的, 也就是说在Service(B)中将和Service(A)使用同一个JDBC连接.

    假设在Service(A)中调用了Service(B), 它的事务传播行为是PROPAGATION_REQUIRE_NEW. 以下是为Service(B)调用了DTM.getTransaction方法后一种可能的事务状态.
TransactionInfo(B)
  |->oldTransactionInfo=TransactionInfo(A)
  |->TransactionStatus(B)
         |->newTransaction=true
         |->savepoint=null
         |->DataSourceTransactionObject(B)
                |->newConnectionHolder=true
                |->SuspendedResourcesHolder(B)
                |      |->suspendedResources=ConnectionHolder(A)
                |->ConnectionHolder(B)
                       |->connectionHandle=SimpleConnectionHandle(dataSource.getConnection())
                       |->transactionActive=true
    由于Service(B)的事务传播行为是PROPAGATION_REQUIRE_NEW, 那么Service(A)的事务将被挂起, 在SuspendedResourcesHolder(B)的suspendedResources属性中保存了被挂起的ConnectionHolder(A). ConnectionHolder(B)也不再指向ConnectionHolder(A), 而是获得一个新的JDBC连接, 同时DTM会把ConnectionHolder(B)绑定到当前线程上. 这意味着Service(B)的事务会在一个不同于Service(A)的JDBC连接中进行. 直到Service(B)方法执行完毕后, DTM会把ConnectionHolder(A)重新绑定到当前线程上, 也就是说接下来的Service(A)方法中仍然会使用ConnectionHolder(A)中保存的JDBC连接. 

    如果Service(B)的事务传播行为是PROPAGATION_NOT_SUPPORTED, 那么Service(A)的事务将被挂起, 同时DTM会解除当前线程上ConnectionHolder(A)的绑定. 但是并不会获得一个新的JDBC连接(因为不需要为ServiceB开启事务, 同时TransactionStatus(B)的newTransaction属性是false). 但是如果在Service(B)中使用了DataSourceUtils.getConnection()方法, 那么在Service(B)中会获得一个新的JDBC连接, 并绑定一个新的ConnectionHolder到当前线程上.

    如果Service(B)的事务传播行为是PROPAGATION_NESTED, 那么会开启一个嵌套事务. 首先引用一下Juergen Hoeller关于嵌套事务的描述:
PROPAGATION_NESTED on the other hand starts a "nested" transaction, which is a true subtransaction of the existing one. What will happen is that a savepoint will be taken at the start of the nested transaction. íf the nested transaction fails, we will roll back to that savepoint. The nested transaction is part of of the outer transaction, so it will only be committed at the end of of the outer transaction.
Nested transactions essentially allow to try some execution subpaths as subtransactions: rolling back to the state at the beginning of the failed subpath, continuing with another subpath or with the main execution path there - all within one isolated transaction, and not losing any previous work done within the outer transaction. 
    也就是说, 嵌套事务和外层事务使用的是同一个JDBC连接上的事务, 嵌套事务伴随着外层事务的提交而提交, 如果嵌套事务rollback, 那么嵌套事务会回滚到嵌套事务开启时的Save Point处, 而外层事务不受影响. 因此嵌套事务需要支持JDBC 3.0 Save Point特性的数据库以及JDBC驱动程序(用con.getMetaData().supportsSavepoints()判断, MySql5.1支持). 以下是为Service(B)调用了DTM.getTransaction方法调用完毕后相关的事务状态. 其中TransactionStatus(B)的savepoint属性保存了con.setSavepoint()返回的Savepoint对象.
TransactionInfo(B)
  |->oldTransactionInfo=TransactionInfo(A)
  |->TransactionStatus(B)
         |->newTransaction=false
         |->savepoint=Savepoint(B)
         |->DataSourceTransactionObject(B)
                |->newConnectionHolder=false
                |->SuspendedResourcesHolder(B)
                |      |->suspendedResources=null

                |->ConnectionHolder(A)




http://whitesock.iteye.com/blog/161868


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值