前言
新来的实习生找我吐槽,在开发过程中,经常遇到事务失效的问题,了不起实在看不下去了,整理了一份事务失效的N种情况,让他学习学习。
大纲
数据库引擎不支持事务
在MySQL5.5版本之前,默认的引擎是MyISAM,MyISAM引擎是不支持事务的。从MySQL5.5版本开始,默认引擎是InnoDB,InnoDB完全支持ACID原则和事务。所以当事务失效时,可以手动查询下当前数据库的存储引擎,具体的SQL语句如下:
SHOW VARIABLES LIKE 'default_storage_engine%';
类没有被Spring管理
// @Service public class UserServiceImpl implements UserService { @Transactional public void saveUser(User user){ // do something... } }
对于上面的例子,类没有被@Service注解修饰,意味着当前类没有被Spring管理,事务自然就失效了。
方法的访问修饰符不是public
@Service public class UserServiceImpl implements UserService { @Transactional protected void saveUser(User user){ // do something... } }
@Transactional注解只有修饰public方法时,事务才会生效,如果用在非public方法上,如protected、private,事务将失效。
自身调用问题
@Service public class UserServiceImpl implements UserService { @Transactional public void saveUser(User user){ // do something... updateUser(user); } @Transactional public void updateUser(User user){ // do something... } }
由于类发生了自身调用,即在saveUser方法中,使用了this.updateUser()进行方法调用,没有经过Spring的代理类,默认只有在外部调用事务方法时才生效。若程序存在自身调用且需要事务生效,可以通过获取代理类的方法进行调用,示例代码如下:
@Service public class UserServiceImpl implements UserService { @Transactional public void saveUser(User user){ // do something... ((UserService)AopContext.currentProxy()).updateUser(user); } @Transactional public void updateUser(User user){ // do something... } }
数据源没有配置事务管理器
数据源没有配置事务管理器时,事务将不生效,可通过以下方法进行配置。
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
不支持事务
@Service public class UserServiceImpl implements UserService { @Transactional public void saveUser(User user){ // do something... ((UserService)AopContext.currentProxy()).updateUser(user); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void updateUser(User user){ // do something... } }
当@Transactional注解使用了错误的传播机制,会导致事务失效。Propagation.NOT_SUPPORTED表示不以事务运行,当前若存在事务时则挂起。
异常被捕获
@Service public class UserServiceImpl implements UserService { @Transactional public void saveUser(User user){ try { // do something... int i = 1/0; } catch (Exception e){ e.printStackTrace(); } } }
当出现除0异常时,异常被catch捕获了,整个程序正常运行,没有抛出异常,最终导致事务无法回滚。
异常类型错误
@Service public class UserServiceImpl implements UserService { @Transactional public void saveUser(User user){ throw new Exception("save user error"); } }
@Transactional注解中,回滚的默认异常是RuntimeException,由于在saveUser()方法中抛出异常不是RuntimeException,导致当前事务不会回滚。若要使事务生效,建议使用@Transactional(rollbackFor = Exception.class)进行修饰。
总结
好啦,以上就是事务失效的几种常见的场景,不知道小伙伴们搞明白没有?在日常开发的过程中需要注意哦!