当前位置: 首页 > news >正文

SpringBoot 中 @Transactional 注解的使用

一、基本介绍
        事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。本篇只说明声明式注解。

1、在 spring 项目中, @Transactional 注解默认会回滚运行时异常及其子类,其它范围之外的异常 Spring 不会帮我们去回滚数据(如果也想要回滚,在方法或者类加上@Transactional(rollbackFor = Exception.class) 即可)。异常继承体系如下图

  •  Throwable 是最顶层的父类,有 Error 和 Exception 两个子类。
    • Error:表示严重的错误(如OOM等)
    • Exception 可以分为运行时异常( RuntimeException 及其子类)和非运行时异常( Exception 的子类中,除了 RuntimeException 及其子类之外的类)。
      • 非运行时异常是检查异常( checked exceptions ),一定要 try catch,因为这类异常是可预料的,编译阶段就检查的出来。如果不抛出异常,该行代码是会报错的,项目也会启动不起来。
      • Error 和运行时异常是非检查异常( unchecked exceptions ),不需要 try catch,因为这类异常是不可预料的,编译阶段不会检查。

2、@Transactional 注解只能应用到 public 方法或者类上才有效
二、简单的使用方法
只需在方法加上 @Transactional 注解就可以了。

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

    @Override@Transactionalpublic String save(ProductModuleConfig productModuleConfig){productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException("save方法运行时异常");}return "成功";}

我们可以从控制台日志可以看出这些信息:

该事务没有提交 commit,因为遇到 RuntimeException 异常该事务进行了回滚,数据库中也没有该条数据。

再看一个简单的使用方法:

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)@Overridepublic String save(ProductModuleConfig productModuleConfig){productModuleConfigDao.insert(productModuleConfig);try {String a = null;boolean equals = a.equals("2");} catch (Exception e) {e.printStackTrace();}return "成功";}
  • save 方法无 @Transactional 注解
    • 空指针异常没有被 try catch:插入数据库操作成功
    • 空指针异常被 try catch:插入数据库操作成功
  • save 方法有 @Transactional 注解
    • 空指针异常没有被 try catch:插入数据库操作失败,回滚成功
    • 空指针异常被 try catch:插入数据库操作成功,回滚失败

三、@Transactional 注解的属性介绍
事务的传播属性(propagation 属性默认值为 Propagation.REQUIRED)

所谓事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。Spring 支持以下 7 种事务传播行为:

名词解释:

  • 当天事务挂起:需要新事物时,将现有的 connection1保存起来(它还有尚未提交的事务),然后创建 connection2,connection2 提交、回滚、关闭完毕后,再把 connection1取出来,完成提交、回滚、关闭等动作,保存 connection1 的动作称之为事务挂起。

详解 Spring 的事务传播属性以及在写代码的过程中发生嵌套并发生事务失效的场景

再说这些之前,大家先要消除一个问题, Spring 的事务是怎么实现的?

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

四、@Transactional 注解的一些代码 demo
        比如如下代码,save 方法首先调用了 method1 方法,然后 save 方法抛出了异常,就会导致事务回滚,如下两条数据都不会插入数据库。可从控制台日志信息可以看出,没有提交(commit)事务,直接回滚掉了。

    @Override@Transactional(propagation = Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){method1();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException("save方法运行时异常");}return "成功";}public void method1() {ProductModuleConfig productModuleConfig = new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName("哈哈哈哈2");productModuleConfigDao.insert(productModuleConfig);}

   

        现在有如下需求,就算 save 方法的后面抛异常了,也不能影响 method1 方法的数据插入。或许很多人的想法如下,给 method1 方法加入一个新的事务,这样 method1 就会在这个新的事务中执行,原来的事务不会影响到新的事务。比如 method1 方法上面再加入注解 @Transactional ,设置 propagation 属性为 Propagation.REQUIRES_NEW,代码如下:

    @Override@Transactional(propagation = Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){method1();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException("save方法运行时异常");}return "成功";}@Transactional(propagation = Propagation.REQUIRES_NEW)public void method1() {ProductModuleConfig productModuleConfig = new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName("哈哈哈哈2");productModuleConfigDao.insert(productModuleConfig);}

         运行之后,发现数据还是没有插入数据库中。怎么回事,我们先看一下控制台日志打印信息。从日志内容可以看出,其实两个方法都是处于同一个事务中,method1 方法并没有创建一个新的事务。

        大概意思:在默认的代理模式下,只有目标方法由外部调用,才能被 Spring 的事务拦截器拦截。 在同一个类中的两个方法直接调用,是不会被 Spring 的事务拦截器拦截,就像上面的 save 方法直接调用了同一个类中的 method1 方法,method1 方法不会被 Spring 的事务拦截器拦截,也就是说 method1 方法上的注解是失效的,根本没起作用。

用一个示意图加深一下印象:

        看上边的示意图你一定会明白了吧,原因还是因为代理的时候,直接把有事务的方法包在了有事务的代理方法里面了,不管 method2方法是否有 @Transactional 注解,都会随着 method1() 的事务属性决定,如果 method1() 回滚,必然会导致 method2() 也会回滚。

        为了解决这个问题,我们可以新建一个类:

@Service
public class OtherServiceImpl implements OtherService {@Resourceprivate ProductModuleConfigDao productModuleConfigDao;@Transactional(propagation = Propagation.REQUIRES_NEW)@Overridepublic void method() {ProductModuleConfig productModuleConfig = new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName("哈哈哈哈3");productModuleConfigDao.insert(productModuleConfig);}}

         然后在 save 方法中调用 otherService.method1 方法

    @Override@Transactional(propagation = Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){otherService.method();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException("save方法运行时异常");}return "成功";}

        这下,otherService.method 方法的数据插入成功,事务提交了。save 方法的数据未插入,事务回滚了。继续看一下日志内容:

        从日志可以看出,首先创建了 save 方法的事务,由于 otherService.method 方法的 @transactional 的 propagation 属性为 Propagation.REQUIRES_NEW(新建事务,如果当前存在事务,就把当前事务挂起。如果当前方法没有事务,就新建事务),所以接着暂停了 save 方法的事务,重新创建了 otherService.method 方法的事务,接着 otherService.method 方法的事务提交,method方法数据保存成功。接着 save 方法事务开始运行碰到错误将其插入的数据进行回滚,但是method方法插入的数据不会回滚。这就印证了只有目标方法由外部调用,才能被 Spring 的事务拦截器拦截。

总结:

  • 在同一个类中事务嵌套的话,最终的结果应该是取决于最外层的方法事务的传播特性。
  • 如果是不同的类的事务嵌套的话,外层的方法按照外层的事务传播属性执行,内层的传播属性按照内层的传播属性的特点去运行。

五、@Transactional 注解失效场景
1、@Transactional 注解应用在非 public 修饰的方法上,导致注解失效
        protected、private 修饰的方法上使用 @Transactional 注解,事务是无效

2、propagation 设置错误,导致注解失败
        propagation 属性设置为 PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、 PROPAGATION_NEVER 这三种类别时,@Transactional 注解就不会产生效果。

3、rollbackFor 设置错误,@Transactional 注解失败
        Spring 默认回滚事务分别为抛出了未检查 unchecked 异常(继承自 RuntimeException 的异常)和 Error 两种情况,其他异常不会回滚,希望抛出其他异常 Spring 亦能回滚事务,需要指定 rollbackFor 属性

4、方法之间的互相调用导致 @Transactional 失效(在同一个 Service 中)

    @Override@Transactional(propagation = Propagation.REQUIRED)public String save(ProductModuleConfig productModuleConfig){method1();productModuleConfigDao.insert(productModuleConfig);if (true) {throw new RuntimeException("save方法运行时异常");}return "成功";}@Transactional(propagation = Propagation.REQUIRES_NEW)public void method1() {ProductModuleConfig productModuleConfig = new ProductModuleConfig();productModuleConfig.setId(UUID.randomUUID().toString());productModuleConfig.setName("哈哈哈哈2");productModuleConfigDao.insert(productModuleConfig);}

5、异常被 catch 捕获导致 @Transactional 注解失效

    @Transactional(propagation = Propagation.REQUIRED)@Overridepublic String save(ProductModuleConfig productModuleConfig){try {productModuleConfigDao.insert(productModuleConfig);method2();} catch (Exception e) {e.printStackTrace();}return "成功";}public void method2(){String a = null;boolean equals = a.equals("2");}

        method2 方法是会报空指针异常,而 save 方法对其进行了 try catch 了method2 方法的异常,那 save 方法的事务就不能正常回滚,数据还是会插入到数据库中的,最终会报 method2 方法的空指针异常。

6、数据库引擎不支持事务
        这种情况出现的概率并不高,事务能否生效数据库引擎是否支持事务是关键。常用的MySQL数据库默认使用支持事务的innodb引擎。一旦数据库引擎切换成不支持事务的myisam,那事务就从根本上失效了。

相关文章:

SpringBoot 中 @Transactional 注解的使用

一、基本介绍 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。本篇只说明声明式注解。 1、在 spring 项目中, Transactional 注解默认会回滚运行时异常及其子类,其它范…...

【还不了解 Dockerfile 的同学不是好测试人】

近年来 Docker 非常火,想要玩好 Docker 的话 Dockerfile 是绕不开的,这就好比想要玩好 Linux 服务器绕不开 shell 道理是一样的。 今天我们就来聊一聊 Dockerfile 怎么写,那些指令到底是什么意思。 前言 一、先来看一个简单的 Dockerfile #这…...

新手一键重装系统Win10步骤教程

如果我们发现电脑上的操作系统出现很严重的问题,不能通过简单的操作解决,这时候就可以选择重新安装电脑系统,快速解决问题。但是,新手用户不具备专业的装机知识,不知道重装Win10系统要怎么操作?那么可以按照…...

Ceph源码分析-在C++中,符号““和“*“有不同的用法。

在C中,符号"&"和"*"有不同的用法。 "&"符号: 在变量声明时,"&"用于定义引用类型。例如:int a 10; int& ref a; 这里的"ref"是一个引用,它引用了…...

Azure AI 内容安全Content Safety Studio实战

Azure AI Content Safety 检测应用程序和服务中用户生成和 AI 生成的有害内容。 Azure AI 内容安全包括文本和图像 API,可用于检测有害材料。 交互式 Content Safety Studio,可用于查看、浏览和试用用于检测不同形式的有害内容的示例代码。 关注TechLead…...

计算机网络学习笔记(四)

文章目录 1.介绍一下HTTPS的流程。2.介绍一下HTTP的失败码。3.说一说你知道的http状态码。4. 301和302有什么区别?5.302和304有什么区别?6. 请描述一次完整的HTTP请求的过程。7.什么是重定向?8. 重定向和请求转发有什么区别?9.介绍…...

typora导出html添加目录

typora导出html添加目录 使用方法 首先要从typora导出html文件,之后用记事本编辑器html文件 找到文档最后面,如图: 用文字编辑类工具打开sideBar.txt,复制其中所有内容【内容在下面】 在如上图的位置插入所复制的内容 打开修改…...

vue3 封装一个按钮组件(可自定义按钮样式)

效果图 鼠标悬浮有对应的文字提示&#xff0c;且图标出现背景色和颜色 实现 目前提供五个固定样式的图标及三个用户自定义的图标&#xff0c;可根据需要补充 组件代码 <script setup lang"ts"> import { onMounted, PropType, reactive, ref, watch } from v…...

Docker 中使用超级用户

在docker中安装keytool产生的问题&#xff1a; sudo apt-get install openjdk-8-jre-headless bash: sudo: command not found elasticsearchd989639e3cb4:~/config/certs$ apt-get install openjdk-8-jre-headless E: Could not open lock file /var/lib/dpkg/lock-frontend …...

git打tag以及拉取tag

场景&#xff1a;某次git代码发布后定版记录&#xff0c;将发版所在的commit时候代码打上tag记录&#xff0c;方便后期切换到对应tag代码位置。 查看所有tag名 git tag// 1.1.0 // 1.0.0查看tag和描述 git tag -l -n//1.0.0 云监管一期项目完结 //1.1.0 …...

TS 36.212 V12.0.0-信道编码、复用和交织(1)-通用过程

本文的内容主要涉及TS 36.212&#xff0c;版本是C00&#xff0c;也就是V12.0.0。...

纯前端上传word,xlsx,ppt,在前端预览并下载成图片(预览效果可以,下载图片效果不太理想)

纯前端上传word,xlsx,ppt,在前端预览并下载成图片&#xff08;预览效果可以&#xff0c;下载图片效果不太理想&#xff09; 一.安装依赖二、主要代码 预览效果链接: https://github.com/501351981/vue-office 插件文档链接: https://501351981.github.io/vue-office/examples/d…...

WPS Office找回丢失的工作文件

WPS office恢复办公文件方法有两种. 1.通过备份中心可以查看近期编辑 office 历史版本进行恢复. 2.缓存备份目录可以查看编辑过的 office 文件的历史版本&#xff0c;新版本 WPS 可以在配置工具-备份清理找到&#xff0c;2019 年旧版本 WPS 可以在新建任意 office 文件-文件-选…...

【MATLAB源码-第106期】基于matlab的SAR雷达系统仿真,实现雷达目标跟踪功能,使用卡尔曼滤波算法。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 1. 雷达系统参数设定&#xff1a; - 工作频率&#xff1a;选择一个适合的工作频率&#xff0c;例如X波段&#xff08;8-12 GHz&#xff09;。 - 脉冲重复频率&#xff08;PRF&#xff09;&#xff1a;设定一个适当的PR…...

【机器学习】scikit-learn机器学习中随机数种子的应用与重现

随机数种子是为了能重现某一次实验生成的随机数而设立的&#xff0c;相同的随机数种子下&#xff0c;生成的随机数序列一样 一、随机数种子基础应用 在python中简单运用随机数种子 import random random.seed(1) a random.sample(range(0,100),10) random.seed(2) b random.…...

欧洲编程语言四巨头

从左往右&#xff0c;依次是 尼克劳斯沃斯 (Niklaus Wirth)&#xff0c;迪杰斯特拉&#xff08;Edsger Dijkstra&#xff09;&#xff0c;霍尔&#xff08;Tony Hoare&#xff09; 尼克劳斯沃斯 (Niklaus Wirth) 瑞士人&#xff0c;一生发明了8种编程语言&#xff0c;其中最著…...

检查密码(字符串)

本题要求你帮助某网站的用户注册模块写一个密码合法性检查的小功能。该网站要求用户设置的密码必须由不少于6个字符组成&#xff0c;并且只能有英文字母、数字和小数点 .&#xff0c;还必须既有字母也有数字。 输入格式&#xff1a; 输入第一行给出一个正整数 N&#xff08;≤…...

Pointnet++改进注意力机制系列:全网首发LSKAttention大核卷积注意力机制 |即插即用,实现有效涨点

简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入LSKAttention注意力机制,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二...

C++常用库函数大小写转换

在我们在编写代码时大小写转换是基础知识&#xff0c;这篇博客将通过介绍C常用库函数来回顾和学习一种不一样的大小写转换 目录 一、islower/isupper函数二、tolower/toupper函数三、ASCLL码 一、islower/isupper函数 islower和isupper函数是C标准库中的字符分类函数&#xff…...

基于springboot+html的汽车销售管理系统设计与实现

基于springboothtml的汽车销售管理系统 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; 前言 随着汽车市场的快速发展&#xff0c;汽车销售企业面临着越来越大的管理…...

pyside6 界面美化库的使用

使用qt_material库&#xff0c;在库中进行导入后&#xff0c;直接使用库提供的皮肤即可非常简单 example&#xff1a; # -*- coding: utf-8 -*- # 使用例子 import sys # from PySide6 import QtWidgets # from PySide2 import QtWidgets from PySide6 import QtWidgets from…...

通过Docker搭建4节点的Tendermint集群

Tendermint&#xff1a;0.34.24 Docker&#xff1a;20.10.21 Docker-Compose&#xff1a;2.20.2 OS&#xff1a;Ubuntu 20.04 Go&#xff1a;1.19.2 Linux/amd64 1 修改Tendermint源码 1.1 修改监听IP 为什么要将127.0.1修改成0.0.0.0呢&#xff1f;因为容器内的服务如果是以…...

element plus 表格组件怎样在表格中显示图片

官方给的&#xff1a; <el-table-column label"Thumbnail" width"180"><template #default"scope"><div style"display: flex; align-items: center"><el-image :preview-src-list"srcList"/><…...

cad快速看图软件免费版(手机在线cad快速看图)

cad快速看图软件免费版(手机在线cad快速看图) 很多机械设计师日常工作过程中涉及到多种格式的cad图纸&#xff0c;cad图纸大多都需要cad设计软件才能打开&#xff0c;然而很多小伙伴并没有下载相应的cad设计软件&#xff0c;这种情况下如何进行cad快速看图呢&#xff1f; 今天…...

C#: Label、TextBox 鼠标停留时显示提示信息

说明&#xff1a;记录在 Label、TextBox 控件上 鼠标停留时显示提示信息的方法。 1.效果图 2.具体实现步骤 1. 在Form 窗口中先创建 Label 并取名&#xff1a;KEY_label &#xff0c;或 TextBox 取名&#xff1a;KEY_textBox 2. lable控件的 tips 实现方法1 &#xff1a;代码…...

.NET 8.0 本机 AOT

在软件开发领域&#xff0c;优化性能和简化效率仍然至关重要。.NET 平台二十年来不断创新&#xff0c;为开发人员提供了构建弹性且高效的软件解决方案的基础架构。 与本机 AOT&#xff08;提前&#xff09;编译相结合&#xff0c;取得了显着的进步。本文深入研究.NET Native AO…...

phpcms v9未审核推荐信息出现在推荐列表中【BUG修复】

修改文件&#xff1a;phpcms/modules/content/class/content_tag.class.php 调整过的方法&#xff1a; public function __construct() {$this->db pc_base::load_model(content_model);$this->position pc_base::load_model(position_model);$this->position_da…...

Linux第20步_在虚拟机上安装“Visual Studio Code”

1、双击windows系统桌面上的“FileZilla Client.exe”&#xff0c;打开FTP客户端&#xff0c;点击03软件下的Visual Studio Code&#xff0c;发现code_1.50.1-1602600906_amd64。 2、点击“文件”&#xff0c;然后点击“站点管理器”&#xff0c;见下图操作&#xff1a; 3、点…...

【服务器数据恢复】Raid5热备盘同步失败导致lvm结构损坏的数据恢复案例

服务器数据恢复环境&#xff1a; 两组由4块磁盘组建的raid5磁盘阵列&#xff0c;两组raid5阵列划分为lun并组成了lvm结构&#xff0c;ext3文件系统。 服务器故障&#xff1a; 一组raid5阵列中的一块硬盘离线&#xff0c;热备盘自动上线并开始同步数据。在热备盘完成同步之前&am…...

react+AntDesign 之 pc端项目案例

1.环境搭建以及初始化目录 CRA是一个底层基于webpack快速创建React项目的脚手架工具 # 使用npx创建项目 npx create-react-app react-jike# 进入到项 cd react-jike# 启动项目 npm start2.安装SCSS SASS 是一种预编译的 CSS&#xff0c;支持一些比较高级的语法&#xff0c;…...

php做自己的网站/优化设计全部答案

在iOS开发中UITableView可以说是使用最广泛的控件&#xff0c;我们平时使用的软件中到处都可以看到它的影子&#xff0c;基本大部分应用都有UITableView。当然它的广泛使用自然离不开它强大的功能&#xff0c;今天就针对UITableView重点展开讨论。 1.UITableView有两种风格&…...

网站建设考试题目/百度一下下载

转自, https://www.jb51.net/html5/342451.html 以JSON编码格式提交表单数据是HTML5对WEB发展进化的又一大贡献&#xff0c;以前我们的HTML表单数据是通过key-value方式传输的服务器端&#xff0c;这种形式的传输对数据组织缺乏管理&#xff0c;形式十分原始。而新出现的JSON格…...

杭州网站建设官方蓝韵网络/什么是竞价

目录 1、匿名内部类 2、包装类实现原理分析 3、装箱与拆箱 4、数据类型转换 5、总结 本文讲解的扩展内容&#xff0c;包括&#xff1a;匿名内部类、包装类实现原理分析、装箱与拆箱、数据类型转换。 1、匿名内部类 匿名内部类&#xff0c;故名思意就是没有名字的内部类。…...

德阳网站建设/百度网盘app怎么打开链接

文章目录修改模型Detect层设计转换后处理优质文章由于有些操作是没法支持的 如5维的操作&#xff1a; Unsupported slice axes ! Unsupported slice axes ! Unsupported slice axes ! Unsupported slice axes ! Unsupported slice axes ! Unsupported slice axes !参考&#…...

做变态手术视频网站/网站优化种类

这是什么年头、不支持代码提示还叫IDE吗~~ 就不转了、直接去看吧&#xff1a; 原文地址&#xff1a;http://www.pythonclub.org/python-basic/vim 转载于:https://www.cnblogs.com/klobohyz/archive/2011/12/01/2270308.html...

网站 robots.txt/设计案例网

DB2数据库服务器 v8(Linux)在更改机器名后数据库服务异常&#xff0c;症状是当使用db2 list db directory命令或者其他命令的时候提示错误信息如下&#xff1a;SQL6031N 在 db2nodes.cfg 文件的行号"1" 上出错。原因码为"10"。解决的办法: 打开DB2实例所有…...