【数据库】——事务

本文详细介绍了数据库事务的概念,包括其ACID特性:原子性、一致性、隔离性和持久性。讲解了事务不隔离可能带来的脏读、不可重复读和幻读问题,并探讨了解决方案。此外,还讨论了事务的四种隔离级别及其应用场景,以及如何通过日志系统确保事务的ACD属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、事务的概念

事务由单独单元的一个或多个SQL语句组成,在这个单元中,每个MYSQL语句是相互依赖的。

  • 而整个单独单元作为一个不可分割的整体,如果单元中某条SQL语句一旦执行失败或者产生错误,整个单元将会回滚。
  • 所有受到影响的数据将返回到事务开始以前的状态,如果单元中所有的SQL语句均执行成功,则事物被顺利执行。

2、事务的ACID

2.1原子性

原子性是指事务是一个不可分割的工作单位,事务里面的操作,要么全部执行成功,要么全部失败回滚,不可以只执行其中的一部分。

【举个栗子】
A向B转账100元,需要执行两个操作:A账户减少100元,B账户增加100元。这两个操作要么都同时执行成功,要么都执行失败,否则一个成功,一个失败都是不合理的。

2.2一致性

数据库从一个一致性状态变到另一个一致性状态(经过一系列操作后,所有的操作和更新全部提交成功)数据库只包含全部成功后的数据就是数据的一致性

【举个栗子】
A向B转账100元,假设转账之前这两个用户的钱加起来总共是2000,那么A向B转账之后,不管这两个账户怎么转,A用户的钱和B用户的钱加起来的总额还是2000,这个就是事务的一致性。

2.3隔离性

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

2.4持久性

持久性是指一个事务一旦被提交,他对数据库中的数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

3、事务不隔离产生的影响

3.1脏读

1、概念
脏读的概念很好理解,就是事务获取到其他事务执行过程中的结果

2、解析
具体的阐述一下脏读的概念,一个事务正在访问一个数据并且对其进行了修改,但是这种修改还没有被提交到数据库,另外一个事务也访问这个数据,然后使用了这个数据。

【举个栗子详细说明】
张三的工资5000,A事务将其修改为8000此时时间片到了轮到B事务,他去查询工资是8000,然后去做其他事情,但事情还没处理完成又轮到A事务了A发生异常,张三的工资又回滚成了5000,但是B去读的8000的数据就为脏数据。具体流程图如下:

在这里插入图片描述
其中B事务所读取的8000元就是一个脏数据。
程序执行过程如下:
在这里插入图片描述

3、解决办法
让事务执行过程中获取不到其他事务执行过程的结果。
解决过后的执行过程如下图所示:
在这里插入图片描述

3.3不可重复读

1、概念
在一个事务内,多次读同一数据。在这个事务还没有结束时,另一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
是基于解决了脏读后的情况

产生原因:事务在执行过程中读取了其他事务不同阶段的结果

2、解析
【举个栗子】
现在张三开始的工资是5000,首先A事务开启查询工资为5000,将其修改成为8000,此时B事务开启,查询得到工资为5000(因为针对脏读已经处理,不允许B事务对A事务执行过程中的数据进行读取)。此时让A事务提交,再让B事务查询就能获取到A事务查询过后的结果了,此时查询结果为8000。具体流程如下:
在这里插入图片描述
从上图的结果就可以很容易的看出,针对B事务做两次查询,拿到两个不同的数据,在整个使用的过程会让数据库系统产生二义性。
程序执行过程如下:

在这里插入图片描述

3、解决办法
在探索出针对于重复读取产生二义性的的情况之前,我们首先来探究一下两个事务的具体执行过程。
我们用绿色代表A事务,紫色代表B事务,将每一个过程划分成了数字标号为1-5
在这里插入图片描述
因为B3过程读到了A1的数据,B4过程读到了A4的数据。这样就出现了重复读的问题。所以为了让B3和B4都只能读取A1的数据。就让A事务相对于B事务透明。

总结一下:事务(B)在其他事务(A)执行过程中开启,让其他事务相对于该事务透明。也就是说B事务看不到整个A事务整个的执行和执行后的结果就相当于B事务就认为A事务没有发生一样
解决了该问题过后的执行过程如下:

在这里插入图片描述

3.3幻读

1、概念

事务执行过程中获取到其他事务不同阶段的结果
【注意】区分幻读和不可重复读的情况
不可重复读是因为修改操作导致,幻读是因为插入和删除导致

2、解析
【举个栗子】
首先张三的工资为5000,A事务开启,查询工资为5000的员工的个数,接着再插入李四这条数据工资给5000。接着轮到B事务开启,做一个查询操作,因为还是不能拿到A事务执行过程中的结果,所以查询结果还是1。接下来时间片又到了,轮到A事务提交执行完成。B事务此时查询结果就是2了。具体的流程图如下所示:
在这里插入图片描述
3、解决办法
通过间隙锁来控制的,具体的在后续博文中会有介绍。解决了该问题过后程序的执行过程如下:
在这里插入图片描述

4、隔离级别

4.1隔离级别概述

1、未提交读
事务中的修改,即使没有提交,其他事务也可以看得到,会导致“脏读”、“幻读”和“不可重复读”。

2、已提交读
大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读”,但不能避免“幻读”和“不可重复读”。该级别适用于大多数系统。

3、可重复读
保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读”和“不可重复读”的情况,但不能避免“幻读”,但是带来了更多的性能损失。

4、可序列化
最严格的级别,事务串行执行,资源消耗最大。

隔离级别脏读不可重复读幻读
未提交读
已提交读×
可重复读××
可序列化×××

4.2隔离级别的使用

  • 查询数据库的隔离级别

在这里插入图片描述

从该命令可以看出,mysql默认的隔离级别为可重复读

  • 修改隔离级别

在这里插入图片描述
当前隔离级别和全局隔离级别
在我们使用修改隔离级别的操作的时候,当修改了A事务的隔离级别,但是发现B事务的隔离级别是并没有修改的。如下所示:
在这里插入图片描述

原因就是当前隔离级别和全局隔离级别的区别。

  • 全局隔离级别是服务器的隔离级别
  • 当前隔离级别则是客户端的隔离级别

全局隔离级别就是数据库服务端默认的隔离级别,特点就是REPETABLE-READ在服务端配置文件中写死的。每次有一个客户端要和其连接是就会为其分配一个当前隔离级别,分配的方式就是拿默认的全局隔离级别为其做一个副本。以后修改的时候只是为这个客户端修改当前隔离级别而不会影响到其他客户端。如下图所示:

在这里插入图片描述

5、如何保证ACD

采用加锁的方式不能保证原子性,因为锁还是一种软件机制,一旦发生断电但是现在所有的操作都在内存中记录着的,一旦断电就导致了内存中的数据都丢失了,重启过后整个操作也就都是空白的也就无法知道操作是否执行完毕。

所以为了保证原子性的操作方式就是通过日志系统(redo log重做日志和undo log未做日志),详情如下:

  • redo log(记录事务将要执行的每一个操作,为了保证所有事务能够全部执行成功)
    采用了日志先行策略保证事务开启时,事务中的操作都会先写入存储引擎的日志缓冲中,在事务提交之前,这些缓冲的日志都需要提前刷新到磁盘持久化。此时如果数据库崩溃或者宕机,那么系统重启进行恢复时,就可以根据redo log中记录的日志,把数据库恢复到崩溃前的一个状态。

【举个栗子】

记录1:<trx1, insert...>
记录2:<trx2, delete...>
记录3:<trx3, update...>
记录4:<trx1, update...>
记录5:<trx3, insert...>
  • undo log(为了保证所有事务全部执行失败)
    Undo log未做日志保存了事务执行过程中的每个状态点,到时候要回滚的时候就按照undo log未做日志里面记录的状态点回滚

【举个栗子】

假设有2个数值,分别为A和B,值为1,2
1. start transaction;
2. 记录 A=1 到undo log;
3. update A = 3;
4. 记录 A=3 到redo log;
5. 记录 B=2 到undo log;
6. update B = 4;
7. 记录B = 4 到redo log;
8. 将redo log刷新到磁盘
9. commit
10.

在1-8的任意一步系统宕机,事务未提交,该事务就不会对磁盘上的数据做任何影响。如果在8-9之间宕机,恢复之后可以选择回滚,也可以选择继续完成事务提交,因为此时redo log已经持久化。若在9之后系统宕机,内存映射中变更的数据还来不及刷回磁盘,那么系统恢复之后,可以根据redo log把数据刷回磁盘。

综上所述:redo log其实保障的是事务的持久性和一致性,而undo log则保障了事务的原子性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值