企业网站建设包括,深圳市企业网络推广平台,网站平台代理,全国疫苗接种率前言
一般失效是使用了Transaction注解的情况下#xff0c;这篇博客就带你详解一下#xff0c;哪些情况下注解会失效#xff0c;在开发过程中要避免这些问题和可以及时发现这些问题#xff0c;并且知道如何去规避和解决 一、Spring事务的基本原理
在深入了解事务失效的场…前言
一般失效是使用了Transaction注解的情况下这篇博客就带你详解一下哪些情况下注解会失效在开发过程中要避免这些问题和可以及时发现这些问题并且知道如何去规避和解决 一、Spring事务的基本原理
在深入了解事务失效的场景之前我们先简单回顾一下Spring事务的工作原理
Spring通过AOP面向切面编程实现声明式事务在方法执行前开启事务执行后根据执行情况提交或回滚事务默认情况下Spring使用动态代理JDK动态代理SpringBoot2.x使用(CGLIB动态代理)来实现事务管理 关于什么是AOP什么是动态代理这篇博客可以带你深入理解 二、Spring事务失效的常见场景
2.1数据库引擎不支持事务
问题描述 如果使用MySQL且存储引擎是MyISAM由于MyISAM不支持事务所以Spring事务会失效。
解决方案
-- 查看表的存储引擎
SHOW CREATE TABLE table_name;-- 修改为支持事务的InnoDB引擎
ALTER TABLE table_name ENGINEInnoDB; 2.2类没有被Spring管理
问题描述 如果类没有加Service、Component等注解没有被Spring容器管理事务自然不会生效。
错误示例
// 没有Spring注解不会被Spring管理
public class UserService {Transactionalpublic void saveUser(User user) {// 事务不会生效}
}正确示例
Service // 加上Spring注解
public class UserService {Transactionalpublic void saveUser(User user) {// 事务正常工作}
}
2.3方法不是public的
问题描述 Transactional注解只能作用于public方法上如果方法是private、protected或默认访问级别事务将不会生效。
错误示例
Service
public class UserService {Transactionalprivate void saveUser(User user) { // private方法事务失效userDao.save(user);}
}正确示例
Service
public class UserService {Transactionalpublic void saveUser(User user) { // public方法事务生效userDao.save(user);}
} 2.4同一个类中方法调用自调用问题
问题描述 当同一个类中的一个方法调用另一个有事务的方法时事务会失效。这是因为Spring的事务是基于AOP代理实现的同一个类中的方法调用是通过this调用的不会经过代理。
错误示例
Service
public class UserService {public void saveUserWithoutTransaction(User user) {// 直接调用本类的事务方法事务不会生效this.saveUser(user);}Transactionalpublic void saveUser(User user) {userDao.save(user);}
}解决方案
方案1通过注入自身来调用
Service
public class UserService {Autowiredprivate UserService userService;public void saveUserWithoutTransaction(User user) {// 通过注入的代理对象调用userService.saveUser(user);}Transactionalpublic void saveUser(User user) {userDao.save(user);}
}2.5异常被catch没有抛出
问题描述 Spring事务默认只在遇到运行时异常RuntimeException和Error时才会回滚如果异常被catch且没有重新抛出事务不会回滚。
错误示例
Service
public class UserService {Transactionalpublic void saveUser(User user) {try {userDao.save(user);// 可能抛出异常的操作throw new RuntimeException(保存失败);} catch (Exception e) {// 异常被捕获没有重新抛出事务不会回滚log.error(保存用户失败, e);}}
}正确示例
Service
public class UserService {Transactionalpublic void saveUser(User user) {try {userDao.save(user);// 可能抛出异常的操作} catch (Exception e) {log.error(保存用户失败, e);// 重新抛出异常让事务回滚throw new RuntimeException(保存用户失败, e);}}
}
2.6抛出的异常类型不对
问题描述 默认情况下Spring只对RuntimeException和Error进行事务回滚对于受检异常checked exception不会回滚。
错误示例
Service
public class UserService {Transactionalpublic void saveUser(User user) throws Exception {userDao.save(user);// 抛出受检异常事务不会回滚throw new Exception(保存失败);}
}解决方案
方案1配置rollbackFor
Service
public class UserService {Transactional(rollbackFor Exception.class) // 指定所有异常都回滚public void saveUser(User user) throws Exception {userDao.save(user);throw new Exception(保存失败); // 现在会回滚}
}
2.7多线程调用
问题描述 Spring事务是基于ThreadLocal实现的不同线程之间的事务是独立的。在多线程环境下子线程的事务和主线程的事务是分离的。
错误示例
Service
public class UserService {Transactionalpublic void saveUsersAsync(ListUser users) {users.forEach(user - {// 新线程中执行不在当前事务中new Thread(() - {userDao.save(user); // 这个操作不在事务中}).start();});}
}解决方案
Service
public class UserService {Autowiredprivate TransactionTemplate transactionTemplate;public void saveUsersAsync(ListUser users) {users.forEach(user - {new Thread(() - {// 在新线程中手动管理事务transactionTemplate.execute(status - {try {userDao.save(user);return true;} catch (Exception e) {status.setRollbackOnly();return false;}});}).start();});}
} 三、总结
Spring事务失效的原因主要包括
环境问题数据库不支持事务、Spring配置错误代理问题自调用、非public方法异常处理问题异常被捕获、异常类型不匹配事务属性问题传播行为设置错误并发问题多线程环境下的事务隔离
在使用Spring事务时我们需要
理解Spring AOP的原理和限制正确配置事务管理器合理处理异常注意方法的访问级别和调用方式在多线程环境下特别小心