事务机制及Spring事务管理

news2025/1/19 2:39:29

事务概览

事务是一组操作的集合,它是一个不可分割的工作单位。 事务会将所有的操作作为一个整体一起向系统提交或撤销操作请求,换句话说:这些操作要么同时成功、要么同时失败。

具体案例

我们先看一个需求:现在有两张数据库表:员工表emp员工工作经历表emp_expr,现在需要完成新增一个员工的需求,我们需要在员工表中添加员工的基本信息和在员工工作经历表中添加员工的工作经历,这个业务操作就包含了两个操作,根据需求可以先写一个Service方法:

/**
 * 新增员工
 * @param emp 员工实体对象
 */
@Override
public void addEmp(Emp emp) {
    // 为新增员工补全属性
    emp.setCreateTime(LocalDateTime.now());
    emp.setUpdateTime(LocalDateTime.now());
    // 新增员工
    empMapper.insertEmp(emp);
    // 批量添加员工工作经历
    Integer empId = emp.getId();
    List<EmpExpr> exprList = emp.getExprList();
    // CollectionUtils.isEmpty不但会检查集合是否为空,还会检查集合是否为null
    if (!CollectionUtils.isEmpty(exprList)) {
        exprList.forEach(empExpr -> empExpr.setEmpId(empId));
        empExprMapper.insertBatch(exprList);
    }
}

这个Service中的方法先会给Emp员工实体对象补全信息,然后将这些信息添加到数据库表emp中:

/**
 * 新增员工
 * @param emp 员工实体对象
 */
@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})")
@Options(useGeneratedKeys = true, keyProperty = "id")
// 添加员工工作经历时需要使用员工id,MyBatis可以设置主键返回,可以返回id主键
void insertEmp(Emp emp);

mapper方法通过@Options注解中的useGeneratedKeys属性将id主键返回(因为Service方法需要使用id主键)

假如该新增员工的工作经历不为空,则会将该员工的工作经历都添加到员工工作经历表emp_expr中。此时,问题就出现了——因为在这个Service方法中包含了两个操作(一个是添加员工、一个是添加员工工作经历),这两个操作都是一个不可分割的工作单位,但假如在添加完员工之后,方法抛出异常,该方法就会结束,员工信息已经成功保存到了数据库中,然而对应的工作经历没有保存!这就导致了数据的不一致性。

事务操作

事务操作主要分为三步操作:

开启事务

需要保证数据一致性的一组操作开始之前,需要先开启事务(start)。

提交事务

如果这一组操作全部执行成功,则可以提交事务(commit)。

回滚事务

假如这一组操作中有任何一个操作失败,都必须回滚事务(rollback) 撤销操作,以保证数据一致性。

事务的操作在生活中的使用是十分广泛的:比如银行转账,如果不使用事务,就会出现转出的账户扣款了,但是转入的账户并没有收到钱,这样的重大BUG,对于这种涉及多个操作的操作,事务管理是十分重要的。

Spring事务管理

通过上述新增员工的案例可以发现:由于没有使用事务机制,所以说出现了员工信息保存了,但是员工工作经历保存失败的问题,从而造成数据不一致的问题。其产生的原因是在Service方法中,保存员工之后方法抛出了异常,导致方法结束,保存工作经历的代码就不会执行了。 为了保证数据的一致性,这两个操作要么全部成功、要么全部失败,此时我们就需要使用事务

由于我们是使用的springboot框架构建的项目,所以说想要使用事务并不需要我们手动实现,Spring框架中已经将事务控制的代码封装完毕,我们只需要使用@Transactional注解即可开启事务控制。

Transactional注解

@Transactional注解会在当前使用的方法上开启事务,方法全部执行完毕之后提交事务,假如该方法在执行过程中出现了异常,那么就会进行事务回滚来撤销本次操作。@Transactional注解可以写在业务层类上,代表该类中的所有方法都交给spring进行事务管理;@Transactional注解写在接口上,代表当前接口的所有实现类中的所有方法都交给spring进行事务管理;@Transactional注解常见于方法上,代表当前方法交给spring进行事务管理。上述案例中,我们就可以在方法上加上@Transactional注解将其交给spring事务管理:

/**
 * 新增员工
 * @param emp 员工实体对象
 */
@Override
@Transactional // 开启Spring事务机制
public void addEmp(Emp emp) {
    // 为新增员工补全属性
    emp.setCreateTime(LocalDateTime.now());
    emp.setUpdateTime(LocalDateTime.now());
    // 新增员工
    empMapper.insertEmp(emp);
    // 批量添加员工工作经历
    Integer empId = emp.getId();
    List<EmpExpr> exprList = emp.getExprList();
    // CollectionUtils.isEmpty不但会检查集合是否为空,还会检查集合是否为null
    if (!CollectionUtils.isEmpty(exprList)) {
        exprList.forEach(empExpr -> empExpr.setEmpId(empId));
        empExprMapper.insertBatch(exprList);
    }
}

我们一般会在业务层当中来控制事务,因为在业务层当中,一个业务功能可能会包含多个数据访问的操作。在业务层来控制事务,我们就可以将多个数据访问操作控制在一个事务范围内。我们还可以在application.properties配置文件中开启事务管理日志:

这样能够更好的使用spring事务管理。

rollbackFor属性

@Transactional注解可以将方法交给spring进行事务管理,但是在默认情况下,只有出现RuntimeException(运行时异常)才会回滚事务,虽然大部分情况下方法的异常都是运行时异常,但是为了以防万一,我们希望方法在出现任何类型的异常时都能回滚事务,此时就需要用到@Transactional注解中的rollbackFor属性来控制回滚了:

@Transactional(rollbackFor = Exception.class)

此时,我们就通过rollbackFor属性指定了方法出现任何异常都将回滚事务。

propagation属性

propagation属性是用于配置事务的传播行为的。事务的传播行为是指:当一个事务方法被另一个事务方法调用时,该事务方法该如何进行事务控制

例如:此时有两个事务方法方法A方法B,两个方法都交给spring进行了事务管理。在A方法运行的时候,首先会开启一个事务,在A方法当中又调用了B方法,但是B方法自身也具有事务,那么B方法在运行的时候,到底是加入到A方法的事务当中来,还是B方法在运行的时候新建一个事务?这就是事务的传播行为。我们可以通过propagation属性控制事务的传播行为:

对于事务传播行为,只需要关注REQUIRED(默认)REQUIRES_NEW即可。大部分情况下,我们只需要使用REQUIRED传播行为即可,但是当我们不希望事务之间互相影响(比如下订单前需要记录日志,但是不论下订单成功与否,都需要成功记录日志)就可以使用REQUIRES_NEW传播行为

事务四大特性

原子性(Atomicity)

原子性是指事务包装的一组SQL是一个不可分割的工作单元事务中的操作要么全部成功、要么全部失败。

一致性(Consistency)

一致性是指一个事务完成之后数据必须处于一致性状态。如果事务执行成功完成,那么数据库的所有变化生效;如果事务执行出现任何错误,那么数据库的所有变化都会回滚(rollback),数据库将返回到原始状态

隔离性(Isolation)

隔离性是指当多用户并发访问数据库时,一个用户的事务不能被其他用户的事务干扰,多个并发的事务之间互相隔离

持久性(Durability)

持久性是指一个事务一但被提交或者回滚,对于数据库的改变是永久性的

事务的四大特性也简称为ACID

总结

当一个方法中包含有多个操作,此时建议开启事务,事务管理可以确保所有的操作要么全部完成、要么全部回滚,可以保证数据的一致性、完整性。对于后端操作数据库是十分重要的技术。

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

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

相关文章

48.【6】BUUCTF WEB BabySQL

进入靶场 order by 判断字节数 输入内容是 1 order by 2# 显示图片内容&#xff0c;知被过滤了 一般最简单的绕过方法是双写或大小写 尝试双写 It is ok continue 经过多次尝试&#xff0c;4时异常&#xff0c;所以字节数是3 union select都被过滤了 双写解决&#xff0c;成…

Spring6.0新特性-HTTP接口:使用@HttpExchange实现更优雅的Http客户端

文章目录 一、概述二、使用1、创建接口HttpExchange方法2、创建一个在调用方法时执行请求的代理3、方法参数4、返回值5、错误处理&#xff08;1&#xff09;为RestClient&#xff08;2&#xff09;为WebClient&#xff08;3&#xff09;为RestTemplate 注意 一、概述 官方文档…

高效并发编程:掌握Go语言sync包的使用方法

高效并发编程&#xff1a;掌握Go语言sync包的使用方法 引言基本概念并发与并行互斥锁&#xff08;Mutex&#xff09;读写锁&#xff08;RWMutex&#xff09;等待组&#xff08;WaitGroup&#xff09;一次性操作&#xff08;Once&#xff09;条件变量&#xff08;Cond&#xff0…

.Net Core webapi 实现JWT认证

文章目录 需求准备创建JWT配置创建JWTService注册JWT创建中间件读取jwt的token在需要的接口上添加属性启动认证启动swagger的授权认证使用 需求 实现一个记录某个用户所有操作的功能 准备 创建你的webapi项目从nuget下载安装JWT资源包根据你的项目使用.net版本下载对应的jwt…

Linux《Linux简介与环境的搭建》

在学习了C或者是C语言的基础知识之后就可以开始Linux的学习了&#xff0c;现在Linux无论是在服务器领域还是在桌面领域都被广泛的使用&#xff0c;所以Linxu也是我们学习编程的重要环节&#xff0c;在此接下来我们将会花大量的时间在Linxu的学习上。在学习Linux初期你可以会像初…

从零开始:Gitee 仓库创建与 Git 配置指南

引言 Git 是一款广泛使用的版本控制工具&#xff0c;它能够帮助开发者在开发过程中高效地管理代码的版本。而 Gitee&#xff08;码云&#xff09;是国内知名的 Git 托管平台&#xff0c;它提供了强大的代码托管、团队协作和项目管理功能。如果你是 Git 和 Gitee 的新手&#x…

创建模式、结构模式及行为模式

谁在什么地方提供什么功能&#xff1f; 要设计几个类?这些类各个是什么功能&#xff1f;相互间的关系是什么&#xff1f; 创建模式指的是对象那么多&#xff0c;怎么把它"生"出来&#xff1f;生几个&#xff1f;从这个角度上来说数组就是一种另类的创建模式。主要…

SpringBoot链接Kafka

一、SpringBoot生产者 &#xff08;1&#xff09;修改SpringBoot核心配置文件application.propeties, 添加生产者相关信息 # 连接 Kafka 集群 spring.kafka.bootstrap-servers192.168.134.47:9093# SASL_PLAINTEXT 和 SCRAM-SHA-512 认证配置 spring.kafka.properties.securi…

Linux下源码编译安装Nginx1.24及服务脚本实战

1、下载Nginx [rootlocalhost ~]# wget -c https://nginx.org/download/nginx-1.24.0.tar.gz2、解压 [rootlocalhost ~]# tar xf nginx-1.24.0.tar.gz -C /usr/local/src/3、安装依赖 [rootlocalhost ~]# yum install gcc gcc-c make pcre-devel openssl-devel -y4、 准备 N…

解答二重积分

什么是积分&#xff1f; 一元函数的积分。具体计算过程&#xff0c;是将无数个小矩形加起来&#xff0c;然后求极限。 而今天我们要讲的积分&#xff0c;是二元函数的积分。我们可以用曲顶柱体的体积来理解。 什么是曲顶柱体&#xff1f; 它的底是xoy平面上的一个闭区域。顶是…

代理模式实现

一、概念&#xff1a;代理模式属于结构型设计模式。客户端不能直接访问一个对象&#xff0c;可以通过代理的第三者来间接访问该对象&#xff0c;代理对象控制着对于原对象的访问&#xff0c;并允许在客户端访问对象的前后进行一些扩展和处理&#xff1b;这种设置模式称为代理模…

回归预测 | MATLAB实TCN时间卷积神经网络多输入单输出回归预测

效果一览 基本介绍 回归预测 | MATLAB实TCN时间卷积神经网络多输入单输出回归预测 …………训练集误差指标………… 1.均方差(MSE)&#xff1a;166116.6814 2.根均方差(RMSE)&#xff1a;407.5741 3.平均绝对误差&#xff08;MAE&#xff09;&#xff1a;302.5888 4.平均相对…

《目标检测数据集下载地址》

一、引言 在计算机视觉的广袤领域中&#xff0c;目标检测宛如一颗璀璨的明星&#xff0c;占据着举足轻重的地位。它宛如赋予计算机一双锐利的 “眼睛”&#xff0c;使其能够精准识别图像或视频中的各类目标&#xff0c;并确定其位置&#xff0c;以边界框的形式清晰呈现。这项技…

Android系统定制APP开发_如何对应用进行系统签名

前言 当项目开发需要使用系统级别权限或frame层某些api时&#xff0c;普通应用是无法使用的&#xff0c;需要在AndroidManifest中配置sharedUserId&#xff1a; AndroidManifest.xml中的android:sharedUserId“android.uid.system”&#xff0c;代表的意思是和系统相同的uid&a…

【NextJS】PostgreSQL 遇上 Prisma ORM

NextJS 数据库 之 遇上Prisma ORM 前言一、环境要求二、概念介绍1、Prisma Schema Language&#xff08;PSL&#xff09; 结构描述语言1.1 概念1.2 组成1.2.1 Data Source 数据源1.2.2 Generators 生成器1.2.3 Data Model Definition 数据模型定义字段(数据)类型和约束关系&…

Mybatis 进阶 / Mybatis—Puls (详细)

目录 一.动态SQL 1.1标签 1.2 标签 1.3标签 1.4标签 1.5标签 1.6标签 mybatis总结&#xff1a; 二.Mybatis-Puls 2.1准备工作 2.2CRUD单元测试 2.2.1创建UserInfo实体类 2.2.2编写Mapper接⼝类 2.2.3 测试类 2.3 常见注解 2.3.1TableName 2.3.2TableField 2.4打印日…

Java工具包:高效开发的魔法钥匙

目录 一、引言 二、Hutool 工具包初体验 2.1 快速入门 2.2 常用工具类及方法详解 2.2.1 Convert 类型转换工具类 2.2.2 DateUtil 日期时间工具类 2.2.3 StrUtil 字符串工具类 2.2.4 其他常用工具类 三、其他 Java 常用工具包巡礼 3.1 Apache Commons 系列 3.2 Google…

Formality:参考设计/实现设计以及顶层设计

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482​​​ Formality存在两个重要的概念&#xff1a;参考设计/实现设计和顶层设计&#xff0c;本文就将对此进行详细阐述。参考设计/实现设计是中两个重要的全局概念&am…

HBase实训:纸币冠字号查询任务

一、实验目的 1. 理解分布式数据存储系统HBase的架构和工作原理。 2. 掌握HBase表的设计原则&#xff0c;能够根据实际业务需求设计合理的表结构。 3. 学习使用HBase Java API进行数据的插入、查询和管理。 4. 实践分布式数据存储系统在大数据环境下的应用&#xff0c;…

C#轻松实现条形码二维码生成及识别

一、前言 大家好&#xff01;我是付工。 今天给大家分享一下&#xff0c;如何基于C#来生成并识别条形码或者二维码。 二、ZXing.Net 实现二维码生成的库有很多&#xff0c;我们这里采用的是http://ZXing.Net。 ZXing是一个开放源码的&#xff0c;用Java实现的多种格式的一…