【Spring】Spring事务和事务传播机制

【Spring】Spring事务和事务传播机制

🎬 那我掉的头发算什么个人主页
🔥 个人专栏: 《javaSE》《数据结构》《数据库》《javaEE》

⛺️待到苦尽甘来日


在这里插入图片描述

文章目录

事务三连

什么是事务

事务是⼀组操作的集合, 是⼀个不可分割的操作.
事务会把所有的操作作为⼀个整体, ⼀起向数据库提交或者是撤销操作请求. 所以这组操作要么同时成功, 要么同时失败.

为什么要有事务

我们在进行程序开发时,也会有事务的需求。
比如转账操作:
第一步:A 账户 -100 元。
第二步:B 账户 +100 元。

如果没有事务,第一步执行成功了,第二步执行失败了,那么 A 账户的 100 元就平白无故消失了。如果使用事务就可以解决这个问题,让这一组操作要么一起成功,要么一起失败。

事务的操作

事务的操作主要有三步:
开启事务:start transaction /begin(一组操作前开启事务)
提交事务:commit(这组操作全部成功,提交事务)
回滚事务:rollback(这组操作中间任何一个操作出现异常,回滚事务)

Spring中事务的实现

Spring 中的事务操作分为两类:
编程式事务(手动写代码操作事务)。
声明式事务(利用注解自动开启和提交事务)。

准备工作

我们先准备好数据以及访问数据的代码:

整体结构:

在这里插入图片描述


数据库:
log_info:

在这里插入图片描述


user_info:

在这里插入图片描述

Spring编程事务

packagecom.hbu.springtransdemo.controller;importcom.hbu.springtransdemo.service.UserInfoService;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.jdbc.datasource.DataSourceTransactionManager;importorg.springframework.transaction.TransactionDefinition;importorg.springframework.transaction.TransactionStatus;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;@RestController@Slf4j@RequestMapping("/User")publicclassUserController{@AutowiredprivateUserInfoService userInfoService;@AutowiredprivateDataSourceTransactionManager dataSourceTransactionManager;privateTransactionDefinition transactionDefinition;@RequestMapping("/regist")publicStringregistryUser(String name,String password){TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);Integer result = userInfoService.registryUser(name, password); log.info("用户信息插入成功");//提交事务 dataSourceTransactionManager.commit(transactionStatus);//回滚事务//dataSourceTransactionManager.rollback(transactionStatus);return"注册成功";}}
在这里插入图片描述


提交事务时,数据库中也会增加相应的记录。
回滚事务时,可以看到日志打印的信息:“用户信息插入成功”以及“注册成功”,但是刷新数据库没有增加相应的新纪录。

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

Spring 声明式事务 @Transactional

在需要事务的方法上添加 @Transactional 注解就可以实现了。无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没有处理的异常会自动回滚事务。

代码也是十分简洁:

packagecom.hbu.springtransdemo.controller;importcom.hbu.springtransdemo.service.UserInfoService;importlombok.extern.slf4j.Slf4j;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.jdbc.datasource.DataSourceTransactionManager;importorg.springframework.transaction.TransactionDefinition;importorg.springframework.transaction.TransactionStatus;importorg.springframework.transaction.annotation.Transactional;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RestController;importjava.io.IOException;importstaticorg.springframework.transaction.annotation.Isolation.READ_COMMITTED;@RestController@Slf4j@RequestMapping("/User2")publicclassUserController2{@AutowiredprivateUserInfoService userInfoService;@Transactional()@RequestMapping("/regist")publicStringregistryUser(String name,String password)throwsIOException{Integer result = userInfoService.registryUser(name, password); log.info("用户信息插入成功");return"注册成功";}}

运行程序,数据插入成功。

反之,如果出现异常:

@RestController@Slf4j@RequestMapping("/User2")publicclassUserController2{@AutowiredprivateUserInfoService userInfoService;@Transactional()@RequestMapping("/regist")publicStringregistryUser(String name,String password)throwsIOException{Integer result = userInfoService.registryUser(name, password); log.info("用户信息插入成功");int a =10/0;return"注册成功";}}

代码就会回滚,数据没法正常插入数据库。

@Transactional 可以用来修饰方法或类:
・修饰方法时:只有修饰 public 方法时才生效(修饰其他方法时不会报错,也不生效)【推荐】
・修饰类时:对 @Transactional 修饰的类中所有的 public 方法都生效

方法 / 类被 @Transactional 注解修饰时,在目标方法执行开始之前,会自动开启事务,方法执行结束之后,自动提交事务。如果在方法执行过程中,出现异常,且异常未被捕获,就进行事务回滚操作。如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务。

在这里插入图片描述


特别的,@Transactional 默认只在遇到运行时异常和 Error 时才会回滚,非运行时异常不回滚。即 Exception 的子类中,除了 RuntimeException 及其子类。

@Transactional详解

通过上面的代码,我们学习了 @Transactional 的基本使用。接下来我们学习 @Transactional 注解的使用细节。

我们主要学习 @Transactional 注解当中的三个常见属性:
1.rollbackFor:异常回滚属性。指定能够触发事务回滚的异常类型。可以指定多个异常类型
2.Isolation:事务的隔离级别。默认值为 Isolation.DEFAULT
3.propagation:事务的传播机制。默认值为 Propagation.REQUIRED

rollbackFor

前面说了,@Transactional 默认只在遇到运行时异常和 Error 时才会回滚,非运行时异常不回滚。

在这里插入图片描述
@Transactional(rollbackFor)@RequestMapping("/regist")publicStringregistryUser(String name,String password)throwsIOException{Integer result = userInfoService.registryUser(name, password); log.info("用户信息插入成功");// int a = 10/0;// try{// int a = 10/0;// }catch (Exception e){// //e.printStackTrace();// }if(true){thrownewIOException();}return"注册成功";}

在上面这种情况下虽然产生异常报错,但是不会产生回滚,数据依旧正常插入数据库。

在这里插入图片描述


此时我们就可以给rollbackFor指定一个回滚的范围,比如此处设置成所有异常类,再运行上面的代码就能正常回滚了。

事务隔离级别

Mysql事务隔离级别

SQL 标准定义了四种隔离级别,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 =READ_COMMITTED)@RequestMapping("/r1")publicStringr1(String name,String password){return"r1";}

可以根据isolation属性的赋值来设置隔离级别。

Spring事务传播机制

事务传播机制就是:多个事务方法存在调用关系时,事务是如何在这些方法间进行传播的。
比如有两个方法 A、B 都被 @Transactional 修饰,A 方法调用 B 方法。A 方法运行时,会开启一个事务。当 A 调用 B 时,B 方法本身也有事务,此时 B 方法运行时,是加入 A 的事务,还是创建一个新的事务呢?
这个就涉及到了事务的传播机制。

在这里插入图片描述


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:以非事务方式运行,如果当前存在事务,则抛出异常。
7.Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。

接下来我们来演示一下其中几个场景:
1.都使用默认传播机制:

@Transactional@RequestMapping("/r2")publicStringr2(String name,String password){ userInfoService.registryUser(name,password); log.info("新建用户成功"); logInfoService.insert(); log.info("新建日志成功");return"成功!!!";}
packagecom.hbu.springtransdemo.service;importcom.hbu.springtransdemo.mapper.UserInfoMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Propagation;importorg.springframework.transaction.annotation.Transactional;@ServicepublicclassUserInfoService{@AutowiredprivateUserInfoMapper userInfoMapper;@Transactional(propagation =Propagation.REQUIRED)publicIntegerregistryUser(String name,String password){return userInfoMapper.insert(name,password);}}
packagecom.hbu.springtransdemo.service;importcom.hbu.springtransdemo.mapper.LogInfoMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Propagation;importorg.springframework.transaction.annotation.Transactional;@ServicepublicclassLogInfoService{@AutowiredprivateLogInfoMapper logInfoMapper;@Transactional(propagation =Propagation.REQUIRED)publicIntegerinsert(){Integer result = logInfoMapper.insert("zhangsan","新建用户");return result;}}

结构类似于:

在这里插入图片描述


因为本身r2就是事务,所以那两个事务会和r2一起成为一个事务。
此时如果有任意一个事务发生回滚操作,就被认定这个合成的大事务产生回滚,所以整个事务都回滚,每一个事务操作都不生效。
当然,正常提交时大家也是都提交。

2.REQUIRES_NEW:

在这里插入图片描述


此时几个事务是独立的,每一个事务提交还是回滚与其他事务无关。

3.NESTED

在这里插入图片描述


跟REQUIRED类似,当主事务回滚,所有事务都回滚。
但是NESTED允许局部回滚,即调用的小事务回滚,其他的事务可以正常提交。

在这里插入图片描述

总结

1.Spring 中使用事务,有两种方式:编程式事务(手动操作)和声明式事务。其中声明式事务使用较多,在方法上添加 @Transactional 就可以实现了。
2.通过 @Transactional (isolation = Isolation.SERIALIZABLE) 设置事务的隔离级别。Spring 中的事务隔离级别有 5 种。
3.通过 @Transactional (propagation = Propagation.REQUIRED) 设置事务的传播机制,Spring 中的事务传播级别有 7 种,重点关注 REQUIRED(默认值)和 REQUIRES_NEW。

Read more

【AI大模型前沿】通义万相Wan2.2:阿里270亿参数巨兽开源,消费级显卡就能跑,免费平替Sora上线

【AI大模型前沿】通义万相Wan2.2:阿里270亿参数巨兽开源,消费级显卡就能跑,免费平替Sora上线

系列篇章💥 No.文章1【AI大模型前沿】深度剖析瑞智病理大模型 RuiPath:如何革新癌症病理诊断技术2【AI大模型前沿】清华大学 CLAMP-3:多模态技术引领音乐检索新潮流3【AI大模型前沿】浙大携手阿里推出HealthGPT:医学视觉语言大模型助力智能医疗新突破4【AI大模型前沿】阿里 QwQ-32B:320 亿参数推理大模型,性能比肩 DeepSeek-R1,免费开源5【AI大模型前沿】TRELLIS:微软、清华、中科大联合推出的高质量3D生成模型6【AI大模型前沿】Migician:清华、北大、华科联手打造的多图像定位大模型,一键解决安防监控与自动驾驶难题7【AI大模型前沿】DeepSeek-V3-0324:AI 模型的全面升级与技术突破8【AI大模型前沿】BioMedGPT-R1:清华联合水木分子打造的多模态生物医药大模型,开启智能研发新纪元9【AI大模型前沿】DiffRhythm:西北工业大学打造的10秒铸就完整歌曲的AI歌曲生成模型10【AI大模型前沿】R1-Omni:阿里开源全模态情感识别与强化学习的创新结合11【AI大模型前沿】Qwen2.5-Omni:

By Ne0inhk

【研发规范】Git 提交(commit)、CodeReview规范

本文将分为三个部分: 1. 为什么需要提交规范? 2. 提交规范详解(核心内容) 3. 与 Code Review 流程的结合 1. 为什么需要提交规范? 在 Code Review 前,如果提交的代码杂乱无章,审查者会非常痛苦: * 理解成本高:审查者需要花费大量时间猜测这个提交到底做了什么和为什么这么做。 * 范围不明确:一个提交里混杂了多个功能的修改,难以聚焦审查。 * 历史追溯困难:混乱的提交信息使得日后排查问题、生成变更日志(Changelog)变得几乎不可能。 良好的提交规范旨在解决这些问题,它的核心目标是:让每一次提交都是一个逻辑独立、意图明确、易于理解的故事单元。 2. 提交规范详解 一份优秀的提交(Commit)主要由两部分组成: 1. 提交信息 2. 提交内容(代码变更集) A. 提交信息规范 提交信息是写给未来维护者(包括你自己) 的说明文档。一个常见的规范格式是:

By Ne0inhk
【Linux工具】git

【Linux工具】git

文章目录 * Git 概述 * 主要功能 * 使用场景 * 资源链接 * 使用和下载git * 总结 Git 概述 Git是一个流行的分布式版本控制系统,主要用于跟踪计算机文件的变化,尤其是在软件开发中。它允许多个开发者协同工作,并管理项目的版本历史。 主要功能 1. 版本跟踪 记录文件的每次更改,用户可以随时回溯到先前的版本。 2. 分支管理 允许开发者创建独立的工作线,便于新特性的开发和实验。 3. 合并功能 轻松合并不同分支的更改,处理冲突并保持代码整洁。 4. 分布式操作 每个开发者都有完整的代码库副本,允许离线工作并提高效率。 使用场景 * 软件开发 最常见的用途,管理源代码的版本控制。 * 文档管理 跟踪文档修改历史,尤其是在团队协作中。 资源链接 * Git官方文档 * Atlassian的Git指南 使用和下载git 如果在你的Linux系统上没有下载git那么我们可以使用下面命令进行下载 sudo yum install -y git 这里我

By Ne0inhk
开源力量:GitCode+昇腾NPU 部署Mistral-7B-Instruct-v0.2模型的技术探索与经验总结

开源力量:GitCode+昇腾NPU 部署Mistral-7B-Instruct-v0.2模型的技术探索与经验总结

开源力量:GitCode+昇腾NPU 部署Mistral-7B-Instruct-v0.2模型的技术探索与经验总结 目录 开源力量:GitCode+昇腾NPU 部署Mistral-7B-Instruct-v0.2模型的技术探索与经验总结 摘要 一、技术背景 1.1 昇腾NPU 1.2 GitCode平台 1.3 vLLM Ascend 二、环境准备 2.1 创建GitCode Notebook 2.2 配置Hugging Face镜像 三、部署方案一:原生部署(transformers + torch_npu) 3.1 安装依赖 3.2 下载模型 3.3 推理代码 3.

By Ne0inhk