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);
相关推荐
今晚务必早点睡10 小时前
微服务改数据库密码后服务仍能访问?一次“看似异常、实则常见”的生产现象全解析
数据库·微服务·oracle
老师我太想进步了202612 小时前
cmd连接MySQL及相关查询
数据库·mysql
kk哥889912 小时前
如何快速掌握JavaSE的核心语法?
java
我是一只小青蛙88812 小时前
AVL树:平衡二叉搜索树原理与C++实战
java·jvm·面试
浩瀚地学12 小时前
【Java】JDK8的一些新特性
java·开发语言·经验分享·笔记·学习
XXOOXRT13 小时前
基于SpringBoot的加法计算器
java·spring boot·后端·html5
阿崽meitoufa13 小时前
JVM虚拟机:垃圾收集器和判断对象是否存活的算法
java·jvm·算法
我是苏苏14 小时前
C#高级:使用ConcurrentQueue做一个简易进程内通信的消息队列
java·windows·c#
難釋懷14 小时前
Redis命令-Set命令
数据库·redis·缓存