03. Spring 事务管理

文章目录

  • 1. Spring 事务管理简介
  • 2. @Transactional 注解属性信息
  • 3. @Transactional 简单使用
  • 4. @Transactional 使用注意事项
    • 4.1 正确指定事务回滚的异常类型
      • 4.1.1 Java 异常继承体系
    • 4.2 `@Transactional` 注解应用在 `public` 方法或类上才有效
    • 4.3 正确设置 `@Transactional` 的 `propagation` 属性。
      • 4.3.1 事务的传播行为
      • 4.3.2 `TransactionDefinition` 和 `Propagation`
  • 5. Spring 事务失效的场景
    • 5.1 @Transactional 注解使用在非 public 方法上,导致事务失效
    • 5.2 propagation 参数设置错误,导致事务失效
    • 5.3 rollbackFor 参数设置错误,导致事务失效
    • 5.4 在同一个类中,方法之间的相互调用导致事务失效
    • 5.5 异常被捕获导致事务失效
    • 5.6 数据库引擎不支持事务

1. Spring 事务管理简介

事务管理是应用系统开发中必不可少的一部分,Spring 为事务管理提供了丰富的功能。Spring 的事务管理分为编程式和声明式两种方式。声明式事务管理可以使业务代码逻辑不受污染,将业务逻辑和事务处理解耦。声明式事务也有两种方式:一种是在配置文件(xml)中做相关的事务规则声明,一种是基于注解 @Transactional 的方式

事务是数据库的概念,Spring 本身是没有事务的,Spring 的事务是借助 AOP,通过动态代理的方式实现。
在我们要操作数据库的时候,实际是 Spring 通过动态代理进行功能拓展,在我们的代码操作数据库之前通过数据库客户端打开数据库事务,如果代码执行完毕没有异常信息或者是没有 Spring 要捕获的异常信息时,再通过数据库客户端提交事务;如果有异常信息或者是有 Spring 要捕获的异常信息,再通过数据库客户端程序回滚事务,从而控制数据库事务。

Spring 基于注解使用事务主要有两步:

  • 在主配置类上声明 @EnableTransactionManagement 注解,表示开启声明式事务;
  • 在访问数据库的方法上添加 @Transactional 注解。

@Transactional 注解也可以用在类上,表示该类的所有公共方法都配置相同的事务属性。如果类和方法都配置了 @Transactional,应用程序会用方法级别的事务属性来管理事务。

2. @Transactional 注解属性信息

属性名说明
name当配置文件中有多个 TransactionManager时,可以用该属性指定选择哪个事务管理器
propagation事务的传播行为,默认值:REQUIRED
isolation事务的隔离度,默认值:DEFAULT
timeout事务的超时时间,默认值 -1。如果超过该时间但事务未完成,则回滚该事务
readOnly指定事务为只读事务,默认值 false。指定当前事务为只读事务后,当前事务不能进行写操作,否则报错
rollbackFor指定能够触发事务回滚的异常类型,如果有多个异常类型要指定,用逗号分隔
noRollbackFor抛出该参数指定的异常类型,不回滚事务

3. @Transactional 简单使用

如下有一个保存数据的方法,加上 @Transactional 注解,运行时抛出运行时异常之后,事务会自动回滚,数据不会插入数据库。

    @Override
    @Transactional
    public boolean save() {
        boolean res = stateRepository.save();
        if(true) {
            throw new RuntimeException();
        }
        return res;
    }
  • 如果去掉 @Transactional 注解,save() 就是一个普通的没有事务的方法,执行时还是会抛出异常,但是会插入数据。
  • 如果加上 @Transactional 注解,但是在方法内使用 try-catch 捕获异常,则事务不会回滚,数据会插入成功。
        @Override
        @Transactional
        public boolean save() {
            boolean res = stateRepository.save();
            try {
                if(true) {
                    throw new RuntimeException();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return res;
        }
    

4. @Transactional 使用注意事项

4.1 正确指定事务回滚的异常类型

默认情况下,@Transactional 会在运行时异常及其子类异常时回滚事务,其他类型的异常 Spring 不会帮我们回滚事务。如果要在指定类型的异常时回滚事务,需要使用 rollbackFor 指定异常类型,如 @Transacrional(rollbackFor = Exception.class)

4.1.1 Java 异常继承体系

在这里插入图片描述
最顶层的异常类型是可抛出异常 Throwable,有 ErrorException 两个子类。

  • Error 表示严重的错误(如 OOM);
  • Exception 分为 运行时异常(RuntimeException)和非运行时异常;
  • 非运行时异常是检查异常(checked exceptions),编译阶段就能检查出来,编码时需要 try-catch 或抛出异常。
  • Error 和运行时异常是非检查异常(unchecked exceptions),编译阶段不会检查。

4.2 @Transactional 注解应用在 public 方法或类上才有效

只有 @Transactional 注解应用到 public 方法,才能进行事务管理。

4.3 正确设置 @Transactionalpropagation 属性。

propagation 属性用于指定事务的传播行为,当 propagation 参数指定为 SUPPORTSNOT_SUPPORTEDNEVER 时,事务将不会发生回滚。

4.3.1 事务的传播行为

事务的传播行为是指,多个事务方法相互调用时,事务如何在这些方法之间传播。

Spring 支持一下 7 种事务传播行为,定义在枚举类 Propagation

传播类型说明
REQUIRED(默认值)支持当前事务,如果有就加入当前事务中。如果当前方法没有事务,则新建一个事务
SUPPORTS支持当前事务,如果有就加入当前事务中。如果当前方法没有事务,则以非事务方式执行
MANDATORY支持当前事务,如果有就加入当前事务中。如果当前方法没有事务,就抛出异常
REQUIRES_NEW如果当前存在事务,就把当前事务挂起,然后新建一个事务;如果当前方法不存在事务,就新建一个事务
NOT_SUPPORTED以非事务方式执行,如果当前方法存在事务就挂起当前事务,执行完后恢复事务
NEVER以非事务方式执行,如果当前方法存在事务,则抛出异常
NESTED如果当前存在事务,则嵌套在当前事务中。如果当前没有事务,则新建一个事务自己执行。(嵌套事务使用保存点作为回滚点,内部事务回滚不影响外部事务的提交,但是外部事务的回滚会把内部事务一起回滚。)

4.3.2 TransactionDefinitionPropagation

TransactionDefinition 和 Propagation 是 Spring 框架中两个不同的概念,它们在事务管理中起着不同的作用。

  • TransactionDefinition 是一个接口,它定义了事务的基本属性,如隔离级别、传播行为、超时时间等。它允许您为事务设置各种属性,并将这些属性应用于事务管理器。
  • Propagation是一个枚举,它定义了事务的传播行为。事务传播行为确定了当一个事务方法被另一个事务方法调用时会发生什么。它控制了事务如何与现有事务相关联,以及是否创建新的事务。
  • 总之,TransactionDefinition 是关于定义事务属性的,而 Propagation 是关于控制事务传播行为的。它们在 Spring 框架的事务管理中发挥着重要作用,使开发人员能够精细地控制事务的行为。

5. Spring 事务失效的场景

5.1 @Transactional 注解使用在非 public 方法上,导致事务失效

5.2 propagation 参数设置错误,导致事务失效

propagation 参数设置为 SUPPORTSNOT_SUPPORTEDNEVER 时,@Transactional 注解就不会产生效果。

5.3 rollbackFor 参数设置错误,导致事务失效

  • Spring 默认在方法抛出未检查异常或 Error 时回滚事务,其他异常类型不会回滚;
  • 如果要在方法抛出其他异常时也能回滚事务,需要 rollbackFor 参数指定异常类型。

5.4 在同一个类中,方法之间的相互调用导致事务失效

如下,在 StateService 中有两个保存方法:

	@Override
    @Transactional
    public boolean save() {
    	save2();
        boolean res = stateRepository.save();
        if(true) {
            throw new RuntimeException();
        }
        return res;
    }
    
    private boolean save2() {
        StateDAO stateDAO = new StateDAO();
        stateDAO.setWorkspaceKey("space1");
        return stateRepository.saveState(stateDAO);
    }

save() 方法首先调用了 save2() 方法,然后 save() 方法抛出异常,导致事务回滚,两条数据都不会插入数据库。

现在我们想实现:save() 方法抛异常不影响 save2() 方法插入数据。@Transactionalpropagation 参数可以设置事务的传播行为,我们可以尝试给 save2() 方法设置 propagation = REQUIRES_NEW 去实现。如下:

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public boolean save() {
    	save2();
        boolean res = stateRepository.save();
        if(true) {
            throw new RuntimeException();
        }
        return res;
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private boolean save2() {
        StateDAO stateDAO = new StateDAO();
        stateDAO.setWorkspaceKey("space1");
        return stateRepository.saveState(stateDAO);
    }

但是,运行之后,发现 save2() 方法的数据也没有插入数据库。

原因:

在默认的代理模式下,只有目标方法由外部调用,才能被 Spring 的事务拦截器拦截。在同一个类的两个方法直接调用,不会被 Spring 的事务拦截器,也就是说 save2() 方法的 @Transactional 注解是失效的。

为解决该问题,可以新建一个 service 类,提供 save2() 方法。然后在 save() 方法中调用这个外部的 save2() 方法。

5.5 异常被捕获导致事务失效

事务通知只有捕获到了目标抛出的异常,才能进行回滚处理;如果目标自己处理掉异常,事务通知无法知悉。

如:

    @Override
    @Transactional
    public boolean save() {
        boolean res = planBaselineStateRepository.save();
        try {
            if(true) {
                throw new RuntimeException();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return res;
    }

5.6 数据库引擎不支持事务

  • InnoDB 引擎支持事务,是 MySQL 默认的引擎;
  • MyIsam 引擎不支持事务。

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

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

相关文章

解决vue3项目vite打包忽略.vue扩展名

项目打包时报could not relolve “...”,因为vite已不再默认忽略.vue扩展名。 解决方法如下: 在vite.config.js中配置vite使其忽略 .vue 扩展名(不建议忽略) 注意:即使忽略了.vue文件,在实际写的时候也要加…

【CTF Web】CTFShow web7 Writeup(SQL注入+PHP+进制转换)

web7 1 阿呆得到最高指示&#xff0c;如果还出问题&#xff0c;就卷铺盖滚蛋&#xff0c;阿呆心在流血。 解法 注意到&#xff1a; <!-- flag in id 1000 -->拦截很多种字符&#xff0c;连 select 也不给用了。 if(preg_match("/\|\"|or|\||\-|\\\|\/|\\*|\…

Spring MVC+mybatis 项目入门:旅游网(一)项目创建与准备

个人博客&#xff1a;Spring MVCmybatis 项目入门:旅游网&#xff08;一&#xff09;项目创建与准备 | iwtss blog 先看这个&#xff01; 这是18年的文章&#xff0c;回收站里恢复的&#xff0c;现阶段看基本是没有参考意义的&#xff0c;技术老旧脱离时代&#xff08;2024年辣…

使用不同的编译器编译 Skia,性能差距居然这么大

Skia 是一个开源的 2D 图形库&#xff0c;提供路径、文本、图像和渲染等图形处理功能。它最初由 Skia Inc. 开发&#xff0c;后来被 Google 收购&#xff0c;并用在多个 Google 的产品中&#xff0c;包括 Chrome 浏览器和 Android 操作系统中。从事 Android 系统开发的同学应该…

Science 基于尖峰时序编码的模拟神经触觉系统,可实现动态对象分类

快速处理和有效利用手与物体交互过程中产生的动态触觉信号&#xff08;例如触摸和抓握&#xff09;对于触觉探索和灵巧的物体操作至关重要。将电子皮肤&#xff08;e-skins&#xff09;推进到模仿自然触觉的水平&#xff0c;是恢复截肢者和瘫痪患者丧失的功能的可行解决方案&am…

北核论文完美复现:自适应t分布与动态边界策略改进的算术优化算法

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原始算术优化算法 改进点1&#xff1a;引入…

深入探索MySQL SELECT查询:从基础到高级,解锁数据宝藏的密钥

系列文章目录 更新ing... MySQL操作全攻略&#xff1a;库、表、数据、事务全面指南深入探索MySQL SELECT查询&#xff1a;从基础到高级&#xff0c;解锁数据宝藏的密钥MySQL SELECT查询实战&#xff1a;练习题精选&#xff0c;提升你的数据库查询技能PyMySQL&#xff1a;连接P…

【电路笔记】-巴特沃斯滤波器设计

巴特沃斯滤波器设计 文章目录 巴特沃斯滤波器设计1、概述2、Decades和Octaves3、低通巴特沃斯滤波器设计4、滤波器设计 – 巴特沃斯低通5、三阶巴特沃斯低通滤波器在之前的滤波器教程中,我们研究了简单的一阶型低通和高通滤波器,这些滤波器的 RC 滤波器电路设计中仅包含一个电…

Ant design vue的表格双击编辑功能(即双击开始编辑并自动获得焦点,失去焦点时完成编辑)

本文基于Ant Design Vue官方网站的表格&#xff08;可编辑单元格&#xff09;&#xff08;表格 Table - Ant Design Vue (antdv.com))中的样板代码获得双击编辑且获得焦点、失去焦点时完成编辑的功能。 要点&#xff1a; &#xff08;1&#xff09;双击时候实现编辑&#xff…

spark实战:实现分区内求最大值,分区间求和以及获取日志文件固定日期的请求路径

spark实战&#xff1a;实现分区内求最大值&#xff0c;分区间求和以及获取日志文件固定日期的请求路径 Apache Spark是一个广泛使用的开源大数据处理框架&#xff0c;以其快速、易用和灵活的特点而受到开发者的青睐。在本文中&#xff0c;我们将通过两个具体的编程任务来展示S…

在CentOS7上安装Oracle11

一、概述 Oracle有两种安装方式&#xff0c;桌面安装和静默安装。这里我采用桌面安装的方式。 不得不说&#xff0c;Oracle真的是我目前为止安装过的最麻烦的软件没有之一&#xff0c;比K8S还麻烦&#xff0c;Oracle&#xff0c;真有你的&#xff01;废话不多说&#xff0c;臭…

重学java 45.多线程 下 总结 定时器_Timer

人开始反向思考 —— 24.5.26 定时器_Timer 1.概述:定时器 2.构造: Timer() 3.方法: void schedule(TimerTask task, Date firstTime, long period) task:抽象类,是Runnable的实现类 firstTime:从什么时间开始执行 period:每隔多长时间执行一次…

Java | Leetcode Java题解之第100题相同的树

题目&#xff1a; 题解&#xff1a; class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {if (p null && q null) {return true;} else if (p null || q null) {return false;}Queue<TreeNode> queue1 new LinkedList<TreeNode>();…

MySQL——优化

全文搜索最慢 EXPLAIN select * from city; 范围搜索 EXPLAIN select * from city where ID>5 and ID<20; 主键查询 EXPLAIN select * from citywhere ID5; 索引查询 EXPLAIN select * from citywhere CountryCodeNLD; 普通查询 EXPLAIN select * from city where Nam…

C# WPF入门学习(四)—— 按钮控件

上期介绍了WPF的实现架构和原理&#xff0c;之后我们开始来使用WPF来学习各种控件。 一、尝试插入一个按钮&#xff08;方法一&#xff09; 1. VS2019 在界面中&#xff0c;点击工具栏中的视图&#xff0c;在下拉菜单中选择工具箱。 至于编译器中的视图怎么舒服怎么来布置&am…

揭秘Kafka从入门到精通,架构最全详解

Kafka架构最全详解 Kafka&#xff0c;作为关键消息中间件&#xff0c;广泛应用于大型架构与顶尖企业。本篇深入解析Kafka架构&#xff0c;掌握其核心技术要点。 Kafka Apache Kafka 是一个分布式发布-订阅消息系统&#xff0c;由LinkedIn开创的分布式发布-订阅消息系统&#x…

数据仓库与数据挖掘实验练习6-7(实验四2024.5.22)

tips&#xff1a; 列出虚拟环境&#xff1a;conda env list 激活虚拟环境&#xff1a;activate hi 进入jupyter-lab&#xff1a;jupyter lab 练习6 1. 处理字符串空格 发现问题: 使用 values 属性查看数据时&#xff0c;如果发现 Name 列没有对齐&#xff0c;很可能是 Name 左…

008-Linux后台进程管理(作业控制:、jobs、fg、bg、ctrl + z、nohup)

文章目录 前言 1、& 2、ctrl z 3、jobs 4、fg&#xff1a;将后台进程调到前台执行 5、bg&#xff1a;将一个暂停的后台进程变为执行 6、&和nohup 总结 前言 有时候我们需要将一个进程放到后台去运行&#xff0c;或者将后台程序切换回前台&#xff0c;这时候就…

刷代码随想录有感(79):回溯算法——N皇后问题

题干: 代码&#xff1a; class Solution { public:vector<vector<string>> res;void backtracking(vector<string>& chessboard, int n, int row){if(row n){res.push_back(chessboard);return;}for(int col 0; col < n; col){if(isvalid(chessboa…

【吊打面试官系列】Java高并发篇 - ThreadLocal 是什么?有什么用?

大家好&#xff0c;我是锋哥。今天分享关于 【ThreadLocal 是什么&#xff1f;有什么用&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; ThreadLocal 是什么&#xff1f;有什么用&#xff1f; ThreadLocal 是一个本地线程副本变量工具类。主要用于将私有线程和该…