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

Spring事务介绍

文章目录

    • 一、编程式事务
    • 二、声明式事务(常用)
    • 三、事务实战详解
      • 3.1)事务的回滚机制
      • 3.2)事务的传播
      • 3.3)事务超时时间
      • 3.4)事务隔离级别
      • 3.5)事务回滚条件

Spring中对事务有两种支持方式,分别是编程式事务与声明式事务:

一、编程式事务

  可通过TransactionManagerTransactionTemplate两大内置事务管理对象来完成:

// Spring内置事务管理器对象
@Autowired
private PlatformTransactionManager transactionManager;/*** 通过编程式事务来控制数据库交互:* 更新菜品价格 -> 自定义transactionManager来控制事务*/
public int updateDishPrice(Map<String, Object> paramMap) {// 1. 首先定义默认的事务属性与隔离级别DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);// 2. 获取TransactionStatusTransactionStatus status = transactionManager.getTransaction(transactionDefinition);int result = 0;try {result = dishMapper.updateDish(paramMap);// int i = 1 / 0; 模拟报错请求// 提交事务transactionManager.commit(status);} catch (DataAccessException e) {LogUtil.error("DishServices.updateDishPrice", e.getMessage());// 回滚事务transactionManager.rollback(status);}return result;
}
// Spring内置事务模板对象
@Autowired
private TransactionTemplate transactionTemplate;/*** 通过编程式事务来控制数据库交互:* 更新菜品代码 -> 自定义transactionTemplate来控制事务*/
public int updateDishCode(Map<String, Object> paramMap) {// 设置事务隔离级别transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);return transactionTemplate.execute(status -> {int result = 0;try {result = dishMapper.updateDish(paramMap);// int i = 1 / 0; // 模拟报错请求} catch (DataAccessException e) {LogUtil.error("MySpringBoot.updateDishCode", e.getMessage());status.setRollbackOnly();}return result;});
}

二、声明式事务(常用)

  声明式事务,通过在方法上加@Transactional注解实现,可以在注解中定义一些事务参数例如事务传播行为PROPAGATION、事务超时时间TIMEOUT、事务隔离级别ISOLATION、事务回滚条件ROLLBACKFOR

@Transactional(timeout = 30, isolation = Isolation.DEFAULT, rollbackFor = DataAccessException.class)
public int updateDishStatus(Map<String, Object> paramMap) {int result = dishMapper.updateDish(paramMap);// int i = 1 / 0; // 模拟报错请求return result;
}
PROPAGATION
PROPAGATION_REQUIRED这是事务的默认传播行为, 表示如果当前存在事务则加入该事务, 如果当前没有事务则创建一个新的事务.A->B, A如果有事务则B加入该事务(A影响B), 如果A没有则B会自己创建一个事务(B不影响A)
PROPAGATION_REQUIRES_NEW无论如何都创建一个新的事务, 如果当前存在事务则把当前事务挂起, 且开启的事务与外部事务相互独立, 互不干扰. A->B, A不影响B, 他们是两个独立的事务; B不影响A
PROPAGATION_NESTED如果当前存在事务就在当前事务中执行, 否则执行PROPAGATION_REQUIRED逻辑 A->B, A影响B, B不影响A
PROPAGATION_SUPPORTS如果当前存在事务, 则加入该事务; 如果当前没有事务, 则以非事务的方式继续运行
PROPAGATION_NOT_SUPPORTED以非事务的方式运行, 如果当前存在事务的话则把当前事务挂起
PROPAGATION_MANDATORY如果当前存在事务, 则加入该事务; 如果当前没有事务, 则抛出异常
PROPAGATION_NEVER以非事务方式运行, 如果当前存在事务, 则抛出异常

三、事务实战详解

3.1)事务的回滚机制

// 准备一个接口,一个service
@Transactional(propagation = Propagation.REQUIRED)
public int insertDishDefault() {Map<String, Object> paramMap = new HashMap<>();...int result = dishMapper.insertDishDefault(paramMap);throw new RuntimeException();
}

  查看数据库可以发现,期望的数据并没有被插入,但是切面日志表的数据是插入成功的,并且在进入该事务方法(insertDishDefault)前的其他方法操作也是成功执行的,所以事务的回滚不会影响到在它作用范围之外的sqlSession。

  仔细查看数据库中的数据变化,对比有事务控制与无事务控制的方法,会先发无事务的方法对DB的操作都是实时的(可以打断点查看),但是有事务的方法则是要等到事务提交才会影响DB,这和数据库里面的事务是一样的,Spring的底层也是用了AOP代理来完成事务控制的。

3.2)事务的传播

  Propagation属性默认是REQUIRED,事务的传播机制涉及到多种不同的情况,同时也是面试中的高频考点,下面列举几个常见的场景(下述场景均只讨论默认的事务传播机制):

  • 有事务Controller层 -> 无事务Services层

    @GetMapping("/insert")
    @Transactional(propagation = Propagation.REQUIRED)
    public int insert() {Ticket ticket = new Ticket();ticket.setDeparture("黑龙江");ticket.setDestination("广州");ticketMapper.insert(ticket);return dishServices.insertDishDefault(); // 无事务方法:插入数据,让其抛出异常
    }
    

      结果:Ticket与Dish表均插入数据失败。所以不同类中有事务的方法 -> 无事务的方法,后者会自动加入前者的事务,且它们是同一个事务,如果是前者抛异常,后者也会回滚,此处不演示。

  • 有事务Services层 -> 无事务Services层

    @Transactional(propagation = Propagation.REQUIRED)
    public int insertDishDefault() {Map<String, Object> paramMap = new HashMap<>();...testsw(); // testsw() 是同类的无事务方法:插入数据,让其抛出异常return result;
    }
    

      结果:Ticket与Dish表均插入数据失败。所以同一个类中有事务的方法 -> 无事务的方法,后者会自动加入前者的事务,且它们是同一个事务,如果是前者抛异常,后者也会回滚,此处不演示。

  • 无事务Controller层 -> 有事务Services层

    @GetMapping("/insert")
    public int insert() {Ticket ticket = new Ticket();ticket.setDeparture("黑龙江");ticket.setDestination("广州");ticketMapper.insert(ticket);return dishServices.insertDishDefault(); // 有事务方法:插入数据,让其抛出异常
    }
    

      结果:Ticket插入成功,Dish插入失败。所以不同类中无事务的方法 -> 有事务的方法,后者不会影响前者,也可以通过数据库看出来,当Controller层代码执行完之后,Tick就已经被实时插入了。如果是前者抛出异常,前者不会回滚,后者需要看无事务方法是否已经执行完毕,如果已经执行完毕则不会回滚(事务方法一旦被执行完毕就会提交)。

  • 无事务Services层 -> 有事务Services层(重要)

    // 同一个类中Dish插入无事务的方法调用有事务的方法
    @Transactional(propagation = Propagation.REQUIRED)
    public void testsw() {Ticket ticket = new Ticket();ticket.setDeparture("黑龙江");ticket.setDestination("广州");ticketMapper.insert(ticket);throw new RuntimeException(); // 同类中无事务调用该有有事务,有事务抛出异常
    }
    

      结果:Ticket与Dish均插入成功,Dish能插入成功因为其没有事务控制,实时就插入了,而Tick能插入成功是因为事务没有生效。如果是前者抛出异常,前者不会回滚,后者需要看无事务方法是否已经执行完毕,如果已经执行完毕则不会回滚(事务方法一旦被执行完毕就会提交)。

为何好端端的事务会失效?

1)Spring的事务注解@Transactional只能放在public方法上才起作用;

2)方法用final或static修饰了,用这两个关键字修饰的方法Spring无法对目标方法进行重写,因此自然也就不存在事务了;

3)如果采用spring+spring mvc,则context:component-scan重复扫描问题可能会引起事务失败;

4)数据库引擎不支持,如使用mysql且引擎是MyISAM,则事务会不起作用,原因是MyISAM不支持事务,可以改成InnoDB引擎;

5)本类中的方法互相调用,不会经过Spring的代理类,所以如果在调用方法前没有事务控制的话,调用后也是没有的(Spring事务是通过AOP代理来实现的)。

3.3)事务超时时间

  timeout属性默认是-1,不超时,在实际生产环境中一般设置为30秒、60秒,注意这个时间是所有事务的执行时间综合。

@Transactional(propagation = Propagation.REQUIRED, timeout = 5)
public int insertDishDefault() {Map<String, Object> paramMap = new HashMap<>();...try {Thread.sleep(6000); //让线程暂停6秒,而事务的回滚时间阈值是5秒} catch (InterruptedException e) {throw new RuntimeException(e);}int result = dishMapper.insertDishDefault(paramMap); // 插入失败return result;
}

3.4)事务隔离级别

  isolation属性默认是-1,表示使用数据库的隔离级别,用一个实验来测试隔离性,如下面代码所示,该查询方法可以查看未提交的事务。

@Transactional(isolation = Isolation.READ_UNCOMMITTED)
public String selectDishDefault(String dishId) {Dish dish =  dishMapper.selectDishDefault(dishId);if (dish == null) {return "没有该用户";} else {return JsonUtil.objectToJson(dish);}
}

  在第一行打上断点,然后执行一个sql插入语句不提交,实际证明该方法可以读取到我们没提交的这个sqlSession中的数据,可以用datagrip来手动提交事务:

image-20230309224709390

image-20230309224814007

3.5)事务回滚条件

  rollbackFor属性默认是空,表示捕获所有异常。指定了异常种类后,只有在出现了指定的异常才会回滚。

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = DataAccessException.class)
public int insertDishDefault() {Map<String, Object> paramMap = new HashMap<>();...int result = dishMapper.insertDishDefault(paramMap);try {int i = 1/0; // 会抛出ArithmeticException异常,但不是回滚的异常条件,数据插入成功} catch (ArithmeticException e) {e.printStackTrace();}return result;
}

相关文章:

Spring事务介绍

文章目录一、编程式事务二、声明式事务&#xff08;常用&#xff09;三、事务实战详解3.1&#xff09;事务的回滚机制3.2&#xff09;事务的传播3.3&#xff09;事务超时时间3.4&#xff09;事务隔离级别3.5&#xff09;事务回滚条件Spring中对事务有两种支持方式&#xff0c;分…...

Intellij Idea如何使用VM

打开Run/Debug Configuration 然后在More option 里选择 add VM options 根据要实现的目的选择main class 比如说要建造class diagram 那就选择app.ClassDiagramGenerator 然后在下面那行输入 D:\software-engineering\2023\commons-compress\target\classes true true org.apa…...

基础04-什么时候不能使用箭头函数

箭头函数的缺点 题目 什么时候不能使用箭头函数&#xff1f; 箭头函数的缺点 没有 arguments const fn1 () > {console.log(this, arguments) // 报错&#xff0c;arguments is not defined } fn1(100, 200)无法通过 call apply bind 等改变 this const fn1 () >…...

算法小抄5-原地哈希

书接上回,学会了数组中重复数字的解法三,相信接下来的题也难不倒你 找到数组中消失的数字 题目链接 题意 对于一个大小为n的数组,数组中所有的数都在[1,n]内,其中有些数字重复了,由于有些数字重复了,另一些数字就一定会确实,这次需要找到所有缺少的数字并且返回结果 有没有发…...

java零基础入门(1)

java零基础入门一、JRE和JDK1.1 JRE1.2 JDK1.3 IDK&#xff0c;JRE&#xff0c;JVM三者的包含关系二、CMD2.1 打开CMD2.2 常用CMD命令2.2.1 盘符名称 冒号2.2.2 dir2.2.3 cd 目录2.2.4 cd ..2.2.5 cls2.2.6 exit2.2.7 cd \2.2.8 cd \目录\目录\目录\目录2.3 利用快捷cmd打开 Q…...

java socket实例

/*** 启动项目后就创建Server Socket服务*/PostConstructpublic void runServerSocket() {try {ExecutorService executorService Executors.newFixedThreadPool(10);// 创建线程池ServerSocket serverSocket new ServerSocket(9090);// 在设备上配置的服务端监听端口为9090e…...

计算机中信息的表示和处理 整数和小数的二进制表示

信息的表示和处理整数进制字移位运算无符号数和有符号数加法运算小数定点表示IEEE 浮点表示规格化和非规格化舍入浮点运算现代计算机存储和处理的信息以二值信号表示&#xff0c;这些二进制数字称为位&#xff0c;为什么要用二进制来进行编码&#xff1f;因为二进制只有1和0两种…...

Chapter2.2:线性表的顺序表示

该系列属于计算机基础系列中的《数据结构基础》子系列&#xff0c;参考书《数据结构考研复习指导》(王道论坛 组编)&#xff0c;完整内容请阅读原书。 2.线性表的顺序表示 2.1 顺序表的定义 线性表的顺序存储亦称为顺序表&#xff0c;是用一组地址连续的存储单元依次存储线性表…...

老马闲评数字化「4」做数字化会不会被供应商拿捏住

原文作者&#xff1a;行云创新CEO 马洪喜 导语 开年过后业务特别的繁忙&#xff0c;出差也比较多&#xff0c;所以有段时间没更新了&#xff0c;对不住大家&#xff01; 上一集&#xff08;您可以查看“行云创新”主页阅读原文&#xff09;咱们聊了数字化转型的“想转、急转、…...

robosuite添加无碰撞的模型

1 前言 最近在使用robosuite时,需要在仿真环境中可视化物体的目标位置,从而方便观察训练情况,可视化的物体有以下要求: 形状尺寸与操作的物体一样半透明只有visual,不与场景其他物体有碰撞可以在每次step后设置位置,且固定在设定的位置,不受重力影响 2 方法 找了半天,最终确…...

JS学习笔记day03

今日内容 零、 复习昨日 CSS 美化,复用,样式文件和表现文件分离便于维护 选择器 {属性:值;…} 引入css 内联文件内部使用style标签外部文件 <link href"路径" rel"stylesheet" type"text/css"> 选择器 基本 idclass标签名 属性 标签名…...

离散数学笔记_第一章:逻辑和证明(3)

1.3 命题等价式1.3.1 逻辑等价式 1.3.2 条件命题和双条件命题的逻辑等价式 1.3.3 德摩根律 1.3.4 可满足性 可满足的 不可满足的 可满足性问题的解 1.3.5析取范式&#xff08;基本积之和&#xff09;&#xff0c;合取范式&#xff08;基本和之积&#xff09;1.3.6合式公式1…...

软件测试分类知识分享,第三方软件测试机构收费贵不贵?

软件测试可以很好的检验软件产品的质量以及规避产品上线之后可能会发生的错误&#xff0c;随着技术的发展&#xff0c;软件测试已经是一个完整且体系庞大的测试活动&#xff0c;不同的测试领域有着不同的测试方法、技术与名称&#xff0c;那么具体有哪些分类呢? 一、软件测试…...

爬虫(二)解析数据

文章目录1. Xpath2. jsonpath3. BeautifulSoup4. 正则表达式4.1 特殊符号4.2 特殊字符4.3 限定符4.3 常用函数4.4 匹配策略4.5 常用正则爬虫将数据爬取到后&#xff0c;并不是全部的数据都能用&#xff0c;我们只需要截取里面的一些数据来用&#xff0c;这也就是解析爬取到的信…...

【C++、C++11】可变参数模板、lambda表达式、包装器

文章目录&#x1f4d6; 前言1. 可变参数模板1.1 万能模板&#xff1a;1.2 完美转发&#xff1a;1.3 可变参数模板的使用&#xff1a;1.4 emplace_back&#xff1a;2. lambda表达式2.1 lambda表达式的定义&#xff1a;2.2 lambda表达式的用法&#xff1a;2.2 - 1 捕捉列表的用法…...

外贸主机测评

一、俄罗斯vps 服务商&#xff1a; JUSTG: Home - Sun Network Company Limited LOCVPS: LOCVPS 全球云 - 十年老牌 为跨境外贸/远程办公/网站建设提供澎湃动力 JUSTHOST: justhost.ru RUVDS: Gcorelabs: 二、主机测评指标&#xff1a; 1、速度、延迟、丢包、路由测试…...

Meta CTO:Quest 2生命周期或比预期更久

前不久&#xff0c;Meta未来4年路线图遭曝光&#xff0c;泄露了该公司正在筹备中的一些AR/VR原型。除此之外&#xff0c;还有消息称Quest Pro或因销量不佳&#xff0c;而不再迭代。毫无疑问&#xff0c;Meta的一举一动持续受到行业关注&#xff0c;而面对最近的爆料&#xff0c…...

Vector - CAPL - 文件处理函数

在当前平台化的趋势下,就算是协议层测试依然需要适配各种各样的项目,也需要处理各类型的文件,那我们如何对文件进行读取、写入、修改等类型的操作呢?今天我们就会介绍此类型的函数,主要适用于text、bin文件的处理。 打开文件 Open...

实力加持!RestCloud完成多方国产化适配,携手共建信创生态

近年来&#xff0c;随着数字化建设进入深水区&#xff0c;企事业单位对信息安全重视程度与日俱增&#xff0c;核心技术自主可控已成为时代呼唤&#xff0c;国产化浪潮日益汹涌澎湃。近日&#xff0c;RestCloud在国产化方面取得新进展&#xff0c;完成了全部产品线信创环境的多方…...

Unity 3D GUI教程||OnGUI TextArea 控件||OnGUI ScrollView 控件

OnGUI TextArea 控件 Unity 3D TextArea 控件用于创建一个多行的文本编辑区。用户可以在多行文本编辑区编辑文本内容。 该控件可以对超出控件宽度的文本内容实现换行操作。 TextArea 控件同样会将当前文本编辑区中的文本内容以字符串形式返回。 开发人员可以通过创建 Strin…...

Golang错误处理实战:defer、panic和recover的正确打开方式(附避坑指南)

Golang错误处理实战&#xff1a;defer、panic和recover的正确打开方式&#xff08;附避坑指南&#xff09; 在Golang的世界里&#xff0c;错误处理是一门艺术。与传统的try-catch机制不同&#xff0c;Go采用了独特的defer-panic-recover组合拳。这种设计哲学体现了Go语言"…...

NsEmuTools:开源模拟器管理工具的质量保障与工程实践

NsEmuTools&#xff1a;开源模拟器管理工具的质量保障与工程实践 【免费下载链接】ns-emu-tools 一个用于安装/更新 NS 模拟器的工具 项目地址: https://gitcode.com/gh_mirrors/ns/ns-emu-tools 在开源项目的生命周期中&#xff0c;如何在快速迭代与代码质量之间找到平…...

Rainmeter皮肤模板循环控制:break/continue实现终极指南

Rainmeter皮肤模板循环控制&#xff1a;break/continue实现终极指南 【免费下载链接】rainmeter Desktop customization tool for Windows 项目地址: https://gitcode.com/gh_mirrors/ra/rainmeter Rainmeter作为一款强大的Windows桌面自定义工具&#xff0c;其皮肤模板…...

5分钟搞定OpenClaw+nanobot:超轻量级AI助手一键部署指南

5分钟搞定OpenClawnanobot&#xff1a;超轻量级AI助手一键部署指南 1. 为什么选择OpenClawnanobot组合 上周我在整理电脑上的项目文档时&#xff0c;突然意识到自己每天要重复执行大量机械操作&#xff1a;查找文件、转换格式、汇总数据。作为独立开发者&#xff0c;这些琐事…...

从逻辑门到CPU:计算机工作原理详解

戏说CPU的工作原理&#xff1a;从逻辑门到计算系统1. 计算系统的基本构建单元1.1 逻辑门的物理实现计算系统最基本的构建单元是逻辑门&#xff0c;它们可以通过简单的物理实体来演示。以三名士兵为例&#xff0c;我们可以构建最基本的逻辑运算单元&#xff1a;输入单元&#xf…...

stm32开发新手福音:告别复杂安装,用快马ai生成带详解的hal库基础代码

作为一名刚接触STM32开发的新手&#xff0c;我最近在尝试用HAL库控制GPIO时遇到了不少麻烦。从下载安装STM32CubeMX到配置工程&#xff0c;每一步都让我这个小白手忙脚乱。直到发现了InsCode(快马)平台&#xff0c;整个过程变得简单多了——不需要自己搭建环境&#xff0c;AI就…...

零代码玩转OpenClaw:ollama-QwQ-32B自动化脚本生成教程

零代码玩转OpenClaw&#xff1a;ollama-QwQ-32B自动化脚本生成教程 1. 为什么选择OpenClawollama-QwQ-32B组合&#xff1f; 上周我在整理旅行照片时&#xff0c;面对上千张命名混乱的图片文件&#xff0c;突然意识到&#xff1a;这不正是测试OpenClaw自动化能力的绝佳场景吗&…...

2024版idea引入lombok总是报错解决方法

在创建SpringBoot文件时不勾选lombok&#xff0c;然后自己手动导入lombok并指定版本玛德这idea的SpringBoot中导入lombok后我使用Data总是说我的get和set方法有毛病&#xff0c;一怒之下我直接就是疯狂搜如何解决lombok引用问题&#xff0c;结果不是让我去勾选一个东西就是让我…...

Docker+iredmail搭建企业级邮件服务器全流程(附常见问题排查)

Dockeriredmail搭建企业级邮件服务器全流程指南 邮件系统作为企业日常沟通的核心基础设施&#xff0c;其稳定性和安全性直接影响业务运转效率。传统邮件服务器部署往往需要复杂的配置和漫长的调试周期&#xff0c;而Docker容器化技术结合iredmail开源邮件解决方案&#xff0c;为…...

光场相机入门:Macro Pixel与SAI如何让你的照片秒变3D(附Python代码示例)

光场相机实战指南&#xff1a;用Macro Pixel与SAI技术打造沉浸式3D影像 当你第一次看到光场相机拍摄的照片能在屏幕上自由切换焦点时&#xff0c;那种震撼感就像发现了摄影的新维度。这背后是Macro Pixel和SAI两项核心技术的完美配合——它们让静态图像拥有了动态的视角选择能力…...