基础概念
从本质上讲,Spring事务是对数据库事务的进一步封装。也就是说,如果数据库不支持事务,Spring也无法实现事务操作
默认情况下,在方法抛出RuntimeException时回滚事务,也可以手动指定回滚事务的异常类型,如果你try 后不往外抛
事务分类
Spring事务分类通过Spring管理的事务可以分为逻辑事务和物理事务两大类。
1)逻辑事务:通常指通过Spring等框架管理的事务,这种事务是建立在物理事务之上的,比物理事务更加抽象。
2)物理事务:通常指的是针对特定数据库的事务。
Spring支持两种事务声明方式,分别是编程式事务和声明式事务。
1)编程式事务:如果系统需要明确的事务,并且需要细粒度的控制各个事务的边界,此时建议使用编程式事务。
2)声明式事务:如果系统对于事务的控制粒度较为粗糙,则建议使用声明式事务。
Spring事务三大接口
Spring事务的三大接口:PlatformTransaction-Manager、TransactionDefinition和TransactionStatus。
PlatformTransactionManager接口
TransactionDefinition接口位于Spring的org.springframework.transaction包下,主要定义了与事务相关的方法,表示事务属性的常量等信息
TransactionStatus接口主要用来存储事务执行的状态,并且定义了一组方法,用来判断或者读取事务的状态信息。
Spring事务隔离级别
Spring中存在5种隔离级别,分别为ISOLATION_DEFAULT、ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE
ISOLATION_DEFAULT
Spring中PlatformTransactionManager默认的事务隔离级别
ISOLATION_READ_UNCOMMITTED
Spring中最低的隔离级别。当Spring中的隔离级别设置为ISOLATION_READ_UNCOMMITTED时,事务A能够读取到事务B未提交的数据。这种隔离级别下会产生脏读、不可重复读和幻读的问题。相当于MySQL中的未提交读隔离级别
ISOLATION_READ_COMMITTED
ISOLATION_READ_COMMITTED隔离级别能够保证事务A修改的数据提交之后才能被事务B读取,事务B不能读取事务A未提交的数据
ISOLATION_REPEATABLE_READ
能够保证不会产生脏读和不可重复读的问题,但是可能会产生幻读的问题
ISOLATION_SERIALIZABLE
事务只能够按照特定的顺序执行,也就是多个事务之间只能够按照串行化的顺序执行
Spring事务传播机制
主要定义了7种类型,分别是REQUIRED、SUPPORTS、MAND-ATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED
REQUIRED事务传播类型表示如果当前没有事务,就创建一个事务,如果已经存在一个事务,就加入这个事务。
REQUIRES_NEW事务传播类型表示如果当前存在事务,则把当前事务挂起,并重新创建新的事务并执行,直到新的事务提交或者回滚,才会恢复执行原来的事务。具备隔离性
- 外部事务执行失败后回滚,不会回滚内部事务的执行结果。
- 内部事务执行失败回滚抛出异常,被外部事务捕获到时,外部事务可以不处理内部事务的回滚操作
SUPPORTS事务传播类型表示支持当前事务,如果当前没有事务,就以非事务的方式执行。
MANDATORY事务传播类型表示支持当前事务,这种事务传播类型具备强制性,当前操作必须存在事务,如果不存在,则抛出异常。
NOT_SUPPORTED事务传播类型表示以非事务方式执行,如果当前操作在一个事务中,则把当前事务挂起,直到当前操作完成再恢复事务的执行。如果当前操作存在事务,则把事务挂起,以非事务的方式运行。
- 内部事务执行失败不回滚,外部事务可以不处理内部事务的回滚操作,看你捕不捕获
NEVER事务传播类型表示以非事务的方式执行,如果当前操作存在事务,则抛出异常。
NESTED事务传播类型表示如果当前方法有一个事务正在运行,则这个方法应该运行在一个嵌套事务中,被嵌套的事务可以独立于被封装的事务进行提交或者回滚。
- 如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚。
- 如果内层事务回滚,则并不影响外层事务的提交和回滚。
- 如果封装事务不存在,则按照REQUIRED事务传播类型执行
日常工作中经常使用的只有REQU-IRED、NOT_SUPPORTED和REQUIRES_NEW这3种
Spring事务失效的场景
- 数据库不支持事务
- 事务方法未被Spring管理
- 方法没有被public修饰
- 同一类中的方法调用
- 未配置事务管理器
- 方法的事务传播类型不支持事务
- 不正确地捕获异常
- 标注错误的异常类型