什么是脏读不可重复读幻读?一文带你快速搞定mysql事务隔离级别(代码片段)

c. c.     2023-01-18     376

关键词:

什么是脏读、不可重复读、幻读?一文带你快速搞定MySQL事务隔离级别

事务

既然要讲事务隔离级别,那我们肯定要来先说一下事务这个概念。

那什么是事务呢?

我们可以看到oracle的解释是:

A transaction is a logical, atomic unit of work that contains one or more SQL statements.

参考:https://docs.oracle.com/database/121/CNCPT/transact.htm#CNCPT117

我们一提到事务就会想到ACID这四个特性,但事务的定义本身并不具备这四个特性。事务只是一个改变,是一些的操作集合;用专业的术语去解释,就是一个程序的执行单元,只是保证了这个执行单元中的SQL要么都执行要么都撤销;我们需要通过某些手段,尽可能让这个执行单元满足这四个特性,那么,我们就可以称它是一个事务,或者说是一个正确的,完美的事务。(这里先举个栗子,比如在读未提交的隔离级别下,它不满足隔离性,但是它确实是一个事务,最完美的事务应该就是串行化隔离级别的事务了,这是对事务的隔离特性的完美实现,也是事务隔离特性的要求)

ACID四个特性

原子性(Atomicity)

All tasks of a transaction are performed or none of them are. There are no partial transactions. For example, if a transaction starts updating 100 rows, but the system fails after 20 updates, then the database rolls back the changes to these 20 rows.

满足原子操作单元,对数据的操作,要么全部执行,要么全部不执行。

ACID 模型的原子性方面主要涉及InnoDB 事务。

The atomicity aspect of the ACID model mainly involves InnoDB transactions. Related MySQL features include:

  • The autocommit setting.
  • The COMMIT statement.
  • The ROLLBACK statement.

一致性(Consistency)

The transaction takes the database from one consistent state to another consistent state. For example, in a banking transaction that debits a savings account and credits a checking account, a failure must not cause the database to credit only one account, which would lead to inconsistent data.

事务应确保数据库的状态从一个一致状态转变为另一个一致状态。即事务开始和完成时,数据都必须保持一致。

ACID 模型的一致性方面主要涉及InnoDB保护数据免受崩溃的内部处理

The consistency aspect of the ACID model mainly involves internal InnoDB processing to protect data from crashes. Related MySQL features include:

  • The InnoDB doublewrite buffer.
  • InnoDB crash recovery.

隔离性(Isolation)

The effect of a transaction is not visible to other transactions until the transaction is committed. For example, one user updating the hr.employees table does not see the uncommitted changes to employees made concurrently by another user. Thus, it appears to users as if transactions are executing serially.

多个事务并发执行时,一个事务的执行不应影响其他事务的执行。事务之间相互独立,中间状态对外部不可见。

ACID 模型 的隔离方面主要涉及InnoDB 事务的隔离级别。

The isolation aspect of the ACID model mainly involves InnoDB transactions, in particular the isolation level that applies to each transaction. Related MySQL features include:

  • The autocommit setting.
  • Transaction isolation levels and the SET TRANSACTION statement

持久性(Durability)

Changes made by committed transactions are permanent. After a transaction completes, the database ensures through its recovery mechanisms that changes from the transaction are not lost.

已被提交的事务对数据库的修改应该永久保存在数据库中。数据的修改是永久性的,即使系统出现任何故障都能够保持。

The durability aspect of the ACID model involves MySQL software features interacting with your particular hardware configuration. Because of the many possibilities depending on the capabilities of your CPU, network, and storage devices, this aspect is the most complicated to provide concrete guidelines for. (And those guidelines might take the form of “buy new hardware”.) Related MySQL features include:

  • The InnoDB doublewrite buffer.
  • The innodb_flush_log_at_trx_commit variable.
  • The sync_binlog variable.
  • Theinnodb_file_per_table variable.
  • The write buffer in a storage device, such as a disk drive, SSD, or RAID array.
  • A battery-backed cache in a storage device.
  • The operating system used to run MySQL, in particular its support for the fsync() system call.
  • An uninterruptible power supply (UPS) protecting the electrical power to all computer servers and storage devices that run MySQL servers and store MySQL data.
  • Your backup strategy, such as frequency and types of backups, and backup retention periods.
  • For distributed or hosted data applications, the particular characteristics of the data centers where the hardware for the MySQL servers is located, and network connections between the data centers.

可以参考一下MySQL官方文档:https://dev.mysql.com/doc/refman/8.0/en/mysql-acid.html

按照严格的标准,只有同时满足ACID特性才是事务;但是在各大数据库厂商的实现中,真正满足ACID的事务少之又少。例如MySQL的NDB Cluster事务不满足持久性和隔离性;InnoDB默认事务隔离级别是可重复读,不满足隔离性;Oracle默认的事务隔离级别为READ COMMITTED,不满足隔离性……因此与其说ACID是事务必须满足的条件,不如说它们是衡量事务的四个维度。

所以我在开头也说了,事务并不是满足这四个条件才叫做事务,这一点希望大家也能够明白。

事务隔离级别

前面提到了可串行化是最完美的隔离级别,但是串行的并发能力是最差的,
但是如果提供并发能力(破坏隔离性)往往会破坏数据的一致性,因此需要在并发量和一致性之间找到一个平衡。最后大佬们根据对数据一致性破坏的程度将事务的隔离性区分了4个级别,一致性破坏造成的影响区分为: 脏读、幻读、不可重复读,这就是ANSI SQL-92标准

下面就讲一下提高并发能力,在多个事务并发执行的时候会引发哪些问题?

多个事务并发执行时引发的问题

一般情况下,多个单元操作(事务,这里的事务,并不是完美的事务,文章最开始提到的)并发执行,会出现这么几个问题。

脏读

脏读:A事务还未提交,B事务就读到了A操作的结果。

1、在事务A执行过程中,事务A对数据资源进行了修改,事务B读取了事务A修改后的数据。

2、由于某些原因,事务A并没有完成提交,发生了RollBack操作,则事务B读取的数据就是脏数据。

这种读取到另一个事务未提交的数据的现象就是脏读(Dirty Read)。

参考:https://www.zhihu.com/question/458275373

下面就来演示一下什么是脏读,这里涉及到事务的隔离级别,后面会讲,这里可以先不用太关心。

首先我们创建一个表,还有插入一条数据。

create table test_tb(
     id varchar(60) primary key  ,
     name varchar(30)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into test_tb value (1,'Kevin');

然后我们打开一个新的窗口, 我们查看当前窗口的事务隔离级别

SELECT @@GLOBAL.tx_isolation, @@tx_isolation; -- MYSQL8之前

SELECT @@GLOBAL.transaction_isolation, @@transaction_isolation; -- MYSQL8之后

可以看到我们的隔离级别是REPEATABLE-READ

然后我们把当前的窗口,也就是当前的session的隔离级别改成READ-UNCOMMITTED

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 修改当前session的隔离级别为读未提交

然后我们再看看当前session的事务隔离级别

现在我们的准备工作做好了,我们再打开一个新的窗口,这个窗口的隔离级别是REPEATABLE-READ

首先我们在REPEATABLE-READ这个窗口开启一个事务,然后执行一个update操作,但是我们不提交数据。

-- REPEATABLE-READ
start transaction ;
update test_tb set name = 'KEVIN' where id = 1;

正常来说,如果我们再打开一个REPEATABLE-READ的新窗口,这个时候是读不到未提交的update后的数据。只有执行update操作的那个事务里面才能读取到。

但是在READ-UNCOMMITTED级别下,是能够读取到未提交的数据。

所以这个时候就出现了脏读,读取到了未提交的数据,这个很显然就是破坏了ACID四个特性中的隔离性了。

不可重复读

不可重复读:A事务在本次事务中,对自己未操作过数据,进行多次读取,结果数据出现不一致(重点是update)

事务B读取了两次数据资源,在这两次读取的过程中事务A修改了数据,导致事务B在这两次读取出来的数据不一致。

这种在同一个事务中,前后两次读取的数据不一致的现象就是不可重复读(Nonrepeatable Read)。

现在我们演示一下不可重复读的情况。

首先我们还是打开一个新的窗口,我们把当前的session的隔离级别改为读已提交,在读已提交的隔离级别下是不会出现脏读的,可以参考上面脏读的例子去试一试,这里就不展示了。但是在读已提交的隔离级别下,还是会出现不可重复读的情况。

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED ; -- 修改当前session的隔离级别为读已提交

然后我们开启事务并且查看数据。

start transaction ;
select * from test_tb; -- READ-COMMITTED

然后我们打开另一个新的窗口,这个窗口依然还是REPEATABLE-READ,然后我们修改数据并提交,这里跟脏读的区别是,我们开启了事务并且进行了提交。

-- REPEATABLE-READ
start transaction ;
update test_tb set name = 'KEVIN' where id = 1;
commit;

然后我们回到我们之前READ-COMMITTED的窗口,在事务中继续查看数据,然后我们发现我们两次读取的数据不一样了,第一次读取到的是Kevin,第二次读取到的是KEVIN

所以这种在同一个事务中,前后两次读取的数据不一致的现象就是不可重复读。

幻读

幻读:A事务在本次事务中,前后两次读取的数据记录条数不一致(主要是新增和删减)

可以看看MySQL官方的定义:

The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.

参考:Phantom Rows

我们来演示一下幻读的情况,首先我们还是打开窗口,设置当前的隔离级别为REPEATABLE-READ

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ; -- 修改当前session的隔离级别为可重复读

在可重复读的隔离级别下是不会出现不可重复读的情况,可以参照上面不可重复读的例子操作一下,结果是读取的还是原来的数据,这里就不演示了,我们来演示幻读的情况。

首先我们DB里面一样只有一条数据。

我们在REPEATABLE-READ的窗口中开启一个事务,然后查看数据,确实是一条数据

start transaction ;
select * from test_tb; -- REPEATABLE-READ
select count(*) from test_tb; -- REPEATABLE-READ

然后我们开启一个新的窗口,默认也是REPEATABLE-READ的隔离级别。

然后我们开启事务并插入一条数据

-- REPEATABLE-READ
start transaction ;
insert into test_tb value (2,'Kevin');
select count(*) from test_tb;
commit;

可以看到现在是两条数据了。

然后我们回到之前的窗口,也就是最开始还没提交事务的窗口。这个时候我们查看一下数量。

可以发现我们的数据条数还是一条,但是我们这个时候执行一个update语句。

update test_tb set name = 'KEVIN' where name = 'Kevin';
start transaction ;
select * from test_tb; -- REPEATABLE READ
select count(*) from test_tb; -- REPEATABLE READ
update test_tb set name = 'KEVIN' where name = 'Kevin';

可以发现执行的时候却是影响了两条记录,就好像出现了幻觉一样,所以这个现象就是幻读

MySQL四个事务隔离级别

事务隔离级别脏读不可重复读幻读
读未提交(read-uncommitted)
不可重复读(read-committed)-
可重复读(repeatable-read)--
串行化(serializable)---

这里需要注意的一个点是,在SQL标准中,RR是无法避免幻读问题的,但是InnoDB实现的RR避免了一些幻读问题。(使用MVCC和next-key lock)。RR虽然避免了部分幻读问题,但是毕竟不是Serializable,不能保证完全的隔离。

关于这部分的问题,到时候我会来详细的讲一讲MVCC还有InnoDB的RR是如何解决幻读问题的,给自己挖一个坑先。

参考

https://docs.oracle.com/database/121/CNCPT/transact.htm#CNCPT117

什么是脏读、不可重复读、幻读?

搞懂MySQL对事务的破坏与补救措施,扫清对事务的误区

https://github.com/hongwen1993/all/blob/master/database/Isolation.md

【MySQL】事务与隔离级别(99%的人存在误区)

直接写SQL给你演示什么是脏读 幻读 可重复读,思路清晰

四个案例看懂 MySQL 事务隔离级别

ANSI SQL-92标准

面试官一上来就问Mysql:幻读到底是什么?

mysql幻读(幽灵问题 phantom problem)

https://dev.mysql.com/doc/refman/5.6/en/innodb-next-key-locking.html

MySQL逻辑架构及性能优化原理

深入学习MySQL事务:ACID特性的实现原理

mySQL数据库间隙锁(mysql是如何解决幻读的)

InnoDB Multi-Versioning

InnoDB Locking

脏读不可重复读幻读

脏读(DirtyRead)    脏读意味着一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚  不可重复读(UnrepeatableRead)     不可重复读意味着,在数据库访问中,一个事务范围内两个... 查看详情

mysql理论:脏读不可重复读幻读(代码片段)

文章目录1.脏读(dirtyread)脏读是指事务读取到其他事务未提交的数据2.不可重复读(non-repeatableread)不可重复读是指在同一次事务中前后查询不一致的问题3.幻读(phantomread)幻读是一次事务中前后数据量发生变化,用户产生不可预... 查看详情

mysql理论:脏读不可重复读幻读(代码片段)

文章目录1.脏读(dirtyread)脏读是指事务读取到其他事务未提交的数据2.不可重复读(non-repeatableread)不可重复读是指在同一次事务中前后查询不一致的问题3.幻读(phantomread)幻读是一次事务中前后数据量发生变化,用户产生不可预... 查看详情

脏读不可重复读幻读

脏读:一个事务读取到了另外一个事务没有提交的数据         事务1:更新一条数据                  &nbs 查看详情

脏读不可重复读幻读

 1.脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。2.不可重复读:是指在一个事务内,多次读同一数据... 查看详情

快速理解脏读,不可重复读,幻读(代码片段)

...几个问题。√为会发生,×为不会发生:隔离级别脏读不可重复读幻读readuncomm 查看详情

数据库事务隔离级别--脏读幻读不可重复读

...peatableread 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读 这几类问题。√:可能出现    ×:不会出现&nbs 查看详情

关于脏读幻读和不可重复读

1.脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 e.g.        1.Mary的原工资... 查看详情

何为脏读不可重复读幻读(代码片段)

2.0前言事务的隔离性是指多个事务并发执行的时候相互之间不受到彼此的干扰的特性,隔离性是事务ACID特性中的I,根据隔离程度从低到高分为ReadUncommitted(读未提交),ReadCommitted(读已提交),RepeatableRead(可重复读),Seriali... 查看详情

数据库的脏读幻读不可重复读

1.脏读:指一个事务A正在访问数据,并且对该数据进行了修改,但是这种修改还没有提交到数据库中(也可能因为某些原因Rollback了)。这时候另外一个事务B也访问这个数据,然后使用了这个被A修改的数据,那么这个数据就是... 查看详情

数据库-脏读不可重复读幻读。

...,如果此时事务B数据回滚,事务A仍然是使用旧的数据即是脏的数据。顺序事务A事务B1开始事务2开始事务3查询余额2000元4取出1000元剩余1000元5查询余额剩余1000元(脏读)6产生异常事务发生回滚,余额剩余2000元7转入2000元,余额为3000... 查看详情

什么是脏读,不可重复读,幻读

1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。2. 不可重复读 :是指在一个事务内,多... 查看详情

什么是脏读,幻读和不可重复读

参考技术A1.脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。2.不可重复读:是指在一个事务内,多次读同一... 查看详情

什么是脏读,不可重复读,幻读

这三者都是数据库事务的错误情况。1、脏读:事务A读到了事务B未提交的数据。2、不可重复读:事务A第一次查询得到一行记录row1,事务B提交修改后,事务A第二次查询得到row1,但列内容发生了变化。3、幻读:事务A第一次查询... 查看详情

数据库脏读不可重读读幻读

脏读:脏读是读到了别的事务回滚前的脏数据。比如事务B执行过程中修改了数据X,在未提交前,事务A读取了X,而事务B却回滚了,这样事务A就形成了脏读。也就是说,当前事务读到的数据是别的事务想要修改成为的但是没有修... 查看详情

五分钟了解mysql脏读幻读不可重复读mvcc(代码片段)

点击上方关注“终端研发部”设为“星标”,和你一起掌握更多数据库知识首先对多事务并发的问题的思考对innodb引擎执行流程 和bufferpool足够了解的话,那一定知道mysql系统在初始化的时候bufferpool会将内存分为多个缓... 查看详情

快速理解脏读,不可重复读,幻读(代码片段)

...几个问题。√为会发生,×为不会发生:隔离级别脏读不可重复读幻读readuncommitted(未提交读)√√√readcommitted(提交读)×√√repeatableread(可重复读)××√serialization(可串行化)×&time... 查看详情

mysql锁与脏读不可重复读幻读详解(代码片段)

最近,在一次mysql死锁的生产事故中,我发现,关于mysql的锁、事务等等,我所知道的东西太碎了,所以,我试着用几个例子将它们串起来。具体做法就是通过不断地问问题、回答问题,再加上“适当”... 查看详情