1、相关根本知识

1.1业务的传播办法

//假如有业务, 那么加入业务, 没有的话新建一个(默许)
@Transactional(propagation=Propagation.REQUIRED)
//容器不为这个办法开启业务 
@Transactional(propagation=Propagation.NOT_SUPPORTED)
//不论是否存在业务, 都创立一个新的业务, 原来的挂起, 新的履行结束, 继续履行老的业务 
@Transactional(propagation=Propagation.REQUIRES_NEW) 
//必须在一个已有的业务中履行, 不然抛出反常
@Transactional(propagation=Propagation.MANDATORY) 
//必须在一个没有的业务中履行, 不然抛出反常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.NEVER) 
//假如其他bean调用这个办法, 在其他bean中声明业务, 那就用业务, 假如其他bean没有声明业务, 那就不用业务
@Transactional(propagation=Propagation.SUPPORTS) 

1.2业务的阻隔等级

// 读取未提交数据(会呈现脏读, 不可重复读) 根本不运用
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
// 读取已提交数据(会呈现不可重复读和幻读) Oracle默许
@Transactional(isolation = Isolation.READ_COMMITTED)
// 可重复读(会呈现幻读) MySQL默许
@Transactional(isolation = Isolation.REPEATABLE_READ)
// 串行化
@Transactional(isolation = Isolation.SERIALIZABLE)

ISOLATION_DEFAULT: 运用后端数据库默许的阻隔等级,Mysql 默许采用的 REPEATABLE_READ阻隔等级 Oracle 默许采用的 READ_COMMITTED阻隔等级.

ISOLATION_READ_UNCOMMITTED: 最低的阻隔等级,答应读取没有提交的数据变更,可能会导致脏读、幻读或不可重复读

ISOLATION_READ_COMMITTED: 答应读取并发业务现已提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生

ISOLATION_REPEATABLE_READ: 对同一字段的多次读取成果都是共同的,除非数据是被本身业务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

ISOLATION_SERIALIZABLE: 最高的阻隔等级,彻底服从ACID的阻隔等级。所有的业务顺次逐个履行,这样业务之间就彻底不可能产生干扰,也就是说,该等级可以避免脏读、不可重复读以及幻读。但是这将严重影响程序的性能。一般情况下也不会用到该等级。

1.3其他属性

事务注解@Transactional又失效了!

  • timeout 业务的超时时刻,默许值为 -1。假如超过该时刻限制但业务还没有完成,则自动回滚业务。
  • readOnly 指定业务是否为只读业务,默许值为 false;为了疏忽那些不需要业务的办法,比方读取数据,可以设置 read-only 为 true。
  • rollbackFor 用于指定可以触发业务回滚的反常类型,可以指定多个反常类型。
  • noRollbackFor 抛出指定的反常类型,不回滚业务,也可以指定多个反常类型。

2、业务失效场景

2.1未被Spring办理

业务办法所在类并没有被Spring办理,则Spring业务会失效。这种关于Springboot项目其实不会的,你把@Service注释掉,Controller中注入UserService是会报错的。

事务注解@Transactional又失效了!

2.2办法不能被重写

这儿的意思是带@Transactional注释的办法必须是可重写的,那咱们知道private、static、final润饰的办法均不能被重写。

事务注解@Transactional又失效了!

2.3同一个类中办法相互调用

这儿咱们在同一个类中办法A调用了办法B,在办法B上运用@Transactional,此时办法B中呈现反常,咱们是希望他能回滚的。

事务注解@Transactional又失效了!

惋惜并没有回滚业务

事务注解@Transactional又失效了!

声明式业务完成原理是面向切面编程,通过cglib创立署理proxy,当咱们拜访带 @Transactional办法,假如通过spring容器获取bean,实际拜访的是署理目标,署理目标现已在带 @Transactional办法前后增加了业务相关的逻辑。而当调用带 @Transactional办法的调用方是同类办法时,调用的是this目标的办法,没有通过spring容器获取bean,就无法拜访到署理目标,业务也就没有生效。

咱们把@Transactional注解放到办法A上就可以了。此时即使办法B是private润饰的也无所谓

事务注解@Transactional又失效了!

2.4反常被catch了

根据2.3的比方,假如把办法B中的反常catch了却没有抛出反常,业务也是不会回滚的。

事务注解@Transactional又失效了!

解决办法:一般咱们会在Springboot项目中自定义一个反常,在catch句子块中抛出自定义反常即可。

2.5rollbackFor运用不当

rollbackFor默许值为UncheckedException,包含了RuntimeException和Error。

在运用@Transactional注解时不指定rollbackFor,Exception及其子类都不会触发回滚。

事务注解@Transactional又失效了!

承继自Runtime Exception或 Error 的是非查看型反常,而承继自 Exception 的则是查看型反常。

2.6数据库引擎不支持业务

比方MySQL数据库选用MyISAM存储引擎,而MyISAM存储引擎本身不支持业务,业务必定不会生效。

2.7多线程问题

假如你去面试,面试官问你多线程业务如何回滚,你要是答复用@Transactional注解,就可以直接回去了。Spring的业务是通过ThreadLocal来保证线程安全的,业务和当时线程绑定。