MySQL事务

什么是事务

当我们执行一系列操作时,这些操作要么全部执行成功,要么全部回滚(撤销),就像完成一项任务一样。这个整体的执行过程就是一个事务。

假设你要将100元从账户A转到账户B,这个过程可以分为两步:首先从账户A中扣除100元,然后将这100元添加到账户B中。如果这两个操作只有一个成功,另一个失败,那么转账就是不完整的。

事务机制的目标就是确保在转账过程中,要么这两个操作都成功,要么两个操作都失败,保持数据的一致性。

要实现事务,通常需要满足一些特性(即ACID特性):

  1. 原子性(Atomicity):一个事务的所有操作要么全部成功,要么全部失败。如果其中一部分操作失败,整个事务会被回滚,恢复到原始状态。

  2. 一致性(Consistency):事务的执行不会破坏数据库的完整性约束。在事务开始之前和结束之后,数据库必须处于一致状态。

  3. 隔离性(Isolation):并发执行的事务之间应该相互隔离,互不影响。每个事务都应该感觉不到其他事务的存在,就像它是唯一在操作数据库一样。

  4. 持久性(Durability):一旦事务被提交,其对数据库的改变应该是永久性的,即使发生系统崩溃或电源故障等情况,数据也应该能够被恢复。

134是处理过程,2是导致的结果,这个过程需要用户和操作系统共同完成。

所以说事务就是在ACID特性下的操作。可以把事务看作多个SQL语句打包成一个事务对象,交给操作系统帮我们执行对应操作。比如我们去银行转钱取钱,并不需要知道中间出错了需要干什么,只知道钱会退回或者成功转账。

什么是回滚

回滚指的是撤销已经执行的事务操作。回滚有定向回滚和直接回滚。

假如你在一个事务里开始执行了多条语句,然后此时你直接rollback就会直接回到最开始。这叫做直接回滚。

如果我们在某一个地方设置了一个保存点:

savepoint s1;

此时我们想回到这个保存点,就可以:

rollback to s1;

事务的操作

启动事务和提交事务

两种方式都可以:

begin;
start transaction;

开启以后,意味着后续的操作都将是同一个事务

结束事务以后用commit提交。

手动提交和自动提交

事务有两种提交方式:手动和自动

在MySQL中,自动提交(autocommit)模式决定了事务提交的行为。当自动提交模式为开启(ON)时,每个单独的SQL语句都会自动提交为一个独立的事务,并立即将修改持久化到数据库中。这意味着每执行完一个SQL语句,对数据库的修改都会立即生效,不需要显式地使用提交命令。这是MySQL的默认行为。

当自动提交模式为关闭(OFF)时,需要显式地使用提交命令(如COMMIT)才能将修改的数据提交到数据库。在这种模式下,多个SQL语句可以作为一个事务的一部分,通过显式地提交事务来保存对数据库的修改。如果没有显式地提交事务,对数据库的修改将不会生效,也不会持久化到数据库中。

但是如果直接启动事务其实也是手动模式的一个标志,意味着需要commit才会对整个事务进行提交。

对于单条语句,其实就是一个事务,由于有自动提交,所以我们不需要自己提交,但是如果把自动提交关掉,就需要自己commit才可以保存。

show variables like模糊查询提交方式:

show variables like 'autocommit';

在这里插入图片描述

把自动提交禁用;

set autocommit = 0;

异常情况下事务的回滚

如果在一个事务未commit前就退出了,那这个事务会直接回滚到开始。

什么是幻读

幻读针对的是集合

幻读和不可重复读的关系:不可重复读主要关注的是在同一个事务中读取相同的数据时,获取到的结果可能发生变化,而幻读则关注的是在同一个事务中进行相同的范围查询时,结果集可能发生变化

为了解决幻读问题,MySQL 中的 InnoDB 存储引擎使用了多版本并发控制(MVCC)机制。

什么是脏读

两个正在并发运行的事务,一个正在写,但是还未提交,另一个就可以查看到它刚写入的数据,这些数据有可能被回滚,导致读的不正确。这就是脏读。它的前提就是读未提交。

事务的隔离级别

数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性。同时允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

隔离级别:

  1. 读未提交:最低的隔离级别,事务可以读取其他事务未提交的修改。这种隔离级别存在脏读(Dirty Read)问题,可能导致不一致的数据。

  2. 读已提交:事务只能读取其他事务已经提交的修改。这种隔离级别可以避免脏读问题,但可能导致不可重复读(Non-repeatable Read)问题,即多次进行相同的查询,但结果却不一致。

  3. 可重复读:这是 MySQL 默认的隔离级别,事务在执行期间多次读取同一数据时,能够保证得到一致的结果,即不会出现不可重复读问题。但是可能导致幻读

  4. 串行化:这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁。但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)

隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等

查看与设置隔离性

session表示当前会话的隔离级别。

设置会话隔离级别只影响当前mysql,设置全局隔离级别会影响后续新开的mysql。

查看全局隔离级别:

SELECT @@global.tx_isolation;

默认是可重复读:

在这里插入图片描述

查看会话(当前)全局隔级别:

SELECT @@session.tx_isolation;

MVCC多版本并发控制

mvcc解决的就是读写时的线程安全问题,线程不用去争抢读写锁。这里的读指的是快照读。

MVCC是MySQL中用来处理并发事务的一种技术。它通过在每个数据行上保存多个版本,允许读操作能够在不被并发事务修改的情况下获得一致性的数据视图。

MVCC的条件是启用事务隔离级别为可重复读(REPEATABLE READ)或更高级别,此时MySQL会使用MVCC来提供一致性的读取。

当一个事务执行SELECT查询时,MySQL会根据事务的时间戳,与每个数据行的版本号进行比较来确定是否该行对事务可见。如果该行的创建版本号早于事务时间戳,且删除版本号晚于事务时间戳(即未被其它事务删除),那么该行就是对当前事务可见的。

预备知识

数据库并发的场景有三种:

  1. 读-读 :不存在任何问题,也不需要并发控制
  2. 读-写 :有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读
  3. 写-写 :有线程安全问题,可能会存在更新丢失问题

四个隐藏字段

  1. DB_TRX_ID(数据库事务ID)是一个唯一标识符,用于标识数据库中的事务。每当执行一个事务时,会为该事务分配一个唯一的事务ID。这个ID可以用来追踪和管理事务的执行过程,包括提交或回滚事务。

  2. DB_ROLL_PTR(数据库回滚指针)是一个指向回滚段的指针,用于标识事务的回滚记录。回滚段是数据库中用于回滚未提交事务或撤销已提交事务的机制。DB_ROLL_PTR指向回滚段中的特定位置,以便在需要时可以恢复或回滚事务。

  3. DB_ROW_ID(数据库行ID)是用于唯一标识数据库表中的行的标识符。每个行都有一个唯一的DB_ROW_ID,它可以用来引用特定行,无论表中的任何其他变化。DB_ROW_ID可以用作行级别的操作和跟踪更改。

  4. 实际还有一个删除flag隐藏字段, 既记录被更新或删除并不代表真的删除,而是删除flag变了

事务id

每个事务都会有自己的事务ID,可以根据事务ID的大小,决定事务到来的先后顺序。

undo日志

它是mysql内的一块缓冲区。 MySQL 将来是以服务进程的方式,在内存中运行。索引,事务,隔离性,日志等,都是在内存中完成的,即在 MySQL 内部的相关缓冲区中,保存相关数据,完成各种判断操作。然后在合适的时候,将相关数据刷新到磁盘当中的。

所以,这里理解undo log,简单理解成,就是 MySQL 中的一段内存缓冲区,用来保存日志数据的就行

什么是快照

当事务开始时,它会创建一个一致性快照,该快照包含了事务开始时的数据库状态。事务读取数据时,只能看到在快照创建之前已经提交的版本。

创建快照时,数据库系统会将当前的数据状态复制并保存为一个副本,通常以某种形式存储在磁盘上。这个副本在创建时是静态的,不会随着数据库中数据的变动而改变。因此,无论后续对数据库的更改如何,快照仍然保持原始创建时的数据状态。

快照和历史版本的区别

快照看作是数据库在某个时刻的静态拷贝,用于提供一致性的读取操作。快照在可重复读和串行化隔离级别下使用,为事务提供一致的数据视图,以防止读取到不一致的数据。

历史版本是指数据库中某个数据项在不同时间点上的不同状态。这些历史版本可以用于回滚事务、执行数据恢复操作或者提供某种形式的时间旅行功能。

当前读和快照读

当前读就是直接读取最新的数据,但是读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

快照读:读取历史版本(一般而言),就叫做快照读。快照读读到的可能是最新版本,也可能是历史版本。因为一个数据被记录了多个版本。

对于插入、更新、删除来说,只能是当前读。

而select是有两种读取的,分别是当前读和快照读。

这也是为什么当我们在多个事务同时进行增删改的时候,为什么我们读取的时候能根据隔离级别的不同而读取到不同的数据。 由隔离级别决定了我们看到的版本不同,可能是当前版本,也可能是历史版本。

Read View

读视图是事务执行快照读操作时创建的。它定义了事务可以看到的数据版本,限定了事务所能读取的数据范围。

创建一个视图以后,里面会有自己修改的版本的ID,如果我们去遍历版本链表的时候,找到一个比当前ID还要小的ID,说明这个版本的事务早就已经提交了,然后还要遍历链表继续找。

至此,相当于既有了新数据又有了老数据,形成了一个历史版本链。那么我们需要回滚的时候,直接将老数据覆盖新数据即可。

如果事务被提交,这个缓冲区就被清理了,所以无法回滚。上面的一个一个版本,我们可以称之为一个一个的快照

mvcc意义

在多个事务同时删改查的时候,都是当前读,是要加锁的。那同时有select过来,如果也要读取最新版(当前读),那么也就需要加锁,这就是串行化。
但如果是快照读,读取历史版本的话,是不受加锁限制的。也就是可以并行执行!换言之,提高了效率,即MVCC的意义所在

最后总结就是:隔离性代表每个不同的事务会看到不同的版本,而具体看到哪个版本由隔离级别决定。

CURD不加控制,会有什么问题

如果不加控制地执行CURD操作(增加、查询、更新、删除),可能会产生以下问题:

  1. 数据不一致性:例如,一个用户正在更新某个数据,而另一个用户同时进行查询,可能会读取到更新之前的旧数据,导致数据的不一致。

  2. 丢失更新:多个用户同时对同一数据进行更新操作时,最后提交的更新可能会覆盖前面的更新,造成数据丢失的问题。

  3. 脏读(Dirty Read):脏读是指一个事务读取了另一个未提交的事务所做的修改。如果不加控制地执行查询操作,在一个事务中读取到了另一个未提交事务的数据,可能会导致读取到不准确的数据,进而产生错误的结果。

  4. 不可重复读(Non-repeatable Read):不可重复读是指在同一个事务中,多次读取同一数据,但在读取过程中发现数据已发生变化。如果不加控制地执行查询操作,在同一个事务中多次读取同一数据,由于其他并发事务的修改,可能导致每次读取到的数据不一致,破坏了数据的一致性。

  5. 幻读(Phantom Read):幻读是指在同一个事务中多次进行查询操作,但结果集的行数发生了变化。如果不加控制地执行查询操作,在同一个事务中多次查询相同的条件,由于其他并发事务的增删操作,可能会导致结果集的行数不一致,出现幻读的情况。

通过加入适当的并发控制机制,如事务隔离级别、锁机制、并发控制算法等,可以解决以上问题,确保数据库的数据一致性和正确性。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值