时过一年重新拾起博文记录,希望后面都能坚持下来。 接着之前MySql的学习,先记录下这篇。
以下都是基于mysql8 innodb存储引擎进行分析的。
步骤 | 事务1 | 事务2 |
1 |
设置隔离级别 mysql> set @@session.transaction_isolation |
|
2 |
开启事务1 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; Empty set (0.00 sec) |
|
3 |
无需管隔离级别,只开启事务2并插入记录
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 1, ‘1‘; Query OK, 1 row affected (0.00 sec) Records: 1 Duplicates: 0 Warnings: 0 |
|
4 |
此时能查到事务2中未提交事务中的数据,这就是脏读。 mysql> select * from t; +------+------+ | id | name | +------+------+ | 1 | 1 | +------+------+ 1 row in set (0.00 sec) |
1 mysql> show variables like ‘%isolation%‘; 2 +-----------------------+------------------+ 3 | Variable_name | Value | 4 +-----------------------+------------------+ 5 | transaction_isolation | READ-UNCOMMITTED | 6 +-----------------------+------------------+ 7 1 row in set (0.00 sec)
步骤 | 事务1 | 事务2 |
1 | 先设置隔离级别
mysql> set @@session.transaction_isolation |
|
2 | 开启事务1,查询t表记录为空
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; Empty set (0.00 sec) |
|
3 |
无需管隔离级别,只开启事务2并插入记录 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 2, ‘2‘; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 |
|
4 |
继续查询表t依然显示为空 (没有读取到事务2未提交的数据,所以不存在脏读问题) mysql> select * from t; Empty set (0.00 sec) |
|
5 |
提交事务2 mysql> commit; |
|
6 |
继续查询表t,此时能查询事务2已提交的数据记录(出现前后查询不一致) mysql> select * from t; +------+------+ | id | name | +------+------+ | 2 | 2 | +------+------+ |
步骤 | 事务1 | 事务2 |
1 |
设置隔离级别 mysql> set @@session.transaction_isolation |
|
2 |
开启事务1,并查询 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +------+------+ | id | name | +------+------+ | 3 | 3 | +------+------+ |
|
3 |
无需管隔离级别,只开启事务2并插入记录 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> insert into t select 4, ‘4‘; Query OK, 1 row affected (0.01 sec) Records: 1 Duplicates: 0 Warnings: 0 |
|
4 | 继续查询表t依然只有一条记录id=3
(没有读取到事务2未提交的数据,所以不存在脏读问题) mysql> select * from t; +------+------+ | id | name | +------+------+ | 3 | 3 | +------+------+ |
|
5 |
将第二个窗口中的事务提交。
mysql> commit; |
|
6 | 继续查询表t依然只有一条记录id=3
(没有读取到事务2已提交的数据,所以不存在不可重复读问题) mysql> select * from t; +------+------+ | id | name | +------+------+ | 3 | 3 | +------+------+ |
|
7 |
接着插入一条4的记录,但提示插入不了,提示主键冲突问题。
然而查询却没有这条id=4记录。 这就是幻读现象。
mysql> insert into t select 4, ‘4‘; ERROR 1062 (23000): Duplicate entry ‘4‘ for key ‘PRIMARY‘ mysql> select * from t; +----+------+ | id | name | +----+------+ | 3 | 3 | +----+------+ 1 row in set (0.00 sec) |
|
8 | 另一种幻读现象:接着上面操作,不插入记录只更新记录,将name 更新成 ‘5‘后,发现有两行受影响 | |
mysql> update t set name = ‘5‘; Query OK, 2 rows affected (0.00 sec) Rows matched: 2 Changed: 2 Warnings: 0 mysql> select * from t; +----+------+ | id | name | +----+------+ | 3 | 5 | | 4 | 5 | +----+------+ |
步骤 | 事务1 | 事务2 |
9 |
查询时加上间隙锁 mysql> begin; mysql> select * from t where id > 0 for update; +----+------+ | id | name | +----+------+ | 3 | 5 | | 4 | 5 | +----+------+
|
|
10 |
插入记录为6的数据就会发现插入这条记录获取锁超时,自动异常 insert into t select 6, ‘6‘; ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
|
1、脏读:在一个事务中会读取到其未提交事务的数据,此种现象也称之为脏读
2、不可重复读:一个事务可以读取另一个已提交的事务,多次读取会造成不一样的结果。这种现象也被称为不可重复读
3、幻读:基于可重复读的基础上查询结果是一样的,但是当对某些行进行更新或者插入时却会受到影响操作不了,就形成了幻读。
隔离级别
|
脏读
|
不可重复读
|
幻读
|
读未提交(uncommitted read)
|
可能出现
|
可能出现
|
可能出现
|
读提交(committed read)
|
不会出现
|
可能出现
|
可能出现
|
可重复读(Repeatable Read)
|
不会出现
|
不会出现
|
可能出现(加上间隙锁就不会)
|
可串行化(Serializable)
|
不会出现
|
不会出现
|
不会出现
|
《MySql 技术内幕(Innodb)第二版》
https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html
原文:https://www.cnblogs.com/yuanfy008/p/14285344.html