spring-tx,spring-jdbc模块笔记,只涉及事务部分
核心类
@EnableTransactionManagement:引入TransactionManagementConfigurationSelector,根据参数判断proxy/aspectj载入不同的解析对象,proxy模式下载入AutoProxyRegistrar和ProxyTransactionManagementConfiguration.
AutoProxyRegistrar:将InfrastructureAdvisorAutoProxyCreator加入到容器中.它将框架基础设施Advisor(role=BeanDefinition.ROLE_INFRASTRUCTURE)生成对应的aop代理
ProxyTransactionManagementConfiguration:载入了基于注解的aop基础设施Bean.主要是将解析注解的Advisor对象加入到容器中
TransactionAttributeSource:事务源信息的获取策略接口,载入的是AnnotationTransactionAttributeSource类,用于处理@Transaction注解
TransactionInterceptor-TransactionAspectSupport-invokeWithinTransaction执行流程
BeanFactoryTransactionAttributeSourceAdvisor:通过StaticMethodMatcherPointcut将方法级过滤转移到TransactionAttributeSource进行判断,advice部分转到TransactionInterceptor进行实现.自身作为advisor加入到容器
事务管理器-事务的流程抽象
PlatformTransactionManager:事务管理器接口定义,使用较多的是DataSourceTransactionManager.它是以DataSource中的connection抽象的事务对象
TransactionStatus:存储事务对象,挂起的上一个事务对象以及额外事务属性的接口.它是主要的中间数据,用于存储原始连接信息以便后续的恢复连接信息
TransactionDefinition:事务属性接口.传播属性,隔离级别,只读等.它的实现主要是DefaultTransactionDefinition
TransactionTemplate:继承DefaultTransactionDefinition,自身即含有事务状态,同时引入了PlatformTransactionManager进行事务操作,还实现了
TransactionOperations接口,提供了手工事务操作入口.
核心流程
首先通过TransactionManager的getTransaction(td)方法获得TransactionStatus对象,后面执行对应的回调方法,如果出异常那么回滚,如果正常执行完成,那么提交操作,这两个操作都需要之前返回的TransactionStatus对象作为入参.
以DataSourceTransactionManager为例,描述完整的事务管理过程
getTransaction()方法,先通过doGetTransaction抽象方法获取事务对象,事务对象是子类自己定义的,这里用的是DataSourceTransactionObject类,在doGetTransaction方法只是新建了DataSourceTransactionObject对象,尝试通过ThreadLocal获取之前的ConnectionHolder设置到当前事务对象中.
然后判断当前线程是否存在被激活的事务(这里根据是否存在当前事务对传播属性进行了实现)
如果有事务
那么检查事务传播行为,做出对应的操作,直接返回结果
事务传播行为对应的操作(获取连接=实际根据属性进行连接配置)
PROPAGATION_NEVER-抛异常
PROPAGATION_NOT_SUPPORTED-挂起当前事务,生成一个空的DefaultTransactionStatus返回(在非事务中执行)
PROPAGATION_REQUIRES_NEW-挂起当前事务,将原事务对象与被挂起的资源放入DefaultTransactionStatus对象,并获取连接(新建事务)
PROPAGATION_NESTED-不挂起当前事务,将原事务对象放入DefaultTransactionStatus对象,并获取连接(支持嵌套才可以,如果是DataSourceTM那么实际上还是同一连接)
其他情况-不挂起当前事务,将原事务对象放入DefaultTransactionStatus对象,直接返回,不获取连接(支持当前事务运行PROPAGATION_REQUIRED或PROPAGATION_SUPPORTS)
如果没有事务
根据对应的传播属性做出对应的操作并返回
PROPAGATION_MANDATORY-抛异常
PROPAGATION_REQUIRED&PROPAGATION_REQUIRES_NEW&PROPAGATION_NESTED-那么执行以下操作
新建TransactionStatus对象(DefaultTransactionStatus),执行doBegin抽象方法,这里doBegin方法先判断事务对象是否有连接,如果没有连接,那么调用DataSource.getConnection获取一个新连接并包装成ConnectionHolder对象放入事务对象内.然后对连接属性进行设置,有隔离级别,手动提交.还要读取Definition信息设置ConnectionHolder对象的属性.同时将之前的连接信息存储到事务对象中,用于后续提交或者回滚后恢复连接属性操作.后面继续判断如果是新连接,那么线程绑定事务对象,同时设置事务激活状态,绑定事务隔离级别,只读属性,名称等.返回TransactionStatus对象,让使用者在可以拿到事务的属性信息.结束创建事务流程.
其他情况-生成一个空的DefaultTransactionStatus返回(在非事务中执行,如PROPAGATION_SUPPORTS,PROPAGATION_NOT_SUPPORTED)
中间在事务中执行对应的sql.
详细说下这里连接对象的获取过程.对于mybatis-spring来说,使用的是SpringManagedTransaction对象进行管理DataSource来获取连接的,这里的getConnection会转到DataSourceUtils的getConnection中,它优先判断从绑定线程中可以获取对应的ConnectionHolder,并且事务是被激活的状态,那么从ConnectionHolder拿出连接直接返回,如果不是的话就获取真实连接,再判断当前事务是否激活,如果是被激活的,那么注册ConnectionSynchronization(用于清理资源)和将ConnectionHolder绑定到当前线程.最后返回连接对象
最后如果抛出异常
回滚操作.先触发绑定线程中的BeforeCompletion回调,然后调用connection的rollback,根据有无异常,触发AfterCompletion的回调并传入不同参数.最后触发AfterCompletion的回调
如果没有抛出异常
提交.检查是否有本地/全局回滚标志,如果有的话调用回滚操作,如果没有,触发BeforeCommit回调,然后BeforeCompletion回调,然后调用connection的commit.如果有异常触发回滚,如果没有,触发AfterCommit回调,最后触发AfterCompletion回调,然后进行清理过程,清理掉所有线程绑定的对象,恢复连接属性(自动提交,隔离级别,只读属性),恢复之前挂起的事务.当前事务结束
事务特点
1.原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做
2.一致性:数据不会因为事务的执行而遭到破坏
3.隔离性:一个事物的执行,不受其他事务的干扰,即并发执行的事物之间互不干扰
4.持久性:一个事物一旦提交,它对数据库的改变就是永久的。
七个事务传播属性—传播属性的实现是spring实现的,有些传播属性(比如PROPAGATION_NESTED)主要是JTA考虑的
PROPAGATION_REQUIRED -- 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS -- 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY -- 支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW -- 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED -- 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER -- 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
五种隔离级别—隔离级别的实现是依靠数据库自身实现的
隔离级别是指若干个并发的事务之间的隔离程度。
ISOLATION_DEFAULT--这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应;
ISOLATION_READ_UNCOMMITTED--这是事务最低的隔离级别,它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED--保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
ISOLATION_REPEATABLE_READ--这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它保证了一个事务中的所有读取操作时一致的结果,不受事务中其他事务提交的影响.但是会产生幻读,比如说范围查询时,每次查询结果是一致的,但是其他事务新插入了符合条件的行,导致执行的范围更新比查询结果多,就像产生的幻觉.部分数据库在RR级别已经可以解决幻读的问题了
ISOLATION_SERIALIZABLE--这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。