一文读懂事务及Spring事务的管理(面试经)_上篇

server/2025/2/20 20:56:24/

导览

  • 前言
  • Q:什么是事务
    • 1. 设计目的
    • 2. 四大特性
      • 2.1 原子性(Atomicity)
      • 2.2 持久性(Durability)
      • 2.3 隔离性(Isolation)
      • 2.4 一致性(Consistency)
    • 3. ACID相互关系
  • Q:什么是事务的隔离级别及其影响
    • 1. 标准隔离级别
    • 2. 并发一致性问题
      • 2.1 丢失修改
      • 2.2 不可重复读
      • 2.3 幻读
  • 结语
  • 精彩回顾

前言

书接上文,继续展开基于Spring的各组件的原理解密。本文带这各位聊聊事务的那些事儿。当提到事务的时候,你会想到什么?各位盆友,是否能够立刻让ACID脱口而出?

我们先从最基础事务谈起吧,Let’s go~

在这里插入图片描述

Q:什么是事务

数据库事务(简称:事务)是数据库管理系统(DBMS)执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

1. 设计目的

事务事务开始(begin transaction)与事务结束(end transaction)之间执行的全体操作组成。数据库事务通常包含了一个序列的对数据库的读/写操作。

通常,包含有以下两个目的:

  1. 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
    当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
  2. 事务被提交给了数据库管理系统(DBMS),则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要回滚;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。

2. 四大特性

事务其实就是并发控制的基本单位,也是一个序列操作。其中的操作要么都执行,要么都不执行,它是一个不可分割的工作单位。数据库事务ACID 四大特性是事务的基础。了解了 ACID 是如何实现的,也就清楚了事务的实现,接下来我们将依次介绍数据库是如何实现这四个特性的。

2.1 原子性(Atomicity)

原子性是指事务包含的所有操作,要么全部成功,要么全部回滚。因此事务的操作,如果成功,就必须要完全应用到数据库,如果失败,则不能对数据库有任何影响。

由于操作并不具有原子性,并且可以再分为多个操作,当这些操作出现错误或抛出异常时,整个操作就可能不会继续执行,而已经进行的操作造成的副作用就可能造成数据更新的丢失或者错误。想要保证事务的原子性,就需要在异常发生时,对已经执行的操作进行回滚。比如,在 MySQL 中,恢复机制是通过回滚日志(undo log)实现的。所有事务进行的修改都会先记录在回滚日志中,然后在写库。

具体过程可参考如下3图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2 持久性(Durability)

持久性是指一个事务一旦被提交,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

与原子性一样,事务的持久性也是通过日志来实现的,比如MySQL 使用重做日志(redo log)实现事务的持久性,重做日志由两部分组成,一是内存中的重做日志缓冲区,它是易失的;另一个是在磁盘上的重做日志文件,它是持久的。当我们在一个事务中尝试对数据进行修改时,它会先将数据从磁盘读入内存,并更新内存中缓存的数据,然后生成一条重做日志并写入重做日志缓存,当事务真正提交时,MySQL 会将重做日志缓存中的内容刷新到重做日志文件,再将内存中的数据更新到磁盘上。下图中的第 4、5 步就是在事务提交时执行的。

在这里插入图片描述
除了所有对数据库的修改会产生重做日志外,由于回滚日志也是需要持久存储的,它们也会创建对应的重做日志。在发生错误后,数据库重启时会从重做日志中找出未被更新到数据库磁盘中的日志重新执行以满足事务的持久性。

2.3 隔离性(Isolation)

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始

即使每个事务都能确保一致性和原子性,如果几个事务并发执行,它们的操作会以某种人们所不希望的方式交叉执行,这也会导致不一致的状态。一种避免事务并发执行而产生的问题的途径是串行地执行事务,但事务并发执行能显著地改善性能。因此人们提出了多种允许多个事务并发执行的解决方法。

以常用的mysql InnoDB存储引擎为例:加入商品表items表中有一个字段status,status=1表示该商品未被下单,status=2表示该商品已经被下单,那么我们对每个商品下单前必须确保此商品的status=1。
此时,假设有一件商品,其id为10000,如果不使用锁,那么通过如下SQL实现:

//查出商品状态
select status from items where id=10000;
//根据商品信息生成订单
insert into orders(id,itemid)values(null,10000);
//修改商品状态为2
update items set status=2 where id=10000;

2.4 一致性(Consistency)

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

一致性要求事务的执行不改变A、B之和。如果没有一致性要求,金额可能会被事务凭空创造或者销毁!如果数据库在事务执行前是一致的,那么事务执行后仍将保持一致性,这是很容易验证的。确保单个事务的一致性是编写该事务的程序员的责任,完整性约束的自动检查给这项工作带来了便利。如果系统的状态不再反映数据库本应描述的现实世界的真实状态,称之为不一致状态。

ACID_64">3. ACID相互关系

在这里插入图片描述

  1. 只有满足一致性,事务的执行结果才是正确的。
  2. 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时要只要能满足原子性,就一定能满足一致性。
  3. 事务并发情况下,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
  4. 事务满足持久化是为了能应对数据库奔溃的情况。

掌握了事务的基本原理后,我们开始正式谈谈Spring中的事务是如何管理的。

Q:什么是事务的隔离级别及其影响

事务的隔离级别是指在数据库系统中,一个事务的执行是否会受到其他事务影响的程度,以及事务之间相互隔离的程度。

1. 标准隔离级别

SQL事务中有四种标准的隔离级别:

1.1 未提交读(READ UNCOMMITTED)
事务中的修改,即使没有提交,对其它事务也是可见的。使用查询语句不会加锁,可能会读到未提交的行(Dirty Read)。
1.2 提交读(READ COMMITTED)
一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所做的修改在提交之前对其它事务是不可见的。只对记录加记录锁,而不会在记录之间加间隙锁,所以允许新的记录插入到被锁定记录的附近,所以再多次使用查询语句时,可能得到不同的结果(Non-Repeatable Read)。
1.3 可重复读(REPEATABLE READ)
保证在同一个事务中多次读取同样数据的结果是一样的。多次读取同一范围的数据会返回第一次查询的快照,不会返回不同的数据行,但是可能发生幻读(Phantom Read)。
1.4 可串行化(SERIALIZABLE)
强制事务串行执行。

博主通过一个表格加以总结:

隔离级别脏读不可重复读幻影读
未提交读YESYESYES
提交读NOYESYES
可重复读NONOYES
可串行化NONONO

以上,所有的事务隔离级别都不允许脏写入(Dirty Write),也就是当前事务更新了另一个事务已经更新但是还未提交的数据,大部分的数据库中都使用了 READ COMMITED 作为默认的事务隔离级别,但是 MySQL 使用了 REPEATABLE READ 作为默认配置。

请参考:在这里插入图片描述

2. 并发一致性问题

2.1 丢失修改

T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。从而产生“丢失修改”的问题。

在这里插入图片描述

2.2 不可重复读

T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。
在这里插入图片描述

2.3 幻读

T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。
在这里插入图片描述

那么,有什么办法解决它们呢?
产生并发不一致性问题主要原因是破坏了事务隔离性,解决方法是通过并发控制来保证隔离性。并发控制可以通过锁来实现,但是封锁操作需要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题。


结语

本文通过精讲的方式,阐述了事务及其基本原理、特性和应用问题。内容丰富,知识点较多,所以很重要,同样也是面试必答环节,好好研习一下,可助你通关哦。

走过的、路过的盆友们,点点赞,收收藏,并加以指导,以备不时之需哈~

精彩回顾

一文读懂Spring Security的工作原理和机制(面试经)
一文读懂Spring AOP的工作原理和机制(面试经)
一文读懂Spring IoC的工作原理和机制(面试经)
一文读懂SpringMVC的工作原理
Springboot中基于X509完成SSL检验的原理与实践
基于springboot+enum配置化实践


在这里插入图片描述


http://www.ppmy.cn/server/131452.html

相关文章

python:假的身份信息生成模块faker

前言 发现一个有趣的python模块(faker),他支持生成多个国家语言下的假身份信息,包含人名、地址、邮箱、公司名、电话号码、甚至是个人简历! 你可以拿它做一些自动化测试,或一些跟假数据有关的填充工作。 代…

原来CDC数据同步可以这么简单,零代码可视化一键数据同步

当前企业实时同步与分析场景中面临的挑战: 随着业务发展需要,实时分析成为企业目前的强需求,成为支撑企业业务发展的必须项。 一般来说,要满足数据实时分析的诉求,通常有两种方案: 第一种是直接使用源端…

postman变量,断言,参数化

环境变量 1.创建环境变量 正式环境是错误的,方便验证环境变化 2.在请求中添加变量 3.运行前选择环境变量 全局变量 能够在任何接口访问的变量 console中打印日志 console.log(responseBody);//将数据解析为json格式 var data JSON.parse(responseBody); conso…

使用C++结合Qt实现聊天室:QTcpSocket实现远程实时通信

既然是要实现远程实时通信,那么就需要用到网络协议。我们需要用到TCP/IP协议,不过Q提供了标准库QTcpSocket,我们只需要能够使用这个库就行了。这个标准库将远程连接通信功能封装的很好,详情可以查看QTcpSocket的文档,在…

【c数据结构】二叉树深层解析 (模拟实现+OJ题目)

目录 前言 一、树 1.树的概念与结构 2.树的专业用语 1.根节点 2.边 3.父节点/双亲节点 4.子节点/孩子节点 5.节点的度 6.树的度 7.叶子节点/终端节点 8.分支节点/非终端节点 9.兄弟节点 10.节点的层次 11.树的高度/深度 12.节点的祖先 13.子孙 14.路径 15.森…

手写mybatis之SQL执行器的定义和实现

前言 所有系统的设计和实现,核心都在于如何解耦,如果解耦不清晰最后直接导致的就是再继续迭代功能时,会让整个系统的实现越来越臃肿,稳定性越来越差。而关于解耦的实践在各类框架的源码中都有非常不错的设计实现,所以阅…

R语言:ERGM指数随机图模型6:模型退化

文章目录 模型退化加载faux.magnolia.high数据集几何加权边共享伙伴项(GWESP)模型退化 当一个模型不能很好地表示观测到的网络时,在马尔可夫链蒙特卡洛链中产生的模拟网络可能与观测到的网络相差甚远,以至于估计过程受到影响。在最坏的情况下,模拟网络会有很大的不同,以…

《深度学习》循环神经网络RNN 结构及原理解析

目录 一、关于RNN 1、传统神经网络存在的问题 2、什么是循环神经网络 3、RNN特点 二、RNN基本结构 1、RNN基本结构 2、推导方式 注意: 3、循环的由来 4、RNN的局限性 一、关于RNN 1、传统神经网络存在的问题 无法训练出具有顺序的数据,模型搭…