1 概述
Spring事务 的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。以JDBC为例,其通过事务操作数据库记录步骤如下:
- 获取连接:Connection con = DriverManager.getConnection();
- 开启事务:con.setAutoCommit(false);
- 执行SQL:CRUD等;
- 提交事务/回滚事务:con.commit() / con.rollback();
- 关闭连接:conn.close();
spring框架本身依赖的还是这些底层提供的能力,只不过spring对这一过程进行了抽象和封装,使开发者不不必使用这么复杂而原始的方式去操作数据库事务。其他经常使用的数据访问技术(如JPA、mybatis,hibernate等)都有事务处理机制,他们也提供了用来开启事务、提交/回滚事务的相关API。当前所有的数据访问技术都能够很友好的和Spring进行集成,Spring统一处理不同数据访问技术的事务处理。在Spring中提供了一个叫做PlatformTransactionManager接口(相当于spring提供了一套事务操作的规范,不同的数据库访问技术进行实现),不同的数据访问技术都会对该接口进行实现,如表所示:
数据库访问技术 | JDBC | JPA | Hibernate |
实现类 | DataSourceTransactionManager | JpaTransactionManager | HibernateTransactionManager |
2 spring事务的传播特性定义
当多个事务同时存在时,spring应对策略。spring的传播特性如下:
传播特性 | 解释 |
| 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。 |
| 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
| 支持当前事务,如果当前没有事务,就抛出异常。 |
| 新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作 |
| 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
| 以非事务方式执行,如果当前存在事务,则抛出异常。 |
| 如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。 |
3 数据库事务隔离级别&spring事务隔离级别
隔离级别 | 描述 |
读未提交(Read-Uncommitted) | 会存在脏读,会读到其他事务未提交的数据,如果其他数据最终回滚,则读到的数据是脏数据。 |
读已提交(Read-Committed) | 避免了脏读,存在不可重复读和幻读。 1. 不可重复读:如果在一个事务中有两次或多次多操作,在这些读取操作之间,另一个事务对数据进行了修改,这时候读取的数据是不一致的。 2. 幻读:一个事务对一定范围的数据进行批量修改,另一个事务在这个范围增加一条数据,此时该事务就会丢失对新增数据的修改。 |
可重复读(Repeatable-Read) | 避免了脏读、不可重复读,但是存在幻读 |
序列化(Serializable) | 串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重 |
spring事务隔离级别在数据库隔离级别基础上新增了一个默认隔离级别,这个级别跟数据库的默认隔离级别保持一致,其余的隔离级别跟数据库隔离级别保一致。
4 spring的两种事务管理
4.1 编程式事务管理
spring 实现编程式事务主要依赖两个类:PlatformTransactionManager和TransactionTemplate,官方推荐使用TransactionTemplate。
4.2 声明式事务管理
声明式事务实现方式主要有2种,一种为通过使用Spring的<tx:advice>定义事务通知与AOP相关配置实现,另为一种通过@Transactional实现事务管理实现。spring声明式事务实现是通过AOP来实现的。
使用@Transactional注意点:
如果在接口、实现类或方法上都指定了@Transactional 注解,则优先级顺序为方法>实现类>接口。
建议只在实现类或实现类的方法上使用@Transactional,而不要在接口上使用,这是因为如果使用JDK代理机制(基于接口的代理)是没问题;而使用使用CGLIB代理(继承)机制时就会遇到问题,因为其使用基于类的代理而不是接口,这是因为接口上的@Transactional注解是“不能继承的”。
参考资料:
https://baijiahao.baidu.com/s?id=1665817944004197918&wfr=spider&for=pc
https://baijiahao.baidu.com/s?id=1677407386011788448&wfr=spider&for=pc
https://www.cnblogs.com/wangyayun/p/6530189.html
https://blog.csdn.net/weixin_44366439/article/details/89030080 源码分析