专栏目录
- 1-Spring架构源码分析-Spring源码搭建
- 2-Spring架构源码分析-SSM框架说明
- 3-Spring架构源码分析-spring体系
- 4-Spring架构源码分析-Spring IOC机制设计思想和源码解读
- 5-Spring架构源码分析-Spring IOC之 Spring 统一资源加载策略
- 6-Spring架构源码分析-IoC 之加载 BeanDefinition
- 7-Spring架构源码分析-IoC 之注册 BeanDefinitions
- 8-Spring架构源码分析-IoC 之解析Bean:解析 import 标签
- 9-Spring架构源码分析-IoC 之解析 bean 标签:开启解析进程
- 10-Spring架构源码分析-IoC 之解析 bean标签:BeanDefinition
- 11-Spring架构源码分析-IoC 之注册解析的 BeanDefinitions
- 12-Spring架构源码分析-IoC 之装载 BeanDefinitions 总结
- 13-Spring架构源码分析-IoC 之开启 Bean 的加载
- 14-Spring架构源码分析-IoC 之加载 Bean:总结
- 15-Spring架构源码分析-Spring代理与AOP
- 16-Spring AOP源码分析-@EnableAspectJAutoProxy和AspectJAutoProxyRegistrar
- 17-Spring AOP源码分析-AnnotationAwareAspectJAutoProxyCreator
- 18-Spring AOP源码分析-AOP与BeanPostProcessor处理器
- 19-Spring AOP源码分析-代理对象调用目标方法
- 20-spring mvc设计思想和源码解读-spring mvc 功能特性
- 21-mvc 体系结构源码详解
- 22-Spring MVC源码跟踪
- 23-Spring事务源码分析
Spring 事务分析
1.什么是事务?
数据库提供了一种机制,可用来将一系列数据库更改归入一个逻辑操作。更改数据库后,所做的更改可以作为一个单元进行提交或取消。事务可确保遵循原子性、一致性、隔离性和持续性(ACID)这几种属性,以使数据能够正确地提交到数据库中。
原子性:操作要么全部成功要么全部失败。
一致性:事务操作后数据状态不变。
隔离性:并发时的串行操作,且数据的中间状态不可被共享。
持久性:事务提交后结果就被持久化。
2.核心接口
2.1)PlatformTransactionManager: (平台)事务管理器
2.2)TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则
2.3)TransactionStatus: 事务运行状态
3.事务管理器
Spring并不直接管理事务,而是提供了多种事务管理器,他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
Spring事务管理器的接口是org.springframework.transaction.PlatformTransactionManager,通过这个接口,Spring为各个平台如JDBC、Hibernate等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了
JDBC事务
DataSourceTransactionManager是通过调用java.sql.Connection来管理事务,而后者是通过DataSource获取到的。通过调用连接的commit()方法来提交事务,同样,事务失败则通过调用rollback()方法进行回滚。
Hibernate事务
sessionFactory属性需要装配一个Hibernate的session工厂,HibernateTransactionManager的实现细节是它将事务管理的职责委托给org.hibernate.Transaction对象,而后者是从Hibernate Session中获取到的。当事务成功完成时,HibernateTransactionManager将会调用Transaction对象的commit()方法,反之,将会调用rollback()方法。
JPA事务
JpaTransactionManager只需要装配一个JPA实体管理工厂(javax.persistence.EntityManagerFactory接口的任意实现)。JpaTransactionManager将与由工厂所产生的JPA EntityManager合作来构建事务。
4.事务属性定义
名称、传播行为、隔离级别、超时时间、是否只读
5.传播行为
传播行为 | 含义 | 特点 |
---|---|---|
PROPAGATION_REQUIRED | 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务 | 默认事务 |
PROPAGATION_SUPPORTS | 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行 | 如果不在事务中,不会回滚 |
PROPAGATION_MANDATORY | 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常 | 必须在事务中运行 |
PROPAGATION_REQUIRED_NEW | 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager | 被其他事务包裹的时候,事务不回滚 |
PROPAGATION_NOT_SUPPORTED | 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager | 事务内的方法不进行事务 |
PROPAGATION_NEVER | 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常 | 当前有事务运行抛出异常 |
PROPAGATION_NESTED | 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务 | 嵌套时独立于当前事务提交或回滚,如果未设置事务属性则保持当前事务属性。不被嵌套时是REQUIRED事务 |
嵌套事务一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。
PROPAGATION_NESTED 与PROPAGATION_REQUIRES_NEW的区别:它们非常类似,都像一个嵌套事务,如果不存在一个活动的事务,都会开启一个新的事务。使用 PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA事务管理器的支持。
使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。DataSourceTransactionManager使用savepoint支持PROPAGATION_NESTED时,需要JDBC 3.0以上驱动及1.4以上的JDK版本支持。其它的JTA TrasactionManager实现可能有不同的支持方式。
PROPAGATION_REQUIRES_NEW 启动一个新的, 不依赖于环境的 “内部” 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。
另一方面, PROPAGATION_NESTED 开始一个 “嵌套的” 事务, 它是已经存在事务的一个真正的子事务. 潜套事务开始执行时, 它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交。
由此可见, PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于, PROPAGATION_REQUIRES_NEW 完全是一个新的事务, 而 PROPAGATION_NESTED 则是外部事务的子事务, 如果外部事务 commit, 嵌套事务也会被 commit, 这个规则同样适用于 roll back.
PROPAGATION_REQUIRED应该是我们首先的事务传播行为。它能够满足我们大多数的事务需求。
6.隔离级别
并发时容易导致的问题:
- 脏读(Dirty reads)——脏读发生在一个事务读取了另一个事务改写但尚未提交的数据时。如果改写在稍后被回滚了,那么第一个事务获取的数据就是无效的。
- 不可重复读(Nonrepeatable read)——不可重复读发生在一个事务执行相同的查询两次或两次以上,但是每次都得到不同的数据时。这通常是因为另一个并发事务在两次查询期间进行了更新。
- 幻读(Phantom read)——幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录。
级别:
ISOLATION_DEFAULT 使用后端数据库默认的隔离级别
ISOLATION_READ_UNCOMMITTED 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
ISOLATION_READ_COMMITTED 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
ISOLATION_REPEATABLE_READ 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生
ISOLATION_SERIALIZABLE 最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别,因为它通常是通过完全锁定事务相关的数据库表来实现的
7.只读
事务的第三个特性是它是否为只读事务。如果事务只对后端的数据库进行该操作,数据库可以利用事务的只读特性来进行一些特定的优化。通过将事务设置为只读,你就可以给数据库一个机会,让它应用它认为合适的优化措施。
8.事务超时
为了使应用程序很好地运行,事务不能运行太长的时间。因为事务可能涉及对后端数据库的锁定,所以长时间的事务会不必要的占用数据库资源。事务超时就是事务的一个定时器,在特定时间内事务如果没有执行完毕,那么就会自动回滚,而不是一直等待其结束。
9.回滚
默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚(这一行为与EJB的回滚行为是一致的)
但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。
10.事务状态
调用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一个实现
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
这个接口描述的是一些处理事务提供简单的控制事务执行和查询事务状态的方法,在回滚或提交的时候需要应用对应的事务状态。
11.编程式事务和声明式事务的区别
编程式事务允许用户在代码中精确定义事务的边界,而声明式事务(基于AOP)有助于用户将操作与事务规则进行解耦。
编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现。
12.如何实现编程式事务
Spring提供两种方式的编程式事务管理,分别是:使用TransactionTemplate和直接使用PlatformTransactionManager。
13.声明式事务的配置方式
1)给每个bean配置一个代理
<bean id="userDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<property name="target" ref="userDaoTarget" />
<property name="proxyInterfaces" value="com.bluesky.spring.dao.GeneratorDao" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
2)给所有bean共享一个代理基类
<bean id="transactionBase"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true" abstract="true">
<!-- 配置事务管理器 -->
<property name="transactionManager" ref="transactionManager" />
<!-- 配置事务属性 -->
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="userDao" parent="transactionBase" >
<property name="target" ref="userDaoTarget" />
</bean>
3)使用拦截器
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>*Dao</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</property>
</bean>
4)使用tx标签配置的拦截器
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="interceptorPointCuts"
expression="execution(* com.bluesky.spring.dao.*.*(..))" />
<aop:advisor advice-ref="txAdvice"
pointcut-ref="interceptorPointCuts" />
</aop:config>
5)全注解
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 定义事务管理器(声明式的事务) -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
专栏目录
- 1-Spring架构源码分析-Spring源码搭建
- 2-Spring架构源码分析-SSM框架说明
- 3-Spring架构源码分析-spring体系
- 4-Spring架构源码分析-Spring IOC机制设计思想和源码解读
- 5-Spring架构源码分析-Spring IOC之 Spring 统一资源加载策略
- 6-Spring架构源码分析-IoC 之加载 BeanDefinition
- 7-Spring架构源码分析-IoC 之注册 BeanDefinitions
- 8-Spring架构源码分析-IoC 之解析Bean:解析 import 标签
- 9-Spring架构源码分析-IoC 之解析 bean 标签:开启解析进程
- 10-Spring架构源码分析-IoC 之解析 bean标签:BeanDefinition
- 11-Spring架构源码分析-IoC 之注册解析的 BeanDefinitions
- 12-Spring架构源码分析-IoC 之装载 BeanDefinitions 总结
- 13-Spring架构源码分析-IoC 之开启 Bean 的加载
- 14-Spring架构源码分析-IoC 之加载 Bean:总结
- 15-Spring架构源码分析-Spring代理与AOP
- 16-Spring AOP源码分析-@EnableAspectJAutoProxy和AspectJAutoProxyRegistrar
- 17-Spring AOP源码分析-AnnotationAwareAspectJAutoProxyCreator
- 18-Spring AOP源码分析-AOP与BeanPostProcessor处理器
- 19-Spring AOP源码分析-代理对象调用目标方法
- 20-spring mvc设计思想和源码解读-spring mvc 功能特性
- 21-mvc 体系结构源码详解
- 22-Spring MVC源码跟踪
- 23-Spring事务源码分析