spring的事务:

事务:在逻辑上是一组操作,要么执行,要不都不执行

Spring 支持两种事务方式:编程式事务和声明式事务,后者最常见,通常情况下只需要一个 @Transactional 就搞定了

编程式事务:

指将事务管理代码嵌入到业务代码中,来控制事务的提交和回滚。

声明式事务

1.声明式事务将事务管理代码从业务方法中抽离了出来,以声明式的方式来实现事务管理(对于开发者来说,声明式事务显然比编程式事务更易用、更好用)
2.不过,要想实现事务管理和业务代码的抽离,就必须得用到 Spring 当中的AOP,其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,执行完目标方法之后根据执行的情况提交或者回滚

声明式事务虽然优于编程式事务,但也有不足,声明式事务管理的粒度是方法级别,而编程式事务是可以精确到代码块级别的。

事务传播行为:
当事务方法被另外一个事务方法调用时,必须指定事务应该如何传播,例如,方法可能继续在当前事务中执行,也可以开启一个新的事务,在自己的事务中执行。
声明式事务的传播行为可以通过 @Transactional 注解中的 propagation 属性来定义

Spring 事务传播机制可使用 @Transactional(propagation=Propagation.REQUIRED) 来定义,Spring 事务传播机制的级别包含以下 7 种:

Propagation.required:默认的事务传播行为;指的是如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务

更确切地意思是:
如果外部方法没有开启事务的话,Propagation.REQUIRED 修饰的内部方法会开启自己的事务,且开启的事务相互独立,互不干扰。
如果外部方法开启事务并且是 Propagation.REQUIRED 的话,所有 Propagation.REQUIRED 修饰的内部方法和外部方法均属于同一事务 ,只要一个方法回滚,整个事务都需要回滚。
也就是说如果a方法和b方法都添加了注解,在默认传播模式下,a方法内部调用b方法,会把两个方法的事务合并为一个事务。

Propagation.requires_new:

表示创建一个新的事务,如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰

Propagation.supports:

如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行

Propagation.not_supported:

以非事务方式运行,如果当前存在事务,则把当前事务挂起。

Propagation.mandatory(mandatory:强制性):

如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

Propagation.never:

以非事务方式运行,如果当前存在事务,则抛出异常。

Propagation.nested(nested:嵌套):

如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,就执行与Propagation.required类似的操作。

事务隔离级别

TransactionDefinition 中一共定义了 5 种事务隔离级别:

1.isolation_default:使用数据库默认的隔离级别,MySql 默认采用的是可重复读
2.isolation_read_uncommitted:允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
3.isolation_read_committed :允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生
4.isolation_repeatable_read:对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改,可防止脏读和不可重复读,但幻读仍有可能发生
5.isolation_serializable:确保不发生脏读、不可重复读、和幻读,但执行效率最低。

通常情况下,我们采用默认的隔离级别 ISOLATION_DEFAULT 就可以了,也就是交给数据库来决定。

@Transaction失效场景

1.作用于非public方法上
2.方法用final修饰,不会生效:因为spring事务底层使用了aop,也就是通过jdk动态代理,帮我们生成了代理类,在代理类中实现的事务功能。但如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法,而添加事务功能
3.未开启事务