前言

有好长一段时间没写文章了,之前一直在找工作,如今工作换好了,可以继续写文章了,今天我们来讲讲spring的声明式事务。

开始

说到声明式事务,我们现在回顾一下事务这个概念,什么是事务呢,事务指的是逻辑上的⼀组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功。从而确保了数据的准确与安全。事务有着四大特性(ACID),分别是

原子性(Atomicity)原⼦性是指事务是⼀个不可分割的⼯作单位,事务中的操作要么都发⽣,要么都不发⽣。

⼀致性(Consistency)事务必须使数据库从⼀个⼀致性状态变换到另外⼀个⼀致性状态。

        隔离性(Isolation)事务的隔离性是多个⽤户并发访问数据库时,数据库为每⼀个⽤户开启的事务,每个事务不能被其他事务的操作数据所⼲扰,多个并发事务之间要相互隔离。
       
        持久性(Durability) 持久性是指⼀个事务⼀旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发⽣故障
也不应该对其有任何影响。

在spring中,一共有两种方式可以实现事务控制,分别是编程式事务和声明式事务。编程式事务指的是在代码中添加事务控制代码,而声明式事务指的是利用xml或者注解的形式来配置控制事务,下面就以纯注解配置声明式事务为例进行剖析。

spring开启声明式事务的注解是@EnableTransactionManagement,讲到这里首先要明白一点,spring的事务管理器管理事务其实就是利用aop的方式,通过创建动态代理加上拦截,实现的事务管理。在spring的配置类中加上这个注解,就支持了声明式事务,那么spring是怎么通过这么一个注解就可以支持事务的呢,我们来看代码。

首先我们看到,在这个注解上,import了一个selector

@Import(TransactionManagementConfigurationSelector.class)

我们看这个selector类中的这么一段代码

@Overrideprotected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY:return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {determineTransactionAspectClass()};default:return null;}}

这段代码中,引入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个类,我们先来看AutoProxyRegistrar这个类,这个类中有一段这样的代码

if (mode == AdviceMode.PROXY) {//重要的是这句代码AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);if ((Boolean) proxyTargetClass) {AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);return;}
}//我们进到这个方法中
@Nullablepublic static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {//可以看到引入了InfrastructureAdvisorAutoProxyCreator这个类,那么这个类又是什么呢return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);}//先看一下
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {@Nullableprivate ConfigurableListableBeanFactory beanFactory;@Overrideprotected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {super.initBeanFactory(beanFactory);this.beanFactory = beanFactory;}@Overrideprotected boolean isEligibleAdvisorBean(String beanName) {return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);}}

看一下继承结构图

可以看到这个方法间接继承于SmartInstantiationAwareBeanPostProcessor,最终继承于BeanPostProcessor,这说明InfrastructureAdvisorAutoProxyCreator类是一个后置处理器,并且跟 spring AOP 开启@EnableAspectJAutoProxy 时注册的AnnotationAwareAspectJProxyCreator实现的是同⼀个接口,这也对应了我之前所说声明式事务是springAOP思想的一种应用。

然后我们回过头来再看ProxyTransactionManagementConfiguration这个类,我们看到其中有一个事务增强器,一个属性解析器和是一个事务拦截器

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {// 事务增强器BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();// 注入属性解析器advisor.setTransactionAttributeSource(transactionAttributeSource);// 注入事务拦截器advisor.setAdvice(transactionInterceptor);if (this.enableTx != null) {advisor.setOrder(this.enableTx.<Integer>getNumber("order"));}return advisor;}@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)// 属性解析器public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)// 事务拦截器public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource);if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;}

先看看属性解析器

//注解解析器集合private final Set<TransactionAnnotationParser> annotationParsers;

这是一个注解解析器的集合,可以添加多种注解解析器,在这里我们主要关注的是spring事务注解解析器SpringTransactionParser,看一下相关代码

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();// 对应Transaction注解的相关属性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<RollbackRuleAttribute> 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;}

可以看到这段代码中的Enum和ClassArray其实正是@Transaction注解中的相关属性,这个属性解析器的作用之一就是用来解析@Transaction注解中的属性

看完了属性解析器,我们接下来看事务拦截器TransactionInterceptor,其中重要的是这段代码

    @Override@Nullablepublic Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...// 增加事务支持return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}

然后我们进到这个方法里面

@Nullableprotected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.// 获取属性解析器,在配置类ProxyTransactionManagementConfiguration配置时加入TransactionAttributeSource tas = getTransactionAttributeSource();final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);final TransactionManager tm = determineTransactionManager(txAttr);if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {throw new TransactionUsageException("Unsupported annotated transaction on suspending function detected: " + method +". Use TransactionalOperator.transactional extensions instead.");}ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());if (adapter == null) {throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +method.getReturnType());}return new ReactiveTransactionSupport(adapter);});return txSupport.invokeWithinTransaction(method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);}// 获取事务管理器PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception// 目标方法抛异常,会执行回滚的操作completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {cleanupTransactionInfo(txInfo);}if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...TransactionStatus status = txInfo.getTransactionStatus();if (status != null && txAttr != null) {retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}}// 目标方法正常运行,会执行commitTransactionAfterReturning,执行事务提交操作commitTransactionAfterReturning(txInfo);return retVal;}else {final ThrowableHolder throwableHolder = new ThrowableHolder();// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.try {Object result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);try {Object retVal = invocation.proceedWithInvocation();if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {// Set rollback-only in case of Vavr failure matching our rollback rules...retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);}return retVal;}catch (Throwable ex) {if (txAttr.rollbackOn(ex)) {// A RuntimeException: will lead to a rollback.if (ex instanceof RuntimeException) {throw (RuntimeException) ex;}else {throw new ThrowableHolderException(ex);}}else {// A normal return value: will lead to a commit.throwableHolder.throwable = ex;return null;}}finally {cleanupTransactionInfo(txInfo);}});// Check result state: It might indicate a Throwable to rethrow.if (throwableHolder.throwable != null) {throw throwableHolder.throwable;}return result;}catch (ThrowableHolderException ex) {throw ex.getCause();}catch (TransactionSystemException ex2) {if (throwableHolder.throwable != null) {logger.error("Application exception overridden by commit exception", throwableHolder.throwable);ex2.initApplicationException(throwableHolder.throwable);}throw ex2;}catch (Throwable ex2) {if (throwableHolder.throwable != null) {logger.error("Application exception overridden by commit exception", throwableHolder.throwable);}throw ex2;}}}

总结

总体来说,spring实现声明式事务的过程是这样的

  1. @EnableTransactionManagement 注解,通过@import引⼊了TransactionManagementConfigurationSelector类,它的selectImports⽅法导⼊了另外两个类:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
  2. AutoProxyRegistrar类中方法registerBeanDefinitions中,通过 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)引⼊InfrastructureAdvisorAutoProxyCreator,是一个后置处理器类
  3. ProxyTransactionManagementConfiguration 是⼀个添加了@Configuration注解的配置类,注册了事务增强器(注⼊属性解析器、事务拦截器)AnnotationTransactionAttributeSource和TransactionInterceptor,AnnotationTransactionAttributeSource内部持有了⼀个解析器集合 Set<TransactionAnnotationParser> annotationParsers,具体使⽤的是SpringTransactionAnnotationParser解析器,用来解析@Transactional的事务属性,事务拦截器TransactionInterceptor实现了MethodInterceptor接⼝,该通用拦截会在产⽣代理对象之前和aop增强合并,最终⼀起影响到代理对象,TransactionInterceptor的invoke⽅法中invokeWithinTransaction会触发原有业务逻辑调用(增强事务)

spring是如何实现声明式事务的相关推荐

  1. 【Spring】Spring第三天 - 声明式事务、常用注解、Ajax 复习

    一.自动注入 1.在Spring 配置文件中对象名和ref="id" . id 名相同,使用自动注入,可以不配置<property/> 2.两种配置办法 2.1 在&l ...

  2. 【Spring】spring基于注解的声明式事务控制

    结构 domin package com.itheima.domain;import java.io.Serializable;public class Account implements Seri ...

  3. 【spring】spring基于xml的声明式事务控制

    结构 domain package com.itheima.domain;import java.io.Serializable;public class Account implements Ser ...

  4. spring事物配置,声明式事务管理和基于@Transactional注解的使用

    事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的一致性. spring支持编程式事务管理和声明式事务管理两种方式. 编程式事务管理使用TransactionTemplate或 ...

  5. spring基于注解的声明式事务控制

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  6. spring基于XML的声明式事务控制-配置步骤

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  7. Spring基于 XML 的声明式事务控制(配置方式)

    一.引入依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http ...

  8. Spring Hibernate使用TransactionInterceptor声明式事务配置

    <!-- 事务管理器 -->  <bean id="transactionManager" class="org.springframework.orm ...

  9. Spring 详解(五):Spring声明式事务

    事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性.本文主要讲解事务涉及到一些概念以及spring中事务的使用. 1. 事务 数据库事务(Database Transaction) ...

最新文章

  1. 「云毕业照」刷爆朋友圈!AI人脸融合技术谁家强?
  2. 从MVC到云原生:CBU研发体系演进之路
  3. Elasticsearch Java 操作client
  4. 国家邮政局公布一项数据 春节期间快递数量依旧很猛!
  5. java activemq 断线_activemq 长时间没有消息client会断开吗?
  6. Unity NGUI中动态添加和删除sprite
  7. Ubuntu18.04取消VIM自动备份文件
  8. 《态度》- 吴军 四十封启明家书 读后感
  9. 用Camshift算法对指定目标进行跟踪
  10. JAVA实现UDP通信
  11. 概率论中几个入门公式
  12. 一文看雷击浪涌的防护解析
  13. 集线器、交换机、路由器功能原理入门总结
  14. 移植u-boot到stm32f407
  15. 移动端适配 - 小结
  16. 【Win 10应用开发】如何知道UAP在哪个平台上运行
  17. break语句和continue语句的区别
  18. Linux操作系统下/etc/hosts文件配置方法(域名映射)
  19. 【loj2639】[Tjoi2017]不勤劳的图书管理员
  20. 核心坚果计划互相监督跟踪平台 (New)

热门文章

  1. 保护你系统安全的影子系统
  2. 什么是点阵图 Bitmap ?
  3. 本周关注我们:节点,流星和网站性能
  4. 三万字加源码,教你从零开始学网页设计(HTML5+CSS)
  5. 实时同步刷新excel数据到数据库
  6. Arduino实验——GP2Y1014检测空气颗粒物浓度
  7. android 9.0谷歌商店,Android 10现可选择Play商店主题模式 附Android 9强制开启深色模式教程...
  8. php学习----php实现验证码
  9. TreeMap 底层原理
  10. 安卓3d游戏开发引擎_从德军总部3D到虚幻5,游戏引擎能有多大的飞跃?