Spring事务失效的几种场景及事务是如何实现的
Spring事务失效的几种场景
1、没有被Spring管理
不是被Spring管理的Bean中的方法,@Transactional不会生效
2、Transactional修饰的方法不是public的
如果必须用在public方法上,需要开启AspectJ代理模式
3、自身调用的问题
类调用了该类自己的方法,而没有经过Spring的代理类,默认只有在外部调用事务才会生效。
public void aMethod(Order o){ update(o); } @Transactional public void update(Order o){ //省略 }
此处调用aMethod,事务不会生效;
4、数据源没有配置事务管理器,下面是配置事务管理器的代码
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
5、异常被try-catch了,事务不回滚
6、异常不是RuntimeException,事务默认回滚的是运行时异常,其他异常需要添加rollbackFor配置;
@Transactionan(rollbackFor = Exception.class)
7、数据库引擎不支持事务,MySQL5.5.5之前默认的是MyISAM引擎,不支持事务;事务的原理是通过aop,在开始前设置autocommit为false,禁止自动提交,来实现的。
事务是如何实现的
1、Spring事务底层是基于数据库事务和AOP机制的;
2、首先对于使用了@Transactional注解的Bean,Spring会创建一个代理对象作为Bean;
3、当调用代理对象的方法时,会先判断该方法上是否加了@Transactional注解,如果加了,那么利用事务管理器创建一个数据库连接,并且修改数据库连接的autocommit属性为false,禁止此连接的自动提交;
4、然后执行当前方法,方法中会执行sql,执行完方法后,如果没有出现异常就直接提交事务;
5、如果出现了异常,并且这个异常时需要回滚的,就会回滚事务,否则事务任然提交;
6、Spring事务的隔离级别对应的就是数据库的隔离级别,Spring事务的传播机制是Spring自己实现的,一个数据库连接一个事务;如果传播机制配置为需要新开一个事务,那么实际上就是先建立一个数据库连接,在此新数据库连接上执行sql;
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的方法只有被代理对象调用时,这个注解才会生效;底层cglib是基于父子类来实现的,子类不能重载父类的private方法,所以private修饰的方法会导致事务失效;