数据库篇(2)--数据库隔离级别及脏读、不可重复读、幻读

一、数据库隔离级别


1.未提交读(Read uncommitted)

  • 未提交读,事务可以读取其他事务未提交的数据,存在脏读问题。

A事务中未提交的内容,在B事务中都可见。如果A事务回滚,B事务读到的数据就是脏数据。

 

2.已提交读(Read committed)

  • 事务只能看到其他事务已经提交的修改。

解决了脏读问题,但有不可重复读的问题,即同一个事务多次执行同样的查询语句不一样。

3.可重复读(Repeatable read)

  • 避免了不可重复读的问题,即能够保证在同一个事务中,多次执行相同的查询的结果是一样的(当前事务的不对该记录修改的前提下),但是存有幻读的问题。

4.可串行化(Serializable)

  • 所有的事务串行进行执行,会在读取的每一行数据都加上锁,可能导致大量的超时和锁争用。因为事务的串行执行,也就避免了幻读的问题。另外考虑到效率的问题,这种级别很少被使用。

备注:

        MySQL默认使用RR(可重复读)隔离级别的原因主要涉及数据一致性、并发性能和实际应用需求。        

二、脏读、不可重复读、幻读


1.脏读:

  • 指一个事务读了另外一个事务未提交的数据

2.不可重复读:

  • 在一个事务内读取表中的某一行数据,多次读取结构不同。

如在一个事务中,两次查询同一用户的剩余金额可能会不一样(由于另一个事务对该用户的金额进行了修改),这种问题被称为不可重复读。

3.幻读:

  • 是指一次事务里,多次查询后,结果集的个数不一致的情况。

一个事务查询某个范围的记录时,其他的事务在这个范围插入了新的记录,导致当前事务查询时会发现比之前查询多了一行记录,就像出现了幻觉一样,称为幻读。

隔离级别

脏读(Dirty Read)

不可重复读(NonRepeatable Read)

未提交读(Read uncommitted)

可能

可能

已提交读(Read committed)

不可能

可能

可重复读(Repeatable read)

不可能

不可能

可串行化(Serializable)

不可能

不可能

备注:

1)在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);

2)在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。

3)需要注意的是以上只是SQL的标准,在实现中并不一定按照标准来,如Innodb引擎通过MVCC(多版本并发控制)在REPEATABLE READ级别解决了幻读的问题。

4)查看当前事务隔离级别命令:

SELECT @@tx_isolation;

5)设置事务隔离级别的命令:

SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]

6)InnoDB如何解决幻读

InnoDB 通过 Next-Key Lock(临键锁)MVCC(多版本并发控制) 的组合机制解决幻读问题。

6-1)临键锁(Next-Key Lock):通过锁定索引记录及间隙,物理上阻止其他事务插入新数据。

        6-1-1)写入操作(INSERT/UPDATE/DELETE):对涉及的范围加临键锁,禁止其他事务插入新数据。

6-2)MVCC:通过一致性视图,逻辑上屏蔽其他事务的修改。

        6-2-1)原理:InnoDB 为每行数据维护多个版本(通过 undo log 实现),每个事务在启动时生成一个一致性视图(Read View),只能看到该视图生成前已提交的数据。

  • 快照读(Snapshot Read):普通 SELECT 语句基于 Read View 读取历史版本数据。
  • 当前读(Current Read)SELECT ... FOR UPDATEUPDATEDELETE 等操作读取最新数据并加锁。

6-2-2)避免幻读的两种场景

  • 快照读:通过 MVCC 读取一致性视图,其他事务的插入操作对当前事务不可见。
  • 当前读:通过临键锁阻塞其他事务的插入操作。

7)Mysql的行级锁到底锁的是什么

        7-1)行级锁:每次锁定的是一行数据的锁机制就是行级别锁定(row-level)。MySQL的行级锁在InnoDB存储引擎中具体锁定的是索引记录,而非物理数据行

        InnoDB的行级锁本质上是通过索引锁定索引记录,结合记录锁、间隙锁和临键锁机制,确保并发事务的数据一致性。

        7-2)行级锁的基础

  • 索引依赖:InnoDB的行级锁通过索引实现。若查询条件使用索引,则锁定对应的索引项;若无索引可用,InnoDB会退化为表级锁,导致并发性能下降。
  • 锁类型:共享锁(S锁):允许其他事务读取被锁行,但禁止修改(如 SELECT ... LOCK IN SHARE MODE)。
  • 排他锁(X锁):禁止其他事务读取或修改被锁行(如 SELECT ... FOR UPDATEUPDATEDELETE)。

        7-3)锁定的具体内容

  • 记录锁(Record Lock):锁定索引中的特定记录。例如,执行 UPDATE users SET name='Alice' WHERE id=10 时,若 id 是主键,则直接锁定主键索引中 id=10 的记录。
  • 间隙锁(Gap Lock):锁定索引记录之间的间隙,防止其他事务插入新数据。例如,当前索引值为10和20,间隙锁可能锁定 (10, 20) 区间,阻止插入 id=15 的记录。
  • 临键锁(Next-Key Lock):记录锁 + 间隙锁的组合,锁定一个左开右闭区间。如锁定 (10, 20],防止插入 id=15 或修改 id=20 的记录。主要用于可重复读(REPEATABLE READ) 隔离级别,解决幻读问题。

 更多内容:

数据库篇(1)--数据库事务的四大特性(ACID)

数据库篇(2)--数据库隔离级别及脏读、不可重复读、幻读

数据库篇(3)--MySQL存储引擎InnoDB和MyISAM区别及使用场景

数据库篇(4)--索引

数据库篇(5)-- sql 优化

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sun cat

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

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

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

打赏作者

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

抵扣说明:

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

余额充值