MySQL的事务以及springboot中如何使用事务
事务的四大特性:
概念:
事务 是一组操作的集合,它是不可分割的工作单元。事务会把所有操作作为一个整体,一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。
注意:
默认MySQL的事务是自动提交的,也就是说,当执行一条DML语句,MySQL会立即隐式的提交事务。
事务的特性:
原子性:
事务是最小的执行单元,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用。不允许部分成功和失败。
一致性:
确保从一个正确的状态转换到另外一个正确的状态。举例,张三把钱转账给李四100元,张三少了100,李四多了100.但是他俩的钱加起来的钱数,还是和转账之前加起来的钱数相同。
隔离性:
并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。
持久性:
事务被提交之后,对数据库中数据的改变是持久的,即使数据库发生故障,也不会对其有影响。
操作:
事务执行的三步操作:
开启事务、提交事务/回滚事务
-- 开启事务
start transaction; / begin;
-- 1. 保存员工基本信息
insert into emp values (39, 'Tom', '123456', '汤姆', 1, '13300001111', 1, 4000, '1.jpg', '2023-11-01', 1, now(), now());
-- 2. 保存员工的工作经历信息
insert into emp_expr(emp_id, begin, end, company, job) values (39,'2019-01-01', '2020-01-01', '百度', '开发'), (39,'2020-01-10', '2022-02-01', '阿里', '架构');
-- 提交事务(全部成功) / 回滚事务(有一个失败)
commit; / rollback;
事务之间的相互影响:
脏读,不可重复读,幻读,丢失更新
通过我们的案例,来演示数据库事务:
在EmpController编写,添加员工的接口:
/*** 新增员工的数据* @param emp* @return* @throws Exception*/@PostMappingpublic Result add(@RequestBody Emp emp) throws Exception {log.info("新增员工数据:{}",emp);empService.add(emp);return Result.success();}
编写EmpService接口:
/*** 新增员工信息* @param emp*/void add(Emp emp) throws Exception;
编写 EmpServiceImpl的实现类:
@Overridepublic void add(Emp emp) throws Exception {//先添加员工的基本信息emp.setCreateTime(LocalDateTime.now()); //赋值初始值emp.setUpdateTime(LocalDateTime.now()); //赋值初始值empMapper.addEmp(emp);//在添加员工的工作经历信息List<EmpExpr> exprList = emp.getExprList();if (!CollectionUtils.isEmpty(exprList)){ //当工作经历不是空的时候,在进行添加exprList.forEach(expr ->{expr.setEmpId(emp.getId());});}// 批量添加员工的经历empExprMapper.insertBatch(exprList);}
注意,我们在添加员工的时候,还需要添加员工的工作经历。
@Insert("insert into emp (username, name, gender, phone, job, salary, image, entry_date, dept_id, create_time, update_time) values" +"(#{username},#{name},#{gender},#{phone},#{job},#{salary},#{image},#{entryDate},#{deptId},#{createTime},#{updateTime})")
void addEmp(Emp emp);
还需要编写 EmpExprMapper接口:
/*** 批量添加员工经历的数据* @param exprList*/void insertBatch(List<EmpExpr> exprList);
主键返回:
在添加员工的工作经历的时候,我们还需要添加一个字段的值就是 emp_id 但是我们改怎么获取到这个刚添加好的主键id的??
主键返回:
在注解上使用:
@option注解
常用的属性值:
useGeneratedKeys:是否使用主键返回。
keyProperty:返回的id绑定那个属性
示例:
@Options(useGeneratedKeys = true,keyProperty = "id") //使用主键返回,并把返回的主键赋值给id属性,emp对象的 id属性@Insert("insert into emp (username, name, gender, phone, job, salary, image, entry_date, dept_id, create_time, update_time) values" +"(#{username},#{name},#{gender},#{phone},#{job},#{salary},#{image},#{entryDate},#{deptId},#{createTime},#{updateTime})")void addEmp(Emp emp);
xml中使用:
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into tb_user(username,password) values(#{username},#{password})
</insert>
编写 EmpExprMapper接口:
/*** 批量添加员工经历的数据* @param exprList*/void insertBatch(List<EmpExpr> exprList);
编写EmpExprMapper.xml
<insert id="insertBatch">insert into emp_expr(emp_id,begin,end,company,job) values<foreach collection="exprList" item="expr" separator=",">(#{expr.empId},#{expr.begin},#{expr.end},#{expr.company},#{expr.job})</foreach></insert>
在Api测试我们成功添加了,员工的基本信息和员工的工作经历信息:
接下来,我做一些改动,添加员工的基本信息成功之后,手写一个运行时异常的bug
点击提交,然后看看会发生什么情况。
可以看到,员工的基本信息,添加成功了。
但是员工的工作经历,添加失败了。
为什么会失败呢?看看idea的看控制台
可以发现,控制台出现了异常 除0异常。
但是我们想一想,添加员工基本信息的时候,就要把员工的工作经历信息添加上去,这是才能保证数据的完整性和一致性,不能一个成功一个失败。
这时我们想到了数据库的事务,如果添加员工和添加员工的工作经历都成功了,那么我们才向数据库执行提交 commit,如果其中一个失败了,我们就回滚事务。roooback
我们可以通过spring事务管理,来解决这个问题。
Spring事务管理:
事务控制:
注解: @Transactional
作用:将当前方法交给spring事务进行管理,方法执行前,开启事务,成功执行后提交事务。出现异常回滚事务。
位置:业务(service)层的方法上面,类上,接口上。
作用在接口上:
作用在类上:
作用在方法上:
@Transactional@Overridepublic PageBean getList(Integer page, Integer pageSize) {PageHelper.startPage(page,pageSize);List<Emp> empList = empMapper.PageList(); //PageHelper后面的第一条SQL语句System.out.println(empList);Page<Emp> emps = (Page<Emp>) empList;return new PageBean(emps.getTotal(),emps.getResult());}
虽然在方法,接口还有实体类上面都可以添加@Transaction注解,但是我的建议是,在一个方法上面添加,因为有的操作,只涉及到了一张表的操作,也不用添加事务,就像添加一张表,要是成功就成功了,失败就失败了。不会保存在数据库里面的。因此不会造成数据的不完整性。
spring事务管理的日志输出:
开启Spring事务管理的debug级别日志,就可以看到控制台中事务开启、提交、回滚的日志了
在application.properties配置问价里面添加
开启spring事务管理的debug级别日志logging.level.org.springframework.jdbc.support.JdbcTransactionManager=debug
在添加员工的基本信息的方法上面添加注解:
@Transactional@Overridepublic void add(Emp emp) throws Exception {try {//先添加员工的基本信息emp.setCreateTime(LocalDateTime.now()); //赋值初始值emp.setUpdateTime(LocalDateTime.now()); //赋值初始值empMapper.addEmp(emp);//在添加员工的工作经历信息List<EmpExpr> exprList = emp.getExprList();if (!CollectionUtils.isEmpty(exprList)){ //当工作经历不是空的时候,在进行添加exprList.forEach(expr ->{expr.setEmpId(emp.getId());});}int i = 1/ 0 ;// 批量添加员工的经历empExprMapper.insertBatch(exprList);}finally {EmpLog empLog = new EmpLog(null,LocalDateTime.now(),emp.toString()); //添加日志empLogService.insertLog(empLog);}}
在测试一下:
可以发现这个时候,已经报错了。
看看数据库里面添加成功里面数据没有:
可以发现员工的基本信息也没有添加进去,说明spring事务生效了。让我们来看一下控制台
在执行添加员工的信息的这个方法时,开始了事务,执行添加员工的基本信息后,SQL是执行成功的,但是里面出现了一个除0的异常,后面的添加员工的工作经历的SQL语句,就不执行了。所以在这一个事务中,一个执行成功了,一个执行失败了,事务就没有commit提交,而是rollback回滚了,所以我们在数据库里面并没有看到有数据添加到数据库里面的表中。
现在·我们把这个除0异常注释掉,看看程序执行会不会报错,数据能不能添加到数据库里面。
前后端联调:
可以看到数据添加成功了。
看看ideal的控制台
事务提交了
看看数据库里面的数据,emp表
在看看emp_expr表
数据也添加成功了
事务进阶:
属性-rollbackFor
- 默认情况下,只有出现 RuntimeException 才回滚异常。
- rollbackFor属性用于控制出现何种异常类型,回滚事务。
如果我们在代码中,添加一个编译时异常,这个时候,spring事务还会回滚吗?
我们可以测试一下,在添加员工的基本信息成功之后,在中间throws一个异常,然后在添加员工的工作经历信息。看看程序会发生什么。
@Transactional@Overridepublic void add(Emp emp) throws Exception {try {//先添加员工的基本信息emp.setCreateTime(LocalDateTime.now()); //赋值初始值emp.setUpdateTime(LocalDateTime.now()); //赋值初始值empMapper.addEmp(emp);//在添加员工的工作经历信息List<EmpExpr> exprList = emp.getExprList();if (!CollectionUtils.isEmpty(exprList)){ //当工作经历不是空的时候,在进行添加exprList.forEach(expr ->{expr.setEmpId(emp.getId());});}if (true){throw new Exception();}// 批量添加员工的经历empExprMapper.insertBatch(exprList);}finally {EmpLog empLog = new EmpLog(null,LocalDateTime.now(),emp.toString()); //添加日志empLogService.insertLog(empLog);}}
服务器端出现异常:
看看数据库里面的数据。
员工的基本信息还是添加成功了
这是因为,默认情况下,只有出现 RuntimeException 才回滚异常。
可以发现在执行添加员工信息的时候,它commit提交了。
这个时候,需要在@Transaction注解里面添加 rollbaclFor属性了。
@Transactional(rollbackFor = {Exception.class}) //开启事务 spring事务默认只能识别到运行时异常,要是想识别到Exception的异常,需要使用rollbackFor
我们在重启服务器测试:
发现数据添加失败了,但是数据库里面没有新增员工的基本信息。
数据表里面刚刚添加的数据。
我们把刚刚 手动写的异常删掉,在运行程序。
可以发现刚刚添加的数据成功了,
看看数据库里面的数据,emp表
查看emp_expr表。数据添加成功了。
相关文章:

MySQL的事务以及springboot中如何使用事务
事务的四大特性: 概念: 事务 是一组操作的集合,它是不可分割的工作单元。事务会把所有操作作为一个整体,一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。 注意: 默认MySQ…...
docker二 redis单机安装
创建文件夹 mkdir -p /usr/local/redis/data /usr/local/redis/logs /usr/local/redis/conf chmod -R 777 /usr/local/redis/data* chmod -R 777 /usr/local/redis/logs*另一种风格 # 创建 redis 配置存放目录 mkdir -p /home/docker/redis/conf && chmod 777 /home/…...

【解决】Vue elementUI table表格 列错位/滑动后切换每页显示数后错位/表格使用fixed后错位...
table表格右侧列固定后,在切换页面之后,就会出现列错误的现象 <el-tablev-adaptive"{ bottomOffset: 85 }"height"100px"v-loading"loading":data"dataList"> 解决方法 方法一 1、给表格添加ref &…...

uniapp实战 —— 分类导航【详解】
效果预览 组件封装 src\pages\index\components\CategoryPanel.vue <script setup lang"ts"> import type { CategoryItem } from /types/index defineProps<{list: CategoryItem[] }>() </script><template><view class"category&…...

LangChain学习二:提示-实战(下半部分)
文章目录 上一节内容:LangChain学习二:提示-实战(上半部分)学习目标:提示词中的示例选择器和输出解释器学习内容一:示例选择器1.1 LangChain自定义示例选择器1.2 实现自定义示例选择器1.2.1实战:…...

Network 灰鸽宝典【目录】
目前已有文章 21 篇 Network 灰鸽宝典专栏主要关注服务器的配置,前后端开发环境的配置,编辑器的配置,网络服务的配置,网络命令的应用与配置,windows常见问题的解决等。 文章目录 服务配置环境部署GitNPM 浏览器编辑器系…...

基于SSM的实验室排课系统
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…...

Docker部署wordpress和Jenkins
准备机器: 192.168.58.151 (关闭防火墙和selinux) 安装好docker服务 (详细参照:http://t.csdnimg.cn/usG0s 中的国内源安装docker) 部署wordpress: 创建目录: [rootdocker ~]# mkdi…...

C语言—每日选择题—Day45
第一题 1. 以下选项中,对基本类型相同的指针变量不能进行运算的运算符是() A: B:- C: D: 答案及解析 A A:错误,指针不可以相加,因为指针相加可能发生越界&…...

音乐制作软件Studio One mac软件特点
Studio One mac是一款专业的音乐制作软件,由美国PreSonus公司开发。该软件提供了全面的音频编辑和混音功能,包括录制、编曲、合成、采样等多种工具,可用于制作各种类型的音乐,如流行音乐、电子音乐、摇滚乐等。 Studio One mac软件…...
华为OD机试 - 会议室占用时间(Java JS Python C)
题目描述 现有若干个会议,所有会议共享一个会议室,用数组表示各个会议的开始时间和结束时间,格式为: [[会议1开始时间, 会议1结束时间], [会议2开始时间, 会议2结束时间]] 请计算会议室占用时间段。 输入描述 第一行输入一个整数 n,表示会议数量 之后输入n行,每行两个…...

Excel COUNT类函数使用
目录 一. COUNT二. COUNTA三. COUNTBLANK四. COUNTIF五. COUNTIFS 一. COUNT ⏹用于计算指定范围内包含数字的单元格数量。 基本语法 COUNT(value1, [value2], ...)✅统计A2到A7所有数字单元格的数量 ✅统计A2到A7,B2到B7的所有数字单元格的数量 二. COUNTA ⏹计…...

刷题学习记录(文件上传)
[GXYCTF 2019]BabyUpload 知识点:文件上传.htaccessMIME绕过 题目直接给题目标签提示文件上传的类型 思路:先上传.htaccess文件,在上传木马文件,最后蚁剑连接 上传.htaccess文件 再上传一个没有<?的shell 但是要把image/pn…...

接口管理——Swagger
Swagger是一个用于设计、构建和文档化API的工具集。它包括一系列工具,如Swagger Editor(用于编辑Swagger规范)、Swagger UI(用于可视化API文档)和Swagger Codegen(用于根据API定义生成客户端库、server stu…...

基于Python+WaveNet+MFCC+Tensorflow智能方言分类—深度学习算法应用(含全部工程源码)(三)
目录 前言引言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 模型构建1)定义模型结构2)优化损失函数 3. 模型训练及保存1)模型训练2)模型保存3)映射保存 相关其它博客工程源代码下载其它资料下载…...

(第5天)进阶 RHEL 7 安装单机 Oracle 19C NON-CDB 数据库
进阶 RHEL 7 安装单机 Oracle 19C NON-CDB 数据库(第5天) 真快,实战第 5 天了,我们来讲讲 19C 的数据库安装吧!19C 是未来几年 Oracle 数据库的大趋势,同样的作为长期稳定版,11GR2 在 2020 年 10 月份官方就宣布停止 Support 了,19C 将成为新的长期稳定版,并持续支持…...

AI自动生成代码工具
AI自动生成代码工具是一种利用人工智能技术来辅助或自动化软件开发过程中的编码任务的工具。这些工具使用机器学习和自然语言处理等技术,根据开发者的需求生成相应的源代码。以下是一些常见的AI自动生成代码工具,希望对大家有所帮助。北京木奇移动技术有…...

jmeter和postman的对比
1.创建接口用例集(没区别) Postman是Collections,Jmeter是线程组,没什么区别。 2.步骤的实现(有区别) Postman和jmeter都是创建http请求 区别1:postman请求的请求URL是一个整体,j…...

深度学习在人体动作识别领域的应用:开源工具、数据集资源及趋动云GPU算力不可或缺
人体动作识别检测是一种通过使用计算机视觉和深度学习技术,对人体姿态和动作进行实时监测和分析的技术。该技术旨在从图像或视频中提取有关人体姿态、动作和行为的信息,以便更深入地识别和理解人的活动。 人体动作识别检测的基本步骤包括: 数…...

科技提升安全,基于YOLOv6开发构建商超扶梯场景下行人安全行为姿态检测识别系统
在商超等人流量较为密集的场景下经常会报道出现一些行人在扶梯上摔倒、受伤等问题,随着AI技术的快速发展与不断普及,越来越多的商超、地铁等场景开始加装专用的安全检测预警系统,核心工作原理即使AI模型与摄像头图像视频流的实时计算…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...