1. 没有使用代理
场景: 如果你在一个类内部调用同一个类中的另一个方法,Spring 事务管理无法生效。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 当在 controller 调用 executeTask 时事务会失效
* 1,因为标注了 @Transaction 注解,spring 会为 MyService 创建一个代理对象
* 2,controller 调用 executeTask 方法时,调用的是真实对象的方法,因为这个方法没有标注事务注解
* 3,executeTask 再调用 performTask 时,其实是 this.performTask,这里的 this 是普通对象,而不是代理对象
*/
@Service
public class MyService {
@Transactional
public void performTask() {
// 模拟数据库操作
System.out.println("Performing task...");
// 这里可以添加更多数据库操作代码
// 例如:userRepository.save(new User());
}
public void executeTask() {
performTask(); // 直接调用同一类中的方法
}
}
原因: 这是因为 Spring 事务管理是基于代理的。当你在一个类中调用另一个方法时,实际上是在同一个对象的上下文中执行的,这样事务注解不会被代理拦截,导致事务失效。
解决方法: 1,将方法提取到不同的类中,2,在同一个类中使用 self
注入。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class MyService {
@Autowired
private MyService self; // 自我注入
@Transactional
public void performTask() {
System.out.println("Performing task...");
// 数据库操作
}
public void executeTask() {
self.performTask(); // 使用自我注入调用,因为此时 self 已经是代理对象了,所以会走 AOP 的通知
}
}
2. 非运行时异常
场景: Spring 默认只对运行时异常(RuntimeException
)进行回滚,如果抛出的是检查性异常(如 IOException
),则不会回滚事务。
@Transactional
public void test(){
userDao.save(user);
new File("D:\\不存在的文件.jpg")
}
原因: 这是 Spring 事务管理的默认行为,非运行时异常不会触发事务回滚。
解决方法: 可以在 @Transactional
注解中指定回滚的异常类型,例如:
@Transactional(rollbackFor = Exception.class)
public void test(){
userDao.save(user);
new File("D:\\不存在的文件.jpg")
}
3. 事务传播行为设置不当
场景: 在多个事务之间的交互时,传播行为设置不当可能导致事务失效。
// 订单 service
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
@Transactional
public void createOrder() {
// 订单创建逻辑
System.out.println("Creating order...");
// 调用 PaymentService 处理支付
paymentService.processPayment();
// 其他订单处理逻辑
}
}
// 支付 service
@Service
public class PaymentService {
// 这个方法使用的是 REQUIRES_NEW,会新开一个事务,出现异常只是当前事务会回滚,不会影响上层的事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void processPayment() {
// 支付处理逻辑
System.out.println("Processing payment...");
// 模拟异常
if (true) {
throw new RuntimeException("Payment failed!");
}
}
}
4. 隔离级别不合适
场景: 在高并发情况下,使用不合适的隔离级别可能导致事务表现不符合预期。
# 1,假设隔离级别是读未提交
# 2,A 事务先新增一条数据
# 3,此时 B 事务读到这条数据了,做业务的途中发生异常,要回滚数据(将要回滚还没有回滚的时候,A RollBack 了)
# 4,B 事务咋回滚,要回滚的数据都没了
5. Spring Boot 和 Spring 版本不兼容
场景: 在使用 Spring Boot 的时候,某些 Spring 版本之间可能存在兼容性问题。
原因: 在不同版本的 Spring 或 Spring Boot 中,事务管理的实现可能会有所不同。
解决方法: 确保使用兼容的 Spring 和 Spring Boot 版本,并查阅相应的文档。
标签:回滚,场景,Spring,Transactional,事务,void,失效,public From: https://www.cnblogs.com/cyrushuang/p/18487998