共计 1144 个字符,预计需要花费 3 分钟才能阅读完成。
引入
1. 什么是读现象(为什么会有)
- 在数据库系统中, 多个事务的 并发进行 , 在读取数据方面可能遇到一些问题, 包括 : 脏读 、 不可重复读 、 幻读
2. 是否所有数据库都有读现象
- 对于一些数据库管理软件会自带相应的机制去解决脏读、不可重复读、幻读等问题(mysql 的 Rr 机制和 Next-Key Lock 解决这个问题, 下篇文章详细介绍)
- 因为这些自带的机制, 下面的一些实验现象可能在某一数据库管理软件的默认机制下并不成立, 即我们并不能在所有数据库管理软件中看到所有的读现象
- 所以此处我们暂且抛开具体的某个数据库管理软件的默认机制的干扰, 暂时假设没有附加任何机制为前提, 单纯地去理解数据库的读现象
一. 脏读 (dirty read)
- 事务一查询一条记录, id 为 2 的 age 为 18
- 事务一查询后, 事务二对该条数据进行了 age=22 的更改, 但是没有进行提交
- 事务一有进行查询操作, 查询到修改后的记录 age=22
- 事务二进行了回滚操作, 记录中就没有了 id=2, age=22 的记录了, 所以, 事务 1 读到了一条脏数据(也叫无效数据)
二. 不可重复读 (nonrepeatable read)
- 事务一查询一条 id=2 的记录
- 事务二随之对 id 为 2 的记录进行了更改, 并且进行了提交
- 事务一再次查询 id=2 的记录, 发现第二次查询的记录已经发生了改变, 这个就叫做不可重复读
在基于锁的并发控制中不可重复读现象发生在当执行 select 操作时没有获得读锁 (read locks) 或者 select 操作执行完后马上释放了读锁; 多版本并发控制中当没有要求一个提交冲突的事务回滚也会发生不可重复读现象
三. 幻读 (phantom read)
幻读是不可重复读的一种特殊情况, 当事务没有获取范围锁的情况下执行 select 操作可能会发生幻读现象
- 事务一读取或修改了指定 where 子句过滤出来的结果集
- 然后事务二插入了一条新记录, 并且该条记录满足 where 子句的过滤条件
- 紧接着事务一使用相同的查询再次进行检索, 发现看到了事务二刚刚插入的记录, 但刚刚明明已经使用 where 子句过滤修改了这些记录, 就好像 "幻觉'' 一样, 这对于事务一来说是突然出现的, 这就是幻读
四. 解决方案
-
其实脏写、脏读、不可重复读、幻读,都是因为业务系统会多线程并发执行,每个线程可能都会开启一个事务,每个事务都会执行增删改查操作
-
然后数据库会并发执行多个事务,多个事务可能会并发地对缓存页里的同一批数据进行增删改查操作
-
于是这个并发增删改查同一批数据的问题,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。
-
所以这些问题的本质,都是数据库的多事务并发问题
-
那么为了解决多事务并发带来的脏读、不可重复读、幻读等读等问题,数据库才设计了 锁机制、事务隔离机制、MVCC 多版本隔离机制,用一整套机制来解决多事务并发问题, 下篇文章详细介绍这些机制
正文完