新来的实习生找我吐槽,在开发过程中,经常遇到事务失效的问题,了不起实在看不下去了,整理了一份事务失效的N种情况,让他学习学习。
在MySQL5.5版本之前,默认的引擎是MyISAM,MyISAM引擎是不支持事务的。从MySQL5.5版本开始,默认引擎是InnoDB,InnoDB完全支持ACID原则和事务。所以当事务失效时,可以手动查询下当前数据库的存储引擎,具体的SQL语句如下:
SHOW VARIABLES LIKE 'default_storage_engine%';
// @Service
public class UserServiceImpl implements UserService {
@Transactional
public void saveUser(User user){
// do something...
}
}
对于上面的例子,类没有被@Service注解修饰,意味着当前类没有被Spring管理,事务自然就失效了。
@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)进行修饰。
好啦,以上就是事务失效的几种常见的场景,不知道小伙伴们搞明白没有?在日常开发的过程中需要注意哦!