Spring事务和事务传播机制(@Transactional)

news2024/11/17 11:31:32

文章目录

  • Spring事务(@Transactional详解)
    • 什么是事务
      • 为什么需要事务
      • 事务的操作(sql)
    • Spring中的事务实现
    • Spring编程式事务
    • Spring声明式事务 @Transactional
      • @Transactional可以用来修饰方法或类
      • 对异常进行捕获细节:
    • @Transactional详解
      • 三个属性
        • 1. rooback
        • 2. Isolation
          • 事务的隔离级别:
            • MySQL事务隔离级别
            • Spring事务隔离级别
        • 3. propagation
          • 什么是事务传播机制
          • 传播机制有哪些

Spring事务(@Transactional详解)

什么是事务

为什么需要事务

转账操作:
第一步:A账户 -100元
第二步:B账户 +100元

如果没有事务,第一步执行成功了,第二步执行失败了,那么A账户的100元就平白无故的消失了.

秒杀系统
第一步:下单成功
第二步:扣减库存

下单成功后,库存要么同步减少,要么扣减失败,所以得把这两个操作放在同一个事务中,要么一起成功,要么一起失败

事务的操作(sql)

  1. 开启事务“start transaction /begin(一组操作前开启事务)
  2. 提交事务:commit(这组操作全部成功,提交事务)
  3. 回滚事务:rollback(这组操作中间的任何一个操作出现异常,回滚事务)
--开启事务
start transaction;

--提交事务
commit;

--回滚事务
rollback;

Spring中的事务实现

  • 编程式事务(手动写代码操作事务)
  • 声明式事务(通过注解自动开启和提交事务)

Spring编程式事务

1.在controller 层 @Autowired 注入事务管理器
2.开启事务
3.提交事务

package com.example.mybatisdemo.controller;

import com.example.mybatisdemo.model.User;
import com.example.mybatisdemo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 手动提交事务
 */
@Slf4j
@RequestMapping("/trans")
@RestController
public class TransactionController {

    @Autowired
    private UserService userService;

    //获取数据库事务管理器
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;
    //数据库事务默认配置
    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/addUser")
    public Integer addUser(String username,String password){
        //获取一个事务
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);
        User user=new User(username,password);
        Integer result = userService.insert(user);
        log.info("影响行数:"+result);
        //回滚到transaction状态
        //dataSourceTransactionManager.rollback(transaction);
        //事务提交
        dataSourceTransactionManager.commit(transaction);
        return  result;
    }
}



 

Spring声明式事务 @Transactional

@Transactional可以用来修饰方法或类

  • 修饰方法时:只有修饰public方法时才生效,修饰其他方法时不会报错,也不生效

  • 修饰类时:对改类的所以public修饰的方法都生效
    执行流程 :被@Transactional修饰时,在目标方法开始执行之前,会自动开启事务,方法执行结束之后,自动提交事务。
    如果在方法执行过程中,出现异常,而且异常未被捕获,就会进行回滚操作
    如果异常被程序捕获,方法就被认为是执行成功,依然会提交事务

    请添加图片描述

对异常进行捕获细节:

@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
 //⽤⼾注册
 	userService.registryUser(name,password);
 	log.info("⽤⼾数据插⼊成功");
 //对异常进⾏捕获
 	try {
 //制造程序抛出异常
 	int a = 10/0;
 }catch (Exception e){
	 e.printStackTrace();
 }
 	return "注册成功";
}

上述例子,因为程序被捕获了,所以事务依然可以提交

如果需要事务进行回滚:

  1. 重新抛出异常
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
 //⽤⼾注册
 	userService.registryUser(name,password);
 	log.info("⽤⼾数据插⼊成功");
 //对异常进⾏捕获
 	try {
 //制造程序抛出异常
 	int a = 10/0;
 }catch (Exception e){
	 //将异常重新抛出去
	 throw e;
 }
 	return "注册成功";
}
  1. 手动回滚事务
@Transactional
@RequestMapping("/registry")
public String registry(String name,String password){
 //⽤⼾注册
 	userService.registryUser(name,password);
 	log.info("⽤⼾数据插⼊成功");
 //对异常进⾏捕获
 	try {
 //制造程序抛出异常
 	int a = 10/0;
 }catch (Exception e){
 //手动回滚事务
	  TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
 }
 	return "注册成功";
}

@Transactional详解

三个属性

1. rooback

异常回滚属性.指定能够触发事务回滚的异常类型。可以指定多个异常
在这里插入图片描述
@Transactional 只有运行时异常和Error才能进行回滚

需要所有异常都回滚, 需要来配置 @Transactional 注解当中的 rollbackFor 属性, 通
过 rollbackFor 这个属性指定出现何种异常类型时事务进⾏回滚

Transactional(rollbackFor = Exception.class)
@RequestMapping("/r2")
public String r2(String name,String password) throws IOException {
 //⽤⼾注册
     userService.registryUser(name,password);
     log.info("⽤⼾数据插⼊成功");
     if (true){
 		throw new IOException();
  }
   return "r2";
  }
2. Isolation
事务的隔离级别:
MySQL事务隔离级别
  1. 读未提交(READ UNCOMMITTED): 读未提交, 也叫未提交读. 该隔离级别的事务可以看到其他事务中
    未提交的数据.
    因为其他事务未提交的数据可能会发⽣回滚, 但是该隔离级别却可以读到, 我们把该级别读到的数
    据称之为脏数据, 这个问题称之为脏读.
  2. 读提交(READ COMMITTED): 读已提交, 也叫提交读. 该隔离级别的事务能读取到已经提交事务的数
    据,
    该隔离级别不会有脏读的问题.但由于在事务的执⾏中可以读取到其他事务提交的结果, 所以在不
    同时间的相同 SQL 查询可能会得到不同的结果, 这种现象叫做不可重复读
  3. 可重复读(REPEATABLE READ): 事务不会读到其他事务对已有数据的修改, 即使其他事务已提交. 也
    就可以确保同⼀事务多次查询的结果⼀致, 但是其他事务新插⼊的数据, 是可以感知到的. 这也就引
    发了幻读问题. 可重复读, 是 MySQL 的默认事务隔离级别.
    ⽐如此级别的事务正在执⾏时, 另⼀个事务成功的插⼊了某条数据, 但因为它每次查询的结果都是
    ⼀样的, 所以会导致查询不到这条数据, ⾃⼰重复插⼊时⼜失败(因为唯⼀约束的原因). 明明在事务
    中查询不到这条信息,但⾃⼰就是插⼊不进去,这个现象叫幻读
  4. 串⾏化(SERIALIZABLE): 序列化, 事务最⾼隔离级别. 它会强制事务排序, 使之不会发⽣冲突, 从⽽解
    决了脏读, 不可重复读和幻读问题, 但因为执⾏效率低, 所以真正使⽤的场景并不多.
Spring事务隔离级别

Spring 中事务隔离级别有5 种:

  1. Isolation.DEFAULT : 以连接的数据库的事务隔离级别为主.
  2. Isolation.READ_UNCOMMITTED : 读未提交, 对应SQL标准中 READ UNCOMMITTED
  3. Isolation.READ_COMMITTED : 读已提交,对应SQL标准中 READ COMMITTED
  4. Isolation.REPEATABLE_READ : 可重复读, 对应SQL标准中 REPEATABLE READ
  5. Isolation.SERIALIZABLE : 串⾏化, 对应SQL标准中 SERIALIZABLE
Transactional(isolation = Isolation.READ_COMMITTED)
@RequestMapping("/r3")
public String r3(String name,String password) throws IOException {
 //... 代码省略
 return "r3";
}
3. propagation

事务的传播机制

什么是事务传播机制

事务传播机制就是:多个事务方法存在调用关系时,事务是如何在这些方法间进行传播的。

比如两个方法A,B都被@Transactional修饰

  • A方法运行时,开启一个事务,当A调用B时,B方法本身也有事务
  • 此时B方法运行时,是加入A的事务,还是创建一个新的事务呢?
    这就设计到事务的传播机制
传播机制有哪些

Transactional 注解⽀持事务传播机制的设置, 通过 propagation 属性来指定传播⾏为.
Spring 事务传播机制有以下 7 种:

  1. Propagation.REQUIRED : 默认的事务传播级别. 如果当前存在事务, 则加⼊该事务. 如果当前没
    有事务, 则创建⼀个新的事务.
  2. Propagation.SUPPORTS : 如果当前存在事务, 则加⼊该事务. 如果当前没有事务, 则以⾮事务的
    ⽅式继续运⾏.
  3. Propagation.MANDATORY :强制性. 如果当前存在事务, 则加⼊该事务. 如果当前没有事务, 则
    抛出异常.
  4. Propagation.REQUIRES_NEW : 创建⼀个新的事务. 如果当前存在事务, 则把当前事务挂起. 也
    就是说不管外部⽅法是否开启事务, Propagation.REQUIRES_NEW 修饰的内部⽅法都会新开
    启⾃⼰的事务, 且开启的事务相互独⽴, 互不⼲扰.
  5. Propagation.NOT_SUPPORTED : 以⾮事务⽅式运⾏, 如果当前存在事务, 则把当前事务挂起(不
    ⽤).
  6. Propagation.NEVER : 以⾮事务⽅式运⾏, 如果当前存在事务, 则抛出异常.

比如⼀对新⼈要结婚了, 关于是否需要房⼦

  1. Propagation.REQUIRED : 需要有房⼦. 如果你有房, 我们就⼀起住, 如果你没房, 我们就⼀起
    买房. (如果当前存在事务, 则加⼊该事务. 如果当前没有事务, 则创建⼀个新的事务)
  2. Propagation.SUPPORTS : 可以有房⼦. 如果你有房, 那就⼀起住. 如果没房, 那就租房. (如果
    当前存在事务, 则加⼊该事务. 如果当前没有事务, 则以⾮事务的⽅式继续运⾏)
  3. Propagation.MANDATORY : 必须有房⼦. 要求必须有房, 如果没房就不结婚. (如果当前存在事
    务, 则加⼊该事务. 如果当前没有事务, 则抛出异常)
  4. Propagation.REQUIRES_NEW : 必须买新房. 不管你有没有房, 必须要两个⼈⼀起买房. 即使
    有房也不住. (创建⼀个新的事务. 如果当前存在事务, 则把当前事务挂起)
  5. Propagation.NOT_SUPPORTED : 不需要房. 不管你有没有房, 我都不住, 必须租房.(以⾮事务
    ⽅式运⾏, 如果当前存在事务, 则把当前事务挂起)
  6. Propagation.NEVER : 不能有房⼦. (以⾮事务⽅式运⾏, 如果当前存在事务, 则抛出异常)
  7. Propagation.NESTED : 如果你没房, 就⼀起买房. 如果你有房, 我们就以房⼦为根据地,做点下
    ⽣意. (如果如果当前存在事务, 则创建⼀个事务作为当前事务的嵌套事务来运⾏. 如果当前没有事
    务, 则该取值等价于 PROPAGATION_REQUIRED )

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

思科模拟器学习1--Vlan Trunk

实验说明:将三台电脑的vlan 加到一台交换机里面,为了验证什么是虚拟局域网,把一个设备隔成三个空间,三个电脑互相不能通讯;目的是:vlan 1的通讯不可以向vlan 2传送,就是消息传送互不干扰的&…

node安装以及node的包管理工具

node安装以及node的包管理工具 node安装nvm管理工具 node安装 1、下载node链接: 点击这里 2、选择需要下载的版本以及对应的系统版本 nvm管理工具 1、下载nvm链接: 点击这里 2、双击运行.exe文件 全部默认安装即可 3、nvm常用命令 nvm list avaliable 显示所有可以下载的n…

QT——tableWidget-跳变之舞V1.0-记录学习【1】

QT——tableWidget-跳变之舞V1.0-记录学习【1】 文章目录 QT——tableWidget-跳变之舞V1.0-记录学习【1】前言一、利用QT创建项目文件1.1 完整项目文件如下图所示:1.2 演示: 二、声明文件:2.1 主界面声明文件:mainwindow.h;2.2 控制窗口声明文…

USB3.0接口——(3)协议层(包格式)

1.协议层 1.1.超高速传输事务 超高速事务(SuperSpeed transactions)由主机对设备端点请求或发送数据开始,并在端点发送数据或确认收到数据时完成。 超高速总线上的数据传输(transfer)是主机请求设备应用程序生成的数…

76岁林子祥升级做爷爷,亲自为孙女取名

林子祥与前妻吴正元的儿子,现年39岁的林德信入行以来绯闻不少,自与圈外女友Candace拍拖后便修心养性,去年他已经低调与拍拖5年多Candace完婚,正式步入人生另一阶段。 昨日(5月12日)林德信借母亲节这个温馨日…

如何在控制台应用程序里面托管ASP.NET Core网站

目录 介绍运行效果开发环境项目结构第三方库引用编写代码介绍 本文如何不通过IIS,使用控制台程序作为宿主主机来运行我们的asp.net core开发的网站程序。通过改案例你也可以后期通过winform或者wpf作为宿主来运行我们的asp.net core开发的网站。 运行效果 开发环境 vs2022+.…

2024年5月面试准备

2024年5月面试准备 资料来源Java基础泛型注解异常反射SPI机制Java集合CollectionMap 并发基础线程并发关键字并发集合Lock核心类并发集合核心类原子类核心类线程池核心类ScheduledThreadPoolExecutorForkJoinPoolFokJoinTask JUC原子类: CAS, Unsafe和原子类详解JUC 工具类 Jav…

【打字】打字训练之针对性键盘区域练习

本文章的核心点是:使用代码生成自己想要训练的键位的词汇,然后导入到打字软件针对性练习 一个程序员突然想纠正打字习惯源于腱鞘炎,虽然使用双拼打字已经不慢了,但是姿势不是很正确,导致了腱鞘炎。 所以想着好好纠正指…

odoo16 银行对账单导入改造

解决问题: odoo原生功能的话 是不能在系统上临时处理文件内容的,只会提示文件内容格式不对。 原始文件格式 在头部与尾部 格式问题,例如csv文件和 C53 文件,做一个前置弹框处理数据之后再导入 camt效果: csv效果:

bugfix:遇见“隐形字符”:ⅰ与i的编码迷局

前言 在软件开发的世界里,遇到各种奇奇怪怪的bug是在所难免的。今天,我就遭遇了一个看似简单实则棘手的问题——用户反馈账号无法登录,系统一直提示“账号不存在”。一番抽丝剥茧后,我发现问题竟然出在一个不起眼的字符上&#x…

xFormers

文章目录 一、关于 xFormers二、安装 xFormers三、基准测试(可选)测试安装 四、使用 xFormers1、Transformers 关键概念2、Repo 地图注意力机制Feed forward mechanismsPositional embeddingResidual pathsInitializations 3、主要特征4、安装故障排除 一…

小红书自动私信获客,打造个人品牌

在当今这个内容为王、社交至上的时代,小红书作为新兴的社交电商平台,凭借其独特的社区氛围和强大的种草能力,成为了众多KOL、商家以及个人品牌打造的首选平台。想要在小红书上脱颖而出,精准引流获客,利用自动私信功能不…

Ajax额

原生Ajax xml 已被json取代 http 请求方法urlhttp版本号 network 谷歌浏览器查看请求报文和响应报文 F12 network header里面有 请求头 响应头 点击view source 可以查看请求响应行 请求体在请求行头下面 get请求有url参数,请求体变为query String…

汇昌联信科技:拼多多电商的运营流程有哪些?

在当今互联网高速发展的时代,电商平台层出不穷,其中拼多多以其独特的团购模式和低价策略迅速崛起,成为众多消费者和商家的新宠。那么,拼多多电商的运营流程究竟包含哪些环节呢?接下来,我们将从商品上架、营销推广、订…

基于PySpark进行去哪儿网数据分析

基于PySpark进行去哪儿网数据分析 本文介绍了如何使用PySpark对去哪儿网的数据进行分析,从而洞察用户偏好、热门目的地以及销售趋势。 1.数据加载 我们需要确保已经准备好了PySpark的开发环境,并且准备好了去哪儿网的数据集。可以通过创建SparkSessio…

vue cmd执行报错 ‘vue‘ 不是内部或外部命令

使用vue脚手架快速搭建项目,在cmd中执行:vue init webpack vue-demo,报错: vue 不是内部或外部命令,也不是可运行的程序 或批处理文件。 解决方法,执行如下的命令 npm config list 注意:找到prefix等号后…

在Ubuntu命令行中一行代码配置C++的OpenCV库

本文介绍在Linux操作系统的Ubuntu版本中,配置C 语言环境下的计算机视觉库OpenCV的方法。 首先,为了保证我们可以在Ubuntu中正确配置OpenCV库,需要使得计算机内具有C 开发环境。其中,在Ubuntu中,我们可以基于命令行方便…

第16节 实战:文件转shellcode

我最近做了一个关于shellcode入门和开发的专题课👩🏻‍💻,主要面向对网络安全技术感兴趣的小伙伴。这是视频版内容对应的文字版材料,内容里面的每一个环境我都亲自测试实操过的记录,有需要的小伙伴可以参考…

在微信小程序项目中安装和使用 Vant 组件库

vant Wwapp 小程序开发组件库官网 Vant Weapp - 轻量、可靠的小程序 UI 组件库 安装 Vant 组件库 1.在微信小程序项目文件目录的空白位置右键,选择在外部终端窗口中打开 2在命令行输入如下命令(在项目中创建包管理配置文件 package.json) …

PHP 自提时间

前端: 后台设置: 代码: public function getBusinessHour(){// 需求单门店$data (new StoreModel())->limit(1)->select()->toArray();$days explode(,, $data[0][shop_hours]);$businessHours $days[1];// 使用 explode 分割字符串,获取开始和结束时…