Spring常见的事务失效原因

一、实现原理

Spring事务的实现原理是动态代理,当调用添加@Transactional注解的方法时,代理对象会先开启事务,再调用方法,最后再提交/回滚事务。

二、常见的事务失效原因

1.修饰方法为非public

Spring事务的动态代理只会对public方法生效(jdk代理只对public方法生效,cglib代理虽然可以代理非public方法,但是在Spring中做了限制,只对public方法进行事务代理)

示例:

java 复制代码
@Service
public class UserService {
    // private修饰 → 事务失效
    @Transactional
    private void updateUserName(Long id, String name) {
        userMapper.updateName(id, name);
    }
}

2.内部方法直接调用

如果通过一个普通方法直接调用添加@Transactional的方法则会导致不走代理对象,那么也不会实现事务管理。

示例:

java 复制代码
@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    // 普通方法(无事务)
    public void updateUserInfo(Long id, String name) {
        // 内部调用事务方法,不走代理 → 事务失效
        this.updateUserName(id, name); 
    }

    // 事务方法
    @Transactional
    public void updateUserName(Long id, String name) {
        userMapper.updateName(id, name);
        int i = 1 / 0; // 异常,但事务不会回滚
    }
}

3.异常类型不匹配

Spring事务只会对RuntimException和Error异常进行回滚,对检查型异常则不会触发事务回滚。

解决方法:

1.扩大异常捕获范围

java 复制代码
//捕获所有类型异常回滚

@Transactional(rollbackFor = Exception.class)

//或指定具体异常
@Transactional(rollbackFor = SQLException.class)

2.将检查型异常包装成运行时异常

java 复制代码
throw new RuntimeException(new SQLException("数据库异常"));

4.手动捕获异常且未手动回滚

手动捕获异常后,Spring无法感知到异常

java 复制代码
@Transactional
public void updateUserName(Long id, String name) {
    try {
        userMapper.updateName(id, name);
        int i = 1 / 0; // 抛出运行时异常
    } catch (Exception e) {
        // 捕获异常但未处理 → 事务提交,数据不会回滚
        log.error("更新失败", e);
    }
}

解决方法

1.在catch中触发手动回滚

java 复制代码
 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

2。显示的抛出运行时异常

java 复制代码
throw new RuntimeException(e);
相关推荐
WeiXin_DZbishe10 分钟前
基于springboot装修风格选择系统的设计与开发-计算机毕设【课程设计】77964
java·vue.js·spring boot·后端·python·php·课程设计
XZ-07000116 分钟前
week9-三元表达式
java·前端·python
摇滚侠17 分钟前
《大模型应用开发实践:基于 Spring AI+DeepSeek 实现》第 11 章 大模型技术概览 阅读笔记 1
人工智能·笔记·spring
编程火箭车25 分钟前
MySQL 拥抱 AI:向量、RAG、AutoML 全进了数据库
数据库·mysql·ai编程·向量数据库·rag·automl·mysql9
云和数据.ChenGuang25 分钟前
name=“张三“ age=18 weight=100.3 print (name,age,weight)
java·服务器·前端
Yeswater44 分钟前
从 NIO 到 Netty:五个坑,和一张把它填平的基础设施网
java·后端·netty
denlaku1 小时前
JDK 15 新特性详解
java·开发语言
用户8662978480081 小时前
KingbaseES 中文乱码、排序不对?区域和字符集的问题,一次说清
数据库
荣码1 小时前
LangSmith可观测性:AI应用出bug根本不知道哪里出了问题,我踩了4个坑
java·python
aruo1 小时前
回退旧镜像之前,先确认数据库还能兼容
数据库