【一】数据库读现象的本质
- 是数据库在高并发场景下
- 多个同时执行的事务带来的影响。
【二】数据库三大读现象
- 在数据库中,不同的事务隔离级别可能会导致脏读(Dirty Read)、不可重复读(Non-repeatable Read)和幻读(Phantom Read)等问题的出现。
【1】脏读
(1)概述
- 事务1和事务2并发执行
- 事务1改了数据
- 事务2读取了以后
- 但事务1进行了回滚
- 导致事务2读取的数据有误。
(2)解释
- 脏读是指当一个事务读取了其他事务尚未提交的数据时发生的现象。
- 换句话说,脏读表示读取到的数据并不一定会最终存入数据库中,因此这些数据实际上是不存在的。
- 脏读现象发生在读取到了不一定存在的数据的情况下。
(3)总结
- 脏读指的是读当前事务到了其他事务未提交的数据,未提交意味着这些数据可能会回滚,
- 也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读
【2】不可重复读
(1)概述
- 事务1读取了数据
- 事务2修改了数据并且提交了
- 接着事务1再次读取
- 发现两次的数据不相同
(2)解释
- 不可重复读是指在一个事务内多次读取同一批数据,但在事务结束之前,这批数据可能发生了变化,导致读取结果不一致的情况。
- 不可重复读的产生通常是由于在事务A多次读取同一数据的过程中,事务B对数据进行了更新并提交。
(3)总结
- 解释:不可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据出现不一致的情况
- 导致的原因:事务 A 多次读取同一数据,但事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致
【3】幻读
(1)概述
- 本质上说是不可重复读的一种现象
- 事务1更改或查询了数据
- 在极短时间内,事务2又插入了一条新的数据
- 导致事务1在接下来的查询中
- 就会发现有⼏列数据是它先前所没有的。
(2)错误的理解
[1]解释
- 有时候,人们错误地将幻读理解为在两次select操作中获得了不同的数据集
- 例如第一次select得到10条记录
- 第二次select得到15条记录。
- 实际上,这种情况仍然属于不可重复读而非幻读。
[2]总结
- 幻读是 事务A 执行两次 select 操作得到不同的数据集,即 select 1 得到 10 条记录,select 2 得到 15 条记录。
- 这其实并不是幻读,既然第一次和第二次读取的不一致,那不还是不可重复读吗,所以这是不可重复读的一种。
(3)正确的理解
[1]解释
- 幻读的本质在于某一次select操作得到的结果无法支撑后续的业务操作。
- 具体来说,例如在执行select判断某条记录是否存在时,假设该记录不存在,准备插入该记录,但在执行insert时却发现该记录已经存在,导致无法插入,这即是幻读的发生。
[2]总结
- 幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。
- 更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读
【4】解决办法
- 要解决脏读,不可重复读和幻读的问题
- 我们就要引入几个概念:MVCC机制,事务隔离机制和数据库锁机制。
【三】数据库事务隔离机制
- 事务具有原子性、一致性、隔离性、持久性四大特性
【1】事务的四大特性(ACID)
(1)原子性(Atomicity)
- 事务是一个不可再分割的单位,要么全部执行成功,要么全部回滚到初始状态,没有中间状态。
- 这意味着如果事务中的任何一步操作失败,整个事务都会被回滚,以确保数据的一致性。
(2)一致性(Consistency)
- 事务执行前后,数据库的状态必须保持一致。
- 这意味着事务在执行期间对数据的操作必须满足预定义的规则和完整性约束,以确保数据的有效性和正确性。
(3)隔离性(Isolation)
- 多个事务可能同时执行,事务之间应该相互隔离,互不影响。
- 隔离性确保每个事务的操作在逻辑上独立于其他并发事务的操作,从而避免了数据不一致的问题。
(4)持久性(Durability)
- 一旦事务提交,对数据库的更改应该是永久性的,即使在系统故障的情况下也不应该丢失。
- 持久性通过将事务记录在持久存储介质(如磁盘)上来实现。
【2】隔离性的四种级别
(1)引入
- 而隔离性顾名思义指的就是事务彼此之间隔离开
- 多个事务在同时处理一个数据时彼此之间互相不影响
- 如如果隔离的不够好就有可能会产生脏读、不可重复度、幻读等读现象
- 为此,隔离性总共分为四种级别
- 由低到高依次为
- Read uncommitted(未提交读)
- Read committed (提交读)
- Repeatable read(可重复读)
- Serializable(串行化)
(2)四种级别
[1]Read uncommitted(读未提交)
- 最低的隔离级别,在这个级别下,一个事务可以读取到另一个事务尚未提交的数据,可能导致脏读(Dirty Read)问题,即读取到未经验证的数据。
[2]Read committed(读已提交)
- 在这个级别下,一个事务只能读取到已经提交的数据,避免了脏读问题。
- 但是可能会出现不可重复读(Non-repeatable Read)问题,即同一事务中,两次读取相同的记录可能得到不同的结果,因为其他事务修改了这些记录。
[3]Repeatable read(可重复读取)
- 在这个级别下,事务开始读取数据后,其他事务无法修改这些数据,保证了同一个事务内两次读取相同记录的一致性。
- 但是可能会出现幻读(Phantom Read)问题,即同一查询在同一事务中两次执行可能返回不同的结果,因为其他事务插入或删除了符合查询条件的记录。
[4]Serializable(串行化)
- 最高级别的隔离级别,要求事务串行执行,事务之间完全隔离,避免了脏读、不可重复读和幻读问题。
- 但是这会牺牲并发性能,因为并发事务被限制为顺序执行。
【3】四大隔离级别解决了什么问题
- Read uncommitted(读未提交)
- 存在脏读、不可重复读和幻读问题。
- Read committed(读已提交)
- 解决了脏读问题,但仍可能出现不可重复读和幻读。
- Repeatable read(可重复读取)
- 解决了脏读和不可重复读问题,但仍可能出现幻读。
- Serializable(串行化)
- 解决了脏读、不可重复读和幻读问题,但在效率方面有所牺牲。
【4】MySQL的存储引擎默认的隔离级别
- Repratable read (可重复读)
【5】幻读的解决办法
- MySQL引入了Next-key lock的行级锁来解决,我们将会在下一节里详细叙述
【四】MVCC机制
【1】什么是MVCC机制
- MVCC是MySQL InnoDB存储引擎实现的一种基于多版本的并发控制协议。
- 基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control) 。
【2】MVCC的优势
- MVCC实现了读不加锁,避免了读写冲突,提高了系统的并发性能。
- MVCC解决了数据的脏读问题,保证了数据的一致性。
【3】MVCC的读操作
- MVCC的并发控制的系统中,读操作可分为两类:当前读和快照读。
(1)快照读
- 快照读是指对数据库进行简单的select操作时,不会加锁,而是通过查询当前事务开始时的系统时间点,获取该时间点之前的数据副本。
- 由于每个事务都有自己的时间点,所以每个事务看到的都是自己创建时的状态,从而避免了脏读的发生。
(2)当前读
- 特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
- 当前读是指对数据库进行插入、更新或删除操作时,需要加锁,以防止其他事务修改已经锁定的数据。只有当事务完成所有更新后,才会将其提交到数据库,并释放所有的锁。
- 这种机制可以确保数据的一致性和完整性,但会降低系统的并发性能。