4.1.1:doGetTransaction获取事务对象 doGetTransaction的实现在DataSourceTransactionManager中,doGetTransactiond创建一个DataSourceTransactionObject用于表示事务。并尝试获取一个与当前线程关联的Connection,这一部分工作交给事务同步管理器TransactionSynchronizationManager来完成。核心在doGetResource方法上。
private static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<Map<Object, Object>>("Transactional resources"); private static Object doGetResource(Object actualKey) { Map<Object, Object> map = resources.get(); if (map == null) { return null; } Object value = map.get(actualKey); // Transparently remove ResourceHolder that was marked as void... if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) { map.remove(actualKey); // Remove entire ThreadLocal if empty... if (map.isEmpty()) { resources.remove(); } value = null; } return value; }
以当前Datasoure对象为key ,从ThreadLocal对象resources中获取Connection
4.1.2:没有事务属性创建一个事务属性
4.1.3:判断当前是否有事务存在(重点) 默认是false,子类可以重写isExistingTransaction方法。DataSourceTransactionManager中重写了此方法
@Override protected boolean isExistingTransaction(Object transaction) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive()); }
查看事务对象获取的Connectin是否为空,Connection是否活跃。是否存在事务指:当前线程中是否存在以当前数据源为key的获取连接Connection.
4.1.3.1:
handleExistingTransaction(处理当前有事务的情况) 事务的传播属性处理
- NEVER: 不支持当前事务,因为当前有事务,抛出异常
- NOT_SUPPORTED:不支持当前事务,当前有事务存在,就挂起当前事务。所谓的
suspend(transaction)
挂起在代码里的表现是:(1)将当前是我的ConnectionHolder设置为null(2)从ThreadLocal对象resources中移除当前线程的Connection(3)将事务的挂起状态封装到SuspendedResourcesHolder中设置到TransactionStatus中,返回。 - REQUIRES_NEW:挂起当前事务,创建新事务。
suspend(transaction)
挂起,doBegin(transaction, definition)
创建新事务; - NESTED:嵌套事务。分为非JTA事务与JTA事务。JTA事务创建
doBegin(transaction, definition)
创建新事务 - SUPPORTS/REQUIRED/MANDATORY: 不处理
4.1.4: 校验超时
4.1.5:处理当前没有事务的情况
- MANDATORY: 支持当前事务,当前事务没有,则抛出异常
- REQUIRED/REQUIRES_NEW/NESTED: 创建新事务
doBegin(transaction, definition)
- NOT_SUPPORTED/SUPPORTS/NEVER: 只是打印warn日志。隔离无意义。
事务创建 doBegin
- 事务里没有数据库连接Connection,则从dataSource里获取一个
- 设置隔离级别
- 设置数据库自动提交为false
- 把Connection放到ThreadLocal对象resources中
至此:getTransaction 返回一个封装了事务的TransactionStatus对象。 总结下:getTransaction 方法重要点:
- 获取数据连接,
- 处理spring事务传播方式
- 设置自动提交为false
4.2prepareTransactionInfo方法
prepareTransactionInfo方法主要是封装:事务管理器PlatformTransactionManager
对象,TransactionAttribute
事务属性对象,方法名
joinpointIdentification
,TransactionStatus
对象 成一TransactionInfo
对象。并把TransactionInfo
对象通过bindToThread()
方法绑定到ThreadLocal<TransactionInfo> transactionInfoHolder
。
至此: createTransactionIfNecessary完成,得到一个TransactionInfo对象。
5.invocation.proceedWithInvocation();
执行下一个增强。在没其他增强的情况下,这通常会导致调用目标对象。
6.completeTransactionAfterThrowing
在目标方法执行错误的情况下,catch异常,执行回滚。 核心在DataSourceTransactionManager.doRollback方法
Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Rolling back JDBC transaction on Connection [" + con + "]"); } try { con.rollback(); }
7.cleanupTransactionInfo(txInfo)
finally 一定执行,清除事务信息。 其实就是把ThreadLocal transactionInfoHolder里的新事务信息清除掉。设置为原事务信息
8.commitTransactionAfterReturning(txInfo);
提交事务 核心在DataSourceTransactionManager.doCommit方法
Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Committing JDBC transaction on Connection [" + con + "]"); } try { con.commit(); }
至此整个事务执行原理完成。里面涉及到很多细节,由于篇幅的原因不能一一列出。建议多看代码。
总结
事务代理的执行,其实就是在AOP基础上的建立起来的。
关键是理解TransactionInterceptor(Advice)。在目标方法执行前后对其进行事务控制的增强。