一、传播特性
@Transactional(propagation=Propagation.REQUIRED)
:如果外层调用方法本身有事务, 那么就加入到该事务中, 没有的话新建一个(这是默认的设置项)@Transactional(propagation=Propagation.NOT_SUPPORTED)
:以非事务方式运行,如果外层调用方法存在事务,则把当这个事务挂起。@Transactional(propagation=Propagation.REQUIRES_NEW)
:不管外层调用方法否存在事务,都创建一个自己的事务,外层调用方法的事务挂起,自己的执行完毕,再执行调用方事务@Transactional(propagation=Propagation.MANDATORY)
:如果外层调用方法存在事务,则加入该事务;如果外层调用方法没有事务,则抛出异常@Transactional(propagation=Propagation.NEVER)
:以非事务方式运行,如果外层调用方法存在事务,则抛出异常。@Transactional(propagation=Propagation.SUPPORTS)
:如果外层调用方法存在事务,则加入该事务;如果外层调用方法没有事务,则以非事务的方式继续运行。@Transactional(propagation=Propagation.NESTED)
:如果外层调用方法存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果外层调用方法没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
二、事务失效的可能原因
2.1、访问权限
Spring的事务代理通常是通过Java动态代理或CGLIB动态代理生成的,这些代理要求目标方法是公开可访问的(public)。私有方法无法被代理,因此事务将无效。将方法改成public或protected即可(idea有报错提醒)。
2.2、目标类没有被spring管理
Spring的事务管理需要在Spring容器中配置的Bean上才能生效。如果目标类没有被spring管理,那么事务将无法被应用。
2.3、方法内部调用
事务管理是基于动态代理对象的代理逻辑实现的,那么如果在类内部调用类内部的事务方法,这个调用事务方法的过程并不是通过代理对象来调用的,而是直接通过this对象来调用方法,绕过的代理对象,肯定就是没有代理逻辑了。
@Component
public class TestService {
@Resource
TestMapper testMapper;
@Transactional
public void test1() {
int re = testMapper.insert(new Test(10,20,30));
if (re > 0) {
throw new NeedToInterceptException("need intercept");
}
testMapper.insert(new Test(210,20,30));
}
public void test2(){
//内部调用事务方法
test1();
}
}
2.4、多线程调用
事务信息是跟线程绑定的。因此在多线程环境下,事务的信息都是独立的,将会导致Spring在接管事务上出现差异。
2.4、数据库不支持事务
这种情况出现的概率并不高,事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了
2.5、传播特性错误
事务传播属性定义了事务如何传播到嵌套方法或外部方法。如果事务传播属性设置不正确,可能会导致事务失效或不符合预期的行为,以下是传播特性
@Transactional(propagation=Propagation.REQUIRED)
:如果外层调用方法本身有事务, 那么就加入到该事务中, 没有的话新建一个(这是默认的设置项)@Transactional(propagation=Propagation.NOT_SUPPORTED)
:以非事务方式运行,如果外层调用方法存在事务,则把当这个事务挂起。@Transactional(propagation=Propagation.REQUIRES_NEW)
:不管外层调用方法否存在事务,都创建一个自己的事务,外层调用方法的事务挂起,自己的执行完毕,再执行调用方事务@Transactional(propagation=Propagation.MANDATORY)
:如果外层调用方法存在事务,则加入该事务;如果外层调用方法没有事务,则抛出异常@Transactional(propagation=Propagation.NEVER)
:以非事务方式运行,如果外层调用方法存在事务,则抛出异常。@Transactional(propagation=Propagation.SUPPORTS)
:如果外层调用方法存在事务,则加入该事务;如果外层调用方法没有事务,则以非事务的方式继续运行。@Transactional(propagation=Propagation.NESTED)
:如果外层调用方法存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果外层调用方法没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED
2.6、自己捕获异常
在代码中手动try…catch了异常
2.7、final或者static修饰
spring事务的源码,事务底层使用了aop,也就是通过jdk动态代理或者cglib,生成了代理类,在代理类中实现的事务功能。但如果某个方法用final修饰了,那么在它的代理类中,就无法重写该方法,而添加事务功能。
2.8、未开启事务
sspringboot通过DataSourceTransactionManagerAutoConfiguration类,已经默认开启了事务。
传统的spring项目,则需要在applicationContext.xml文件中,手动配置事务相关参数。