Spring事务
2、【源码】Spring Data JPA原理解析之事务注册原理
3、【源码】Spring Data JPA原理解析之事务执行原理
对于数据库的操作,可能存在脏读、不可重复读、幻读等问题,从而引入了事务的概念。
事务是指在数据库管理系统中,一系列紧密相关的操作序列,这些操作作为一个单一的工作单元执行。事务的特点是要么全部成功,要么全部失败,不会出现部分完成的情况。如果事务中的任何一个操作失败,那么整个事务都会被回滚到开始之前的状态,以确保数据库的一致性和完整性。
事务具有4个特性:原子性、一致性、隔离性和持久性。通常称为ACID。
1)原子性(Atomicity)
事务是一个不可分割的工作单位,事务中包含的所有操作要么全部成功,要么全部失败。
2)隔离性(Isolation)
一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的。
3)持久性(Durability)
一旦事务提交成功,则其所做的修改就会永久保存在数据库中,即使发生系统故障也不会丢失。
4)一致性(Consistency)
事务必须确保数据库从一个一致性状态转变到另一个一致性状态。
更准确的说,事务是通过原子性、隔离性和持久性,实现了事务的一致性。另外,一致性还需要额外的工作来保证,如转账,从A转给B,A的资金减少了,B的资金增加了。转账要么成功、要么失败,但不管成功还是失败,事务的一致性要求两人的资金之和必须一致,要么成功,A减少了、B增加了,要么失败,A和B的资金都不变。为了一致性,需要程序来开启事务,同时修改A和B的资金,从而才能保证一致性。
在SpringBoot框架中,会自动引入TransactionAutoConfiguration。且在META-INF的spring-autoconfigure-metadata.properties有如下配置:
- org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration=
- org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration=
- org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration.ConditionalOnBean=org.springframework.transaction.TransactionManager
说明在自动引入TransactionAutoConfiguration时,必须存在TransactionManager的bean,且要先引入内部类EnableTransactionManagementConfiguration。
内部类EnableTransactionManagementConfiguration的源码如下:
- public class TransactionAutoConfiguration {
- @Configuration(proxyBeanMethods = false)
- @ConditionalOnBean(TransactionManager.class)
- @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
- public static class EnableTransactionManagementConfiguration {
-
- @Configuration(proxyBeanMethods = false)
- @EnableTransactionManagement(proxyTargetClass = false)
- @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
- public static class JdkDynamicAutoProxyConfiguration {
-
- }
-
- @Configuration(proxyBeanMethods = false)
- @EnableTransactionManagement(proxyTargetClass = true)
- @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
- matchIfMissing = true)
- public static class CglibAutoProxyConfiguration {
-
- }
-
- }
- }
EnableTransactionManagementConfiguration内中会自动引入JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration,且添加了@EnableTransactionManagement注解。该注解会自动引入TransactionManagementConfigurationSelector。TransactionManagementConfigurationSelector的父类实现了ImportSelector接口,该类的selectImports()方法返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration类名数组,即AutoProxyRegistrar和ProxyTransactionManagementConfiguration会自动注入到Spring IOC容器中。
Spring的配置类解析的时候,会执行ConfigurationClassParser.processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection
importCandidates, boolean checkForCircularImports),在该方法中,判断importCandidates是否继承于ImportSelector接口,如果是,调用ImportSelector的selectImports()方法,获取需要额外自动加入容器的类。
ProxyTransactionManagementConfiguration的源码如下:
- package org.springframework.transaction.annotation;
-
- /**
- * Transaction事务管理代理的配置类
- */
- @Configuration
- @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
- public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
-
- /**
- * 返回一个BeanFactoryTransactionAttributeSourceAdvisor【继承AbstractBeanFactoryPointcutAdvisor,重
- * 写了getPointcut()方法。即当前Advisor包含了事务需要的advice以及pointcut】
- * @return
- */
- @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
- @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
- public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
- // 声明一个BeanFactoryTransactionAttributeSourceAdvisor对象,
- // 传入的transactionAttributeSource为AnnotationTransactionAttributeSource
- BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
- advisor.setTransactionAttributeSource(transactionAttributeSource());
- advisor.setAdvice(transactionInterceptor());
- if (this.enableTx != null) {
- advisor.setOrder(this.enableTx.
getNumber("order")); - }
- return advisor;
- }
-
- /**
- * 创建一个AnnotationTransactionAttributeSource对象,该继承AbstractFallbackTransactionAttributeSource,
- * 对外提供了getTransactionAttribute()方法。该方法返回某个方法的事务注解信息
- */
- @Bean
- @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
- public TransactionAttributeSource transactionAttributeSource() {
- return new AnnotationTransactionAttributeSource();
- }
-
- /**
- * 创建一个TransactionInterceptor对象
- * @return
- */
- @Bean
- @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
- public TransactionInterceptor transactionInterceptor() {
- TransactionInterceptor interceptor = new TransactionInterceptor();
- interceptor.setTransactionAttributeSource(transactionAttributeSource());
- if (this.txManager != null) {
- interceptor.setTransactionManager(this.txManager);
- }
- return interceptor;
- }
-
- }
在ProxyTransactionManagementConfiguration中,自动注入了BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource和TransactionInterceptor。添加了事务处理的advisor,该advisor生效时,会执行TransactionInterceptor拦截器。
BeanFactoryTransactionAttributeSourceAdvisor的源码如下:
- package org.springframework.transaction.interceptor;
-
- /**
- * 继承AbstractBeanFactoryPointcutAdvisor,重写了getPointcut()方法。即当前Advisor包含了事务需要的advice以及pointcut
- * 1、维护TransactionAttributeSource对象;
- * 2、创建一个TransactionAttributeSourcePointcut,重写getTransactionAttributeSource(),返回TransactionAttributeSource对
- * 象给TransactionAttributeSourcePointcut,进行方法事务注解判断
- */
- @SuppressWarnings("serial")
- public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
-
- // 在ProxyTransactionManagementConfiguration类中的transactionAdvisor()方法,
- // 设置transactionAttributeSource为AnnotationTransactionAttributeSource
- @Nullable
- private TransactionAttributeSource transactionAttributeSource;
-
- private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
- @Override
- @Nullable
- protected TransactionAttributeSource getTransactionAttributeSource() {
- return transactionAttributeSource;
- }
- };
-
- public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
- this.transactionAttributeSource = transactionAttributeSource;
- }
-
- public void setClassFilter(ClassFilter classFilter) {
- this.pointcut.setClassFilter(classFilter);
- }
-
- @Override
- public Pointcut getPointcut() {
- return this.pointcut;
- }
-
- }
在BeanFactoryTransactionAttributeSourceAdvisor切面中,切点为自定义的实现抽象类TransactionAttributeSourcePointcut的对象,抽象方法getTransactionAttributeSource()返回的TransactionAttributeSource对象为ProxyTransactionManagementConfiguration的transactionAdvisor()方法传入的AnnotationTransactionAttributeSource对象。
TransactionAttributeSourcePointcut的源码如下:
- package org.springframework.transaction.interceptor;
-
- /**
- * 抽象类,继承StaticMethodMatcherPointcut,属于静态的方法匹配。在方法匹配中,通过抽象方法getTransactionAttributeSource()获
- * 取TransactionAttributeSource对象,然后执行TransactionAttributeSource.getTransactionAttribute(),判断方法是否有事务注解,
- * 如果有,表示匹配;没有则不匹配
- */
- @SuppressWarnings("serial")
- abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
-
- @Override
- public boolean matches(Method method, @Nullable Class> targetClass) {
- if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
- return false;
- }
- // 返回AnnotationTransactionAttributeSource
- TransactionAttributeSource tas = getTransactionAttributeSource();
- // 在AnnotationTransactionAttributeSource的getTransactionAttribute()方法中,
- // 获取方法添加的@Transactional注解的信息,如果没有添加@Transactional注解,返回null
- return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof TransactionAttributeSourcePointcut)) {
- return false;
- }
- TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
- return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
- }
-
- @Override
- public int hashCode() {
- return TransactionAttributeSourcePointcut.class.hashCode();
- }
-
- @Override
- public String toString() {
- return getClass().getName() + ": " + getTransactionAttributeSource();
- }
-
- /**
- * 抽象方法,获得一个TransactionAttributeSource对象
- * @return
- */
- @Nullable
- protected abstract TransactionAttributeSource getTransactionAttributeSource();
-
- }
TransactionAttributeSourcePointcut继承StaticMethodMatcherPointcut,StaticMethodMatcherPointcut的类匹配默认为ClassFilter.TRUE,即匹配所有的类。
当Spring中的bean对象声明之后,都会调用BeanFactoryTransactionAttributeSourceAdvisor切面,遍历bean的方法,执行切点的matches(Method method, @Nullable Class> targetClass)方法,该方法执行如下:
6.1)调用getTransactionAttributeSource(),获取一个TransactionAttributeSource。此处为AnnotationTransactionAttributeSource对象;
6.2)因为TransactionAttributeSource对象不为空,所以执行TransactionAttributeSource的getTransactionAttribute()方法,该方法会执行AnnotationTransactionAttributeSource的父类AbstractFallbackTransactionAttributeSource的getTransactionAttribute()方法,如果方法有返回值,则matches()方法返回true。对应的bean创建代理类,并添加Advisor中的拦截器,即添加TransactionInterceptor;
在该方法中,最终会调用子类AnnotationTransactionAttributeSource的determineTransactionAttribute()方法,遍历事务的解析器,从解析器中获取事务属性信息;结合1)中的描述,会解析org.springframework.transaction.annotation包和javax.transaction包下的@Transactional注解。如果没有@Transactional注解,getTransactionAttribute()最终返回null。matches()会返回false,即不支持,如果有注解,则返回true。对应的bean创建代理类,并添加Advisor中的拦截器,即添加TransactionInterceptor;
AnnotationTransactionAttributeSource的相关源码如下:
- package org.springframework.transaction.annotation;
-
- /**
- * 继承AbstractFallbackTransactionAttributeSource,对外提供了getTransactionAttribute()方法。该方法返回某个方法的事务注解信息
- * 1、添加不同类型的事务注解解析器,用于解析注解信息。支撑jta、ejb和spring的事务
- */
- @SuppressWarnings("serial")
- public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
- implements Serializable {
-
- /** 判断包中是否有javax.transaction.Transactional这个类,即项目中是否有对应的包。如果有,则需要添加对应的事务解析器 */
- private static final boolean jta12Present = ClassUtils.isPresent(
- "javax.transaction.Transactional", AnnotationTransactionAttributeSource.class.getClassLoader());
-
- /** 判断包中是否有javax.ejb.TransactionAttribute这个类,即项目中是否有对应的包。如果有,则需要添加对应的事务解析器 */
- private static final boolean ejb3Present = ClassUtils.isPresent(
- "javax.ejb.TransactionAttribute", AnnotationTransactionAttributeSource.class.getClassLoader());
-
- /** 标记是否只有public方法才可以添加事务,默认为true */
- private final boolean publicMethodsOnly;
-
- private final Set
annotationParsers; -
- public AnnotationTransactionAttributeSource() {
- this(true);
- }
-
- /**
- * 设置publicMethodsOnly的值,并添加事务的注解解析器集合
- */
- public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
- this.publicMethodsOnly = publicMethodsOnly;
- if (jta12Present || ejb3Present) {
- this.annotationParsers = new LinkedHashSet<>(4);
- // 添加spring的Transactional注解解析器
- this.annotationParsers.add(new SpringTransactionAnnotationParser());
- // 根据条件,添加jta和ejb3两种事务的注解解析器
- if (jta12Present) {
- this.annotationParsers.add(new JtaTransactionAnnotationParser());
- }
- if (ejb3Present) {
- this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
- }
- }
- else {
- // 如果不支持jta和ejb3两种注解的事务,则只添加spring的Transactional注解解析器
- this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
- }
- }
-
- /**
- * 调用determineTransactionAttribute()方法,从类中查找事务注解信息
- */
- @Override
- @Nullable
- protected TransactionAttribute findTransactionAttribute(Class> clazz) {
- return determineTransactionAttribute(clazz);
- }
-
- /**
- * 调用determineTransactionAttribute()方法,从方法中查找事务注解信息
- */
- @Override
- @Nullable
- protected TransactionAttribute findTransactionAttribute(Method method) {
- return determineTransactionAttribute(method);
- }
-
- /**
- * 确定事务属性。遍历事务解析器集合,对当前element进行解析,如果能够正常解析,则返回对应
- * 的TransactionAttribute【RuleBasedTransactionAttribute对象】;否则返回null
- */
- @Nullable
- protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
- for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
- TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
- if (attr != null) {
- return attr;
- }
- }
- return null;
- }
-
- }
在AnnotationTransactionAttributeSource构造方法中,会添加SpringTransactionAnnotationParser和JtaTransactionAnnotationParser事务注解解析器。
SpringTransactionAnnotationParser的源码如下:
- package org.springframework.transaction.annotation;
- /**
- * 实现TransactionAnnotationParser,解析org.springframework.transaction.annotation.Transactional的注解信息,
- * 返回一个RuleBasedTransactionAttribute对象
- */
- @SuppressWarnings("serial")
- public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
-
- /**
- * 解析@Transaction注解,获取一个TransactionAttribute对象
- */
- @Override
- @Nullable
- public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
- // 在所提供的element上方的注释层次结构中查找Transactional的第一个注释,
- // 并将该注释的属性与注释层次结构较低级别注释中的匹配的attribute合并
- AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
- element, Transactional.class, false, false);
- // 解析Transactional注解,返回一个RuleBasedTransactionAttribute对象
- if (attributes != null) {
- return parseTransactionAnnotation(attributes);
- }
- else {
- return null;
- }
- }
-
- public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
- return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
- }
-
- /**
- * 从注解属性对象中,获取事务注解相关属性信息,封装成RuleBasedTransactionAttribute对象
- */
- protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
- // 根据注解的信息,创建一个RuleBasedTransactionAttribute对象
- RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
-
- Propagation propagation = attributes.getEnum("propagation");
- rbta.setPropagationBehavior(propagation.value());
- Isolation isolation = attributes.getEnum("isolation");
- rbta.setIsolationLevel(isolation.value());
- rbta.setTimeout(attributes.getNumber("timeout").intValue());
- rbta.setReadOnly(attributes.getBoolean("readOnly"));
- rbta.setQualifier(attributes.getString("value"));
-
- // 添加回滚规则
- List
rollbackRules = new ArrayList<>(); - for (Class> rbRule : attributes.getClassArray("rollbackFor")) {
- rollbackRules.add(new RollbackRuleAttribute(rbRule));
- }
- for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
- rollbackRules.add(new RollbackRuleAttribute(rbRule));
- }
- for (Class> rbRule : attributes.getClassArray("noRollbackFor")) {
- rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
- }
- for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
- rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
- }
- rbta.setRollbackRules(rollbackRules);
-
- return rbta;
- }
-
-
- @Override
- public boolean equals(Object other) {
- return (this == other || other instanceof SpringTransactionAnnotationParser);
- }
-
- @Override
- public int hashCode() {
- return SpringTransactionAnnotationParser.class.hashCode();
- }
-
- }
SpringTransactionAnnotationParser用于解析org.springframework.transaction.annotation包下的@Transactional的注解信息。
JtaTransactionAnnotationParser的源码如下:
- package org.springframework.transaction.annotation;
-
- /**
- * 实现TransactionAnnotationParser,用于解析javax.transaction.Transactional注解的事务属性。返回一个RuleBasedTransactionAttribute对象
- */
- @SuppressWarnings("serial")
- public class JtaTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {
-
- /**
- * 判断是否有javax.transaction.Transactional,如果有,则进行注解解析【解析传播行为,回滚的异常类、不回滚的异常类设置回滚规则】,
- * 返回一个RuleBasedTransactionAttribute对象
- * @param element
- * @return
- */
- @Override
- @Nullable
- public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
- AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
- element, javax.transaction.Transactional.class);
- if (attributes != null) {
- return parseTransactionAnnotation(attributes);
- }
- else {
- return null;
- }
- }
-
- public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) {
- return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
- }
-
- protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
- RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
-
- // 通过注解的value设定传播行为。默认为REQUIRED
- rbta.setPropagationBehaviorName(
- RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString());
-
- // 根据设置的回滚的异常类,添加回滚规则
- List
rollbackRules = new ArrayList<>(); - for (Class> rbRule : attributes.getClassArray("rollbackOn")) {
- rollbackRules.add(new RollbackRuleAttribute(rbRule));
- }
- // 根据设置的不回滚的异常类,添加回滚规则,定义为不回滚
- for (Class> rbRule : attributes.getClassArray("dontRollbackOn")) {
- rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
- }
- rbta.setRollbackRules(rollbackRules);
-
- return rbta;
- }
-
-
- @Override
- public boolean equals(Object other) {
- return (this == other || other instanceof JtaTransactionAnnotationParser);
- }
-
- @Override
- public int hashCode() {
- return JtaTransactionAnnotationParser.class.hashCode();
- }
-
- }
JtaTransactionAnnotationParser用于解析javax.transaction包下的@Transactional注解。
在6.2)中调用AnnotationTransactionAttributeSource的getTransactionAttribute(),最终会调用AnnotationTransactionAttributeSource的determineTransactionAttribute()方法,遍历事务注解的解析器,从解析器中获取事务属性信息。只要方法中添加了org.springframework.transaction.annotation包或javax.transaction包的@Transactional注解,则能够正常获取事务属性信息。
限于篇幅,本篇先分享到这里。以下做一个小结:
1)在SpringBoot框架的项目,项目启动时,会自动开启@EnableTransactionManagement注解,从而自动添加BeanFactoryTransactionAttributeSourceAdvisor切面,添加TransactionAttributeSourcePointcut切点。该切点的ClassFilter为ClassFilter.TRUE,即过滤所有的类。
2)Spring的bean自动注入时,会执行BeanFactoryTransactionAttributeSourceAdvisor切面,遍历bena的方法,执行TransactionAttributeSourcePointcut的matches()。在该方法中,会执行AnnotationTransactionAttributeSource的getTransactionAttribute()方法,判断方法是否添加了org.springframework.transaction.annotation包或javax.transaction包下的@Transactional注解,如果有,则bean的代理类中添加TransactionInterceptor拦截器;
关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。