遇到Spring事务失效,你该怎么办?

Spring 事务场景失效是一个常见的问题。今天来分析这个问题。

在这里插入图片描述

1、事务方法被final、static关键字修饰,方法访问权限不是public

@Service
public class UserService {
    
    @Autowired
    private UserDao userDao;

    // final修饰的事务方法
    @Transactional
    public final void addUser(User user) {
        userDao.addUser(user);
    }

    // 访问权限不是public的事务方法
    @Transactional
    protected void updateUser(User user) {
        userDao.updateUser(user);
    }

    // 静态方法的事务方法
    @Transactional
    public static void deleteUser(int userId) {
        userDao.deleteUser(userId);
    }
}

失效原因

  1. 事务方法被final、static关键字修饰:这是因为Spring事务的实现依赖于AOP技术,而final、static方法无法被代理,因此在这些方法中调用事务方法,事务无法生效。
  2. 方法访问权限不是public:Spring事务的实现也是基于AOP的,所以在非public的方法中调用事务方法,无法触发AOP代理,因此事务不会生效。

2、同一个类中,方法内部调用

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    @Transactional
    public void addUser(User user) {
        // 事务方法内部调用了updateUser方法,事务失效
        updateUser(user);
    }

    public void updateUser(User user) {
        userDao.updateUser(user);
    }
}

失效原因
在同一个类中,事务方法内部调用其他方法时,可能会导致事务失效。这是因为Spring的事务是基于AOP(面向切面编程)实现的,在同一个类中的方法内部调用其他方法时,实际上是调用的类的内部方法,而不是通过代理调用方法,从而导致事务无法生效。

3、事务注解配置错误

  • 没有开启事务注解扫描或者没有在配置文件中开启事务。
<!-- 开启事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

<!-- 开启事务注解扫描 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
  • 没有在需要开启事务的方法上添加@Transactional注解。
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Transactional
    public void addUser(User user) {
        userDao.addUser(user);
    }
}
  • 在事务方法上添加了错误的propagation或isolation属性值。
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)
public void transferMoney(String fromAccount, String toAccount, double amount) {
    // transfer money from one account to another
}

  • 在注解中配置了错误的rollbackFor或noRollbackFor属性值。
@Transactional(rollbackFor = RuntimeException.class, noRollbackFor = BusinessException.class)
public void updateUserInfo(User user) throws BusinessException {
    // update user information
}

4、 事务注解被覆盖导致事务失效

@Transactional(propagation = Propagation.REQUIRED)
public class ParentClass {
    public void doSomething() {
        // ...
    }
}

public class ChildClass extends ParentClass {
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void doSomething() {
        // ...
    }
}

在上述代码中,ParentClass 中的事务注解 @Transactional(propagation = Propagation.REQUIRED) 覆盖了 ChildClass 中的事务注解 @Transactional(propagation = Propagation.NOT_SUPPORTED),因此当调用 ChildClass 中的 doSomething 方法时,事务将会失效。为了解决这个问题,可以在子类中将事务注解的属性值与父类保持一致。

5、 嵌套事务和异常被捕获导致事务失效

嵌套事务是指在一个事务内部,开启了一个新的事务,这个新事务与外部事务是嵌套关系,也就是内部事务依赖于外部事务,只有外部事务提交成功,内部事务才能生效。

在 Spring 中,通过设置事务传播级别来实现嵌套事务,常见的传播级别包括:

  • REQUIRED:如果当前存在事务,则加入该事务;否则,创建一个新的事务。这是默认值。
  • REQUIRES_NEW:每次都创建一个新的事务,并将当前事务挂起。
  • NESTED:如果当前存在事务,则在嵌套事务内执行;否则,创建一个新的事务。这种方式也是嵌套事务的实现方式。
    在嵌套事务中,如果外部事务回滚了,那么内部事务也会回滚;如果内部事务回滚了,只会回滚内部事务,而不会影响到外部事务。

然而,使用嵌套事务需要注意一些坑:

  1. 数据库支持
    嵌套事务是由数据库来实现的,不同的数据库对于嵌套事务的支持不同,有些数据库甚至不支持嵌套事务,例如 MySQL 默认是不支持嵌套事务的。

  2. 事务管理器
    Spring 事务是通过事务管理器来实现的,不同的事务管理器对于嵌套事务的支持也不同,如果使用的事务管理器不支持嵌套事务,那么嵌套事务就会失效。

  3. 异常处理
    在嵌套事务中,如果内部事务抛出了异常,并且外部事务没有捕获这个异常,那么整个事务会回滚,包括内部事务和外部事务。因此,在嵌套事务中,要注意异常处理。

@Service
public class UserServiceImpl implements UserService {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional(propagation = Propagation.REQUIRED)
    public void updateUser(User user) {
        jdbcTemplate.update("update user set name = ? where id = ?", user.getName(), user.getId());
        try {
            insertLog(user.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Transactional(propagation = Propagation.NESTED)
    public void insertLog(Long userId) {
        jdbcTemplate.update("insert into log(user_id) values(?)", userId);
        throw new RuntimeException("插入日志失败");
    }

}

上述代码中,updateUser 方法中调用了 insertLog 方法,insertLog 方法使用了 Propagation.NESTED 的传播级别来实现嵌套事务。当插入日志时,会抛出 RuntimeException 异常,并被 updateUser 方法中的 try-catch 块捕获。在这种情况下,虽然 insertLog 方法的事务会回滚,但是由于使用的是嵌套事务,所以 updateUser 方法的事务并不会回滚,导致了事务失效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/13644.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

技术干货|直流电源自动测试系统功能介绍

直流电源是一种将交流电转换为恒定电压或电流输出的电子设备。在实际生产生活中&#xff0c;直流电源被广泛应用于各种场合。但由于各种原因&#xff0c;包括工艺、质量等因素&#xff0c;直流电源存在一定的出厂偏差。为了确保直流电源的精度和稳定性&#xff0c;在生产过程中…

如何将模块加载到linux内核

一 顺利的情况 假设存在一个文件叫mymq.c,下该文件相同目录下的makefile如下语句&#xff1a; obj-y mymq.o 然后编译&#xff1a;编译完成了以后&#xff0c;mymq.c文件中&#xff0c;有个函数叫mymq_open,搜索这个函数在不在System.map文件中&#xff0c;如果在&#xff…

开放式耳机真的比封闭式强很多吗?推荐几款主流的开放式耳机

​开放式耳机&#xff0c;顾名思义&#xff0c;就是通过骨头振动来传导声音的耳机。相比于传统耳机&#xff0c;它的声音传输更加开放&#xff0c;不会对耳膜造成压迫感&#xff0c;也不会对耳膜旁的内毛细胞造成损害。因此开放式耳机既是运动蓝牙耳机&#xff0c;又是音乐蓝牙…

Spring依赖注入的三种方式使用及优缺点

初学Spring的时候,我们从Spring容器中获取Bean对象都是通过bean标签先将Bean对象注册到Spring容器中&#xff0c;然后通过上下文对象congtext的getBean方法进行获取&#xff0c;显然这种方法较为麻烦&#xff0c;所以有了更简单的存方法&#xff1a;五大类注解&#xff1b;取方…

在Linux中进行Jenkins-2.190的安装及使用

Jenkins-2.190安装在公网IP为x.x.x.x的服务器上 环境准备 第一步&#xff0c;下载server-jre-8u202-linux-x64.tar.gz安装包。 登录地址&#xff1a;https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html下载server-jre-8u202-linux-x64.tar.gz…

3自由度并联绘图机器人实现写字功能(一)

1. 功能说明 本文示例将实现R305样机3自由度并联绘图机器人写字的功能。 2. 电子硬件 在这个示例中&#xff0c;采用了以下硬件&#xff0c;请大家参考&#xff1a; 主控板 Basra主控板&#xff08;兼容Arduino Uno&#xff09; 扩展板Bigfish2.1扩展板电池7.4V锂电池 3. 功能…

能量密度的必要性:城市比乡村具有更高的能量密度

文章目录 引言I 人口密度1.1 人口密度太低对于经济的发展的不利因素1.2 足够的人口密度带来的好处1.3 乌鲁克城II 农耕文明和商业文明2.1 农耕文明2.2 商业文明III 有效掌握动力的文明处于优势3.1 苏美尔人- 轮子&风能的利用3.2 英国人- 以蒸汽机为代表的工业革命引言 文明…

作业3综合练习

综合练习: 要求&#xff1a;请给openlab搭建web网站 网站需求: 1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! 2.给该公司创建三个子界面分别显示学生信息,教学资料和缴费网站,基于www.openlab.com/student #更改配置文件 &#xff08;虚拟主机标签…

2023好玩的解压游戏,压力大点开玩可以放松自己

你是不是经常感觉到压力大&#xff1f; 现代社会&#xff0c;竞争逐步激烈&#xff0c;不管是来自学习上&#xff0c;工作上&#xff0c;还是生活上的&#xff0c;压力都非常大&#xff01; 这时候&#xff0c;我们要学会自我减压&#xff0c;有效的放松是为了更好地前行。 …

新互联网人必学-产品经理课无密为伊消得人憔悴

新互联网人必学-产品经理课 download&#xff1a;https://www.666xit.com/3832/ 产品经理&#xff1a;连接用户需求和产品设计的重要角色 随着移动互联网的迅猛发展&#xff0c;产品经理已成为越来越多IT公司中不可或缺的职位。作为一名产品经理&#xff0c;他所扮演的角色是…

如何使用DNS实现融合CDN功能

将托管DNS解决方案与CDN配对可为您的网站提供额外的性能、可靠性和灵活性。 域名系统&#xff08;DNS&#xff09;是一种用于计算机、服务或连接到Internet或专用网络的任何资源的分层分布式命名系统&#xff0c;它将各种信息与分配给每个参与实体的域名相关联&#xff0c;它基…

【LeetCode】剑指 Offer 66. 构建乘积数组 p312 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/gou-jian-cheng-ji-shu-zu-lcof/ 1. 题目介绍&#xff08;66. 构建乘积数组&#xff09; 给定一个数组 A[0,1,…,n-1]&#xff0c;请构建一个数组 B[0,1,…,n-1]&#xff0c;其中 B[i] 的值是数组 A 中除了下标 i 以外的元素…

System V 共享内存

System V 共享内存 共享内存是什么如何使用共享内存ftokshmgetshmatshmdtshmctl 共享内存的原理共享内存实现两个进程间通信共享内存的特点共享内存与管道配合使用两个进程间通信多个进程间通信 共享内存是什么 &#x1f680;共享内存是最快的IPC形式。一旦这样的内存映射到共…

网络工程师的水平检测1

水平测试 文章目录 水平测试填空题&#xff08;11分&#xff09;判断题&#xff08;9分&#xff09;选择题&#xff08;8分&#xff09;简答题&#xff08;26分&#xff09;子网划分&#xff08;24分&#xff09;实验拓扑&#xff08;19分&#xff09;填空题&#xff08;5分&am…

【MySQL】数据库完整性和安全性

目录 一、完整性 1.概念 2.sql语言支持的两种约束 2.1静态约束 撤销追加约束 断言 2.3动态约束 触发器 二、安全性 用DBMS对数据库实现的两个特性 一、完整性 1.概念 指dbms保证的db的一种特性&#xff0c;在任何情况下的正确性、有效性、一致性 原理图 广义完整性&…

园区路线地图指引图怎么画?园区地图三维图怎么画?

目前在园区信息化应用形式中&#xff0c;广泛缺乏专业电子地图的使用&#xff0c;因此&#xff0c;使这种高效的信息化工具的应用受到了很大限制。有些仅以图片代替&#xff0c;但图片没有空间计算、检索、路径设计的能力&#xff0c;在地图应用形式中&#xff0c;使用价值很低…

Day953.以假设驱动为指引 -遗留系统现代化实战

以假设驱动为指引 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于以假设驱动为指引的内容。 很多人在做遗留系统现代化的时候呢&#xff0c;总觉得它是一个十分复杂的技术问题。 本来嘛&#xff0c;无论是代码的重构、架构的拆分&#xff0c;还是 DevOps 平台的搭…

除了学历,你更需要有能力

遥想当年&#xff0c;家里培养出一个大学生&#xff0c;是多荣耀的事&#xff01;可现今却处于一个比较尴尬的状态。 为什么大学生贬值得这么厉害&#xff1f;其实大学生之所以会不值钱不外乎三大原因&#xff1a;量大、与企业需求不匹配、质量差。 高校扩招下&#xff0c;大…

Python每日一练(20230423)

目录 1. 删除链表的倒数第 N 个结点 &#x1f31f;&#x1f31f; 2. 最小覆盖子串 &#x1f31f;&#x1f31f;&#x1f31f; 3. 二叉树的层序遍历 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏…

Java核心技术 卷1-总结-11

Java核心技术 卷1-总结-11 Java 集合框架将集合的接口与实现分离Collection接口迭代器泛型实用方法集合框架中的接口 Java 集合框架 将集合的接口与实现分离 Java集合类库将接口&#xff08;interface&#xff09;与实现&#xff08;implementation&#xff09;分离。 例如队…
最新文章