Mysql demonstrates dirty read, non-repeatable read, and phantom read

What I want to demonstrate today is the isolation level of Mysql transaction isolation.
Briefly introduce the four major characteristics of transactions

InnoDB transaction principle

  • Transaction (Transaction) is one of the important characteristics that distinguish the database from the file system. The transaction converts the database from one consistency state to another consistency state.
  • When the database is submitted, it can be ensured that either all modifications have been saved, or all modifications are not saved.

Transaction (ACID) characteristics

  • Atomicity: All operations of the entire thing are either submitted successfully or all failed and rolled back (partial execution will not occur).
  • Consistency: For several transactions executed in parallel, the execution result must be consistent with the result of serial execution in a certain order.
  • Isolation (Isolation): The execution of the transaction is not interfered by other transactions, and the intermediate results of the execution of the transaction must be transparent to other transactions.
  • Durability: Once a transaction is committed, the changes to the data in the database are permanent. Even if the database system encounters a failure, the operation of committing the transaction will not be lost.
Transaction isolation level
  • Uncommitted read: dirty read (READ UNCOMMITTED) read uncommitted

  • Submit read: non-repeatable read (READ COMMITTED)

  • Repeatable read: phantom read (REPEATABLE READ): This is MySQL's default transaction isolation level

  • Serial Readable (SERIALIZABLE) Serialization & Serial Read

    Under this isolation level, the dirty read, non-repeatable read, and phantom read problems that appeared before can be solved, but it will also cause a large number of timeouts and lock competitions. It is generally not recommended to use

√ means it will happen, × means it will not happen

Isolation level Dirty read Non-repeatable Phantom reading
read uncommitted (uncommitted read)
read committed ×
repeatable read × ×
serializable (serializable) × × ×
表格借鉴的Java识堂(https://blog.csdn.net/weixin_44685869/article/details/104105291)

Some MySQL commands used in this article

# 查看 MySQL 版本
select version()

# 查看 MySQL 隔离级别
SELECT @@tx_isolation

# MySQL在会话层面设置隔离级别
set session transaction isolation level 隔离级别名字

# 开启事务
start transaction

# 提交事务
commit

# 回滚事务
rollback
1234567891011121314151617

Create libraries, tables, and view.

# 创建 demo01 数据库
create database demo01

use demo01

# 创建测试表
create table test01(
	id int(3) not null primary key auto_increment,
	name varchar(64) default null,
	price int(7) default 0         # 这里不许有逗号
)ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
1234567891011

Insert initial data

insert into test01(name,price) values('张三',100),('李四',0);
1
一切ok 开始干活

Dirty read

The data in the table is as follows, set the isolation level to uncommitted read
Insert picture description here

time Client A (Tab A) Client B (Tab B)
T1 set session transaction isolation level read uncommitted; start transaction; update test01 set price = price + 100 where id = 1; select * from test01 where id = 1; Set as uncommitted read, give Zhang San account +100, Output is 200
T2 set session transaction isolation level read uncommitted; start transaction; select * from test01 where id = 1; query balance output is 200
T3 rollback
T4 commit
T5 select * from test01 where id = 1; query balance output is 100

Dirty read refers to when a transaction is accessing data, and the data is modified, and this modification has not yet been committed to the database, at this time, another transaction also accesses the data, and then uses the data.

Give another serious example to prove the hazard
. The data in the table is as follows
Insert picture description here

time Client A (Tab A) Client B (Tab B)
T1 set session transaction isolation level read uncommitted; start transaction; update test01 set price = price - 100 where id = 1; update test01 set price = price + 100 where id = 2;
T2 set session transaction isolation level read uncommitted; start transaction; select price from test01 where id = 2; update test01 set price = price - 100 where id = 2; 更新语句被阻塞
T3 rollback
T4 commit

After the execution is complete, the data in the database is as follows
Insert picture description here

time Explanation
T1 1 to 2 turn 100
T2 2. The balance of 2 is enough to buy 100 yuan, and the update statement is blocked
T3 1 rolls back, the balance of 1 becomes 100, and the balance of 2 becomes 0
T4 2 Successful deduction, balance 0-100=-100

It's fine now, the bank lost 100 yuan for no reason.

Non-repeatable

The data in the table is as follows, set the isolation level to commit read

Insert picture description here

time Client A (Tab A) Client B (Tab B)
T1 set session transaction isolation level read committed; start transaction; select * from test01 where id = 2; Query balance output is 0
T2 set session transaction isolation level read committed; start transaction; update test01 set price = price + 100 where id = 2; select * from test01 where id = 2; commit; 查询余额输出100
T3 select * from test01 where id = 2; commit; check balance output 100

Non-repeatable read means that in transaction 1, a piece of data is read, and when transaction 1 has not ended, transaction 2 has also accessed the data, modified the data, and submitted it. Immediately afterwards, transaction 1 reads this data again. Due to the modification of transaction 2, the data read twice in transaction 1 may be different, so it is called non-repeatable read.

当然你可以在T2时间段客户端B修改完id=2的账户余额但没有commit的时候,在客户端A查询id=2的账户余额,发现账户余额为0,可以证明提交读这个隔离级别不会发生脏读。

可重复读级别

看一下可重复读是个什么过程?
表中的数据如下,设置隔离级别为可重复读
Insert picture description here

时间 客户端A(Tab A) 客户端B(Tab B)
T1 set session transaction isolation level repeatable read; start transaction; select * from test01 where id = 2; 查询余额输出为0
T2 set session transaction isolation level repeatable read; start transaction; update test01 where set price = price + 100 where id = 2; select * from test01 where where id = 2; commit; 查询余额输出100
T3 select * from test01 where where id = 2; commit; 查询余额输出0

当我们将当前会话的隔离级别设置为可重复读的时候,当前会话可以重复读,就是每次读取的结果集都相同,而不管其他事务有没有提交。

但是在可重复读的隔离级别上,会产生幻读的问题。

幻读

设置隔离级别为可重复读

Insert picture description here

所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。InnoDB存储引擎通过多版本并发控制(MVCC)解决了幻读的问题。

用大白话解释一下,就是事务1查询id<10的记录时,返回了2条记录,接着事务2插入了一条id为3的记录,并提交。接着事务1查询id<10的记录时,返回了3条记录,说好的可重复读呢?结果却多了一条数据。

演示如何解决的幻读,表中的数据如下
Insert picture description here
MySQL通过 MVCC 解决了这种情况下的幻读
MVCC 在我理解 就是类似于乐观锁

时间 客户端A(Tab A) 客户端B(Tab B)
T1 set session transaction isolation level repeatable read; start transaction; select count(*) from test01 where id <= 10; 输出2
T2 set session transaction isolation level repeatable read; start transaction; insert into test01 (id, name, price) values (3, “王五”, 0); select count(*) from test01 where id <= 10; commit; 输出3
T3 select count(*) from test01 where id <= 10; commit; 输出2

这种情况下的幻读被解决了,我再举一个例子

表中的数据如下

Insert picture description here

时间 客户端A(Tab A) 客户端B(Tab B)
T1 set session transaction isolation level repeatable read; start transaction; select count(*) from account where id = 3; 输出为0
T2 set session transaction isolation level repeatable read; start transaction; insert into account (id, name, balance) values (3, “王五”, 0); commit;
T3 insert into account (id, name, balance) values ​​(3, "王五", 0); duplicate primary key, insert failed
T4 select count(*) from account where id = 3; the output is 0
T5 rollback;

Select whether a record exists, does not exist, and is ready to insert this record, but when the insert is executed, it is found that the record already exists and cannot be inserted. This is a problem.

Many people tend to confuse non-repeatable reading and phantom reading. Indeed, the two are somewhat similar. But non-repeatable reading focuses on update and delete, while phantom reading focuses on insert.

In general, phantom reading means transaction A operates on data, transaction B can still use insert to insert data, because row locks are used, and the various strange problems caused by this are phantom reading. There are many manifestations, so I won’t list them. .

When the isolation level is set to serializable, the transaction is forced to be executed serially, avoiding the problem of phantom reading mentioned earlier.

Reference original address: https://blog.csdn.net/zzti_erlie/article/details/88080822


The database uses locks to support better concurrency and provide data integrity and consistency.
InnoDB is a storage engine that supports row locks. The types of locks are:

  • Shared lock (S)
  • Exclusive lock (X)
  • Intention Sharing (IS)
  • Exclusive intention (IX)

In order to provide better concurrency, InnoDB provides non-locking read: do not need to wait for the lock on the access row to be released, read a snapshot of the row. This method is implemented through a feature of InnoDB: MVCC.

InnoDB has three row lock algorithms:

  1. Record Lock: The lock on a single row record.
  2. Gap Lock: Gap lock, lock a range, but does not include the record itself. The purpose of the GAP lock is to prevent the two current reads of the same transaction from phantom reads.
  3. Next-Key Lock: 1+2, lock a range, and lock the record itself. For row queries, this method is used, and the main purpose is to solve the problem of phantom reading.

Guess you like

Origin blog.csdn.net/weixin_47587864/article/details/108563655