Java Spring AOP源码解析之事务实现原理
作者:Java识堂 发布时间:2023-09-10 02:39:46
不用Spring管理事务?
让我们先来看一下不用spring管理事务时,各种框架是如何管理事务的
使用JDBC来管理事务
使用Hibernate来管理事务
业务逻辑和事务代码是耦合到一块的,并且和框架的具体api绑定了。当我们换一种框架来实现时,里面对事务控制的代码就要推倒重写,并不一定能保证替换后的api和之前的api有相同的行为。
基于这些问题,Spring抽象了一些事务相关的顶层接口,我们面向接口编程,换框架时只要换具体的实现即可。有点像JDBC API的味道了
常用api | 接口 |
---|---|
PlatformTransactionManager | 对事务进行管理 |
TransactionDefinition | 定义事务的相关属性,例如隔离级别,传播行为 |
TransactionStatus | 保存事务状态 |
针对不同的数据访问技术,使用不用的PlatformTransactionManager类即可
数据访问技术 | PlatformTransactionManager实现类 |
---|---|
JDBC/Mybatis | DataSourceTransactionManager |
Hibernate | HibernateTransactionManager |
Jpa | JpaTransactionManager |
Jms | JmsTransactionManager |
编程式事务管理
使用PlatformTransactionManager
使用TransactionTemplate
当我们直接使用PlatformTransactionManager来管理事务时,有很多模版代码。例如业务代码正常执行,提交事务,否则回滚事务。我们可以把这部分模版代码封装成一个模版类,这样使用起来就很方便了,如下所示
如下图所示,TransactionTemplate#execute方法就是一个典型的模版方法
我们可以传入如下2个接口的实现类来执行业务逻辑,TransactionCallback(需要返回执行结果)或TransactionCallbackWithoutResult(不需要返回结果)
声明式事务管理
为了让使用更加简洁,Spring直接把事务代码的执行放到切面中了,我们只需要在业务代码方法上加上一个@Transactional注解即可,这种方式我们最常用哈
使用@Transactional注解
此时事务相关的定义我们就可以通过@Transactional注解来设置了
属性名 | 类型 | 描述 | 默认值 |
---|---|---|---|
value(和transactionManager互为别名) | String | 当在配置文件中有多个PlatformTransactionManager ,用该属性指定选择哪个事务管理器 | 空字符串"" |
propagation | 枚举:Propagation | 事务的传播行为 | REQUIRED |
isolation | 枚举:Isolation | 事务的隔离度 | DEFAULT |
timeout | int | 事务的超时时间。如果超过该时间限制但事务还没有完成,则自动回滚事务 | -1 |
readOnly | boolean | 指定事务是否为只读事务 | false |
rollbackFor | Class[] | 需要回滚的异常 | 空数组{} |
rollbackForClassName | String[] | 需要回滚的异常类名 | 空数组{} |
noRollbackFor | Class[] | 不需要回滚的异常 | 空数组{} |
noRollbackForClassName | String[] | 不需要回滚的异常类名 | 空数组{} |
源码解析
我们需要在配置类上加上@EnableTransactionManagement注解,来开启spring事务管理功能,@EnableTransactionManagement最主要的功能就是注入一个TransactionInterceptor * ,来控制事务开启,提交或者回滚
ProxyTransactionManagementConfiguration
TransactionInterceptor#invoke
TransactionAspectSupport#invokeWithinTransaction
TransactionAspectSupport#createTransactionIfNecessary
当开启事务的时候,可以看到各种传播属性的行为
AbstractPlatformTransactionManager#getTransaction
Spring事务的传播行为在Propagation枚举类中定义了如下几种选择
支持当前事务
REQUIRED
:如果当前存在事务,则加入该事务。如果当前没有事务,则创建一个新的事务SUPPORTS
:如果当前存在事务,则加入该事务 。如果当前没有事务, 则以非事务的方式继续运行MANDATORY
:如果当前存在事务,则加入该事务 。如果当前没有事务,则抛出异常
不支持当前事务
REQUIRES_NEW
:创建一个新事务,如果当前存在事务,则把当前事务挂起NOT_SUPPORTED
: 以非事务方式运行,如果当前存在事务,则把当前事务挂起NEVER
: 以非事务方式运行,如果当前存在事务,则抛出异常
其他情况
NESTED
:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来执行 。如果当前没有事务,则该取值等价于REQUIRED
以NESTED启动的事务内嵌于外部事务中 (如果存在外部事务的话),此时内嵌事务并不是一个独立的事务,它依赖于外部事务。只有通过外部事务的提交,才能引起内部事务的提交,嵌套的子事务不能单独提交
参考博客
https://www.jb51.net/article/229456.htm
来源:https://blog.csdn.net/zzti_erlie/article/details/122276188


猜你喜欢
- 延伸:以后除了可以为实体类注入属性,还可以为配置类注入相关的配置信息1.编写实体类@Component@ConfigurationPrope
- 字符串的编码方式UTF-8是Unicode的一种实现方式,也就是它的字节结构有特殊要求,所以我们说一个汉字的范围是0X4E00到0x9FA5
- java 数据类型:在Java中,数据类型分为两大种:基本数据类型(值类型)和包装类型(引用数据类型)。基本数据类型不是对象,不能调用toS
- 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对,例如在数组{7,5,6,4}中,一共存在5对逆序对,分别是{
- C#编程中,调用封装dll中的函数是高频使用的。那么,如何在程序中加载dll并调用其中的函数呢?更进一步的,如何在主程序中对自己封装的dll
- 牛逼!IDEA不愧为神器,结合Groovy脚本,简直天下无敌,如今, 有许许多多的插件或者编辑器都支持根据数据表自动生成数据实体类了, 比如
- 昨天晚上写代码的时候偶然发现 DateTime 里出现了星期几,当时一阵凌乱,去网上百度没有详细解决办法,很多人说可以用用 ToString
- 1.with 函数首先先从with函数开始,with函数接受两个参数,第一个参数可以是一个任意类型的对象,第二个参数是一个Lambda表达式
- 一.hutool工具摘抄一段hutool工具的简介:Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,
- 本文实例讲述了java Swing组件setBounds()简单用法。分享给大家供大家参考,具体如下:先看API:public void s
- 移动端微信消息页实现在上一篇中主界面实现说过微信四个页面中间都是是fragment的,并且四个fragment的布局都还没实现,所以这一篇主
- 一、Spring Boot 、 Spring MVC 、Spring对比首先你需要明白一件事情:Spring Boot项目目的并不是替换Sp
- 1、Java主要特点简单性、跨平台性、分布性、安全性、健壮性、平 * 立与可移植性、多线程、动态性、面向对象的编程语言、支持垃圾自动收集处理等
- 一、什么是JWTJSON Web Token (JWT),它是目前最流行的跨域身份验证解决方案。现在的项目开发一般都是前端端分离,这就涉及到
- 介绍环境配置Jdk1.8 + Tomcat8.5 + mysql + Eclispe(IntelliJ IDEA,Eclispe,MyEcl
- 前提首先,我们肯定要在Application里面注册一个CrashHandler,监听应用crashpublic class TestApp
- 本文实例为大家分享了C#实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下之前一直想写一个贪吃蛇小游戏,上个周末终于有时间做了一个,现在和
- ClickHouse应用场景:1.绝大多数请求都是用于读访问的2.数据需要以大批次(大于1000行)进行更新,而不是单行更新;或者根本没有更
- mybatis的SqlSession一定要关闭今天在使用mybatis查询数据时,出现了一个很奇怪的问题。同一条sql语句,查询时快时慢,并
- 1、实现效果:项目的整体的日志打印级别为ERROR,但在某个包下或某个类想打印INFO级别的日志。2、配置:FILE是ERROR级别日志打印