mysql隔离级别容易理解的方法

Posted 梁俊俊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql隔离级别容易理解的方法相关的知识,希望对你有一定的参考价值。

开始我以为图像会容易理解mysql隔离级别,后面看到这个文章,发现这个代码容易理解了,只是有些部分有小错误,和排版看的不容易,就加以修改转来了
关于mysql隔离级别的实验

简介

SQL定义了四种隔离级别。包括

  • READ UNCOMMITED(未提交读)
  • READ COMMITED(提交读)
  • REPEATABLE READ(可重复读)
  • REPEATABLE READ(可串行化)

其区别在于
表1

隔离级别脏读可能性不可重复读可能性幻读可能性加锁读
READ UNCOMMITEDYesYesYesNo
READ COMMITEDNoYesYesNo
REPEATABLE READNoYesNoNo
SERAILIZABLENoNoNoYes

个人理解,所涉及的几个名称的含义为:

  • 脏读: 在一事务中读取到其他未提交事务的数据
  • 不可重复读: 在一事务中读取到其他已提交事务的数据
  • 幻读: 在一事务中读取到其他已提交事务的新增行
  • 加锁读: 在一事务中对读取到的每一行数据都加锁

为了实验上述理解,以下建立一城市表进行各个隔离级别的仿真。
统一建立一城市表为

CREATE TABLE `isolationtest_city_innodb` (
  `id` int(11) NOT NULL DEFAULT '0',
  `name` varchar(128) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

并建立两个测试用城市:

INSERT INTO isolationtest_city_innodb(id, NAME) VALUES(131, '北京'), (289, '上海');

开启两个事务A,B。A,B的执行顺序为

时序AB
1start transaction
2start transaction
3update isolationtest_city_innodb set name = ‘成都’ where name = ‘北京’
4select * from isolationtest_city_innodb
5commit
6select * from isolationtest_city_innodb
7start transaction
8insert isolationtest_city_innodb set id = 332, name = ‘天津’
9select * from isolationtest_city_innodb
10commit
11select * from isolationtest_city_innodb
12insert isolationtest_city_innodb set id = 332, name = ‘天津’
13commit

后续实验都将建立在此基础上。

READ UNCOMMITED

根据表1所述,事务B在时序4,6,9,11上将均能获取到事务A的数据。为验证以上断言,在开启事务B前修改数据库隔离模式

set tx_isolation = 'READ-UNCOMMITTED';

READ COMMITED

根据表1所述,事务B在事务A未提交事务前是看不到事务A的数据的。据此断言对于事务B,时序4将只能看到事务B的数据;时序6能看到事务A在时序5提交的数据;时序9看不到事务A的数据;时序11可以看到事务A在时序10提交的数据。
为验证以上断言,在开启事务 B前修改数据库隔离模式

set tx_isolation = 'READ-COMMITTED';

REPEATABLE READ

根据表1所述,事务B在事务A未提交事务前是看不到事务A的数据的。据此断言对于事务B,时序4将只能看到事务B的数据;时序6能看到事务A在时序5提交的数据;时序9看不到事务A的数据;时序11可以看到事务A在时序10提交的数据。
为验证以上断言,在开启事务 B前修改数据库隔离模式

set tx_isolation = 'REPEATABLE READ';

SERIALIZABLE

SERIALIZABLE通过强制事务串行执行,避免幻读问题《高性能mysql》

也就是,事务B将在事务A结束后才得以执行。因此,事务B将在时序4阻塞;在时序6读取到‘北京’被修改为‘成都’的信息;而事务A在时序7再次阻塞。后续时序将无法继续执行。

测试得时序4,6,7的结果分别为

READ UNCOMMITED

READ COMMITED

REPEATABLE READ

SERIALIZABLE

时序结果时序结果时序结果时序结果
4+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
+—–+——–+
4+—–+——–+
| id | name |
+—–+——–+
| 131 | 北京 |
| 289 | 上海 |
+—–+——–+
4+—–+——–+
| id | name |
+—–+——–+
| 131 | 北京 |
| 289 | 上海 |
+—–+——–+
6+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
+—–+——–+
6+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
+—–+——–+
6+—–+——–+
| id | name |
+—–+——–+
| 131 | 北京 |
| 289 | 上海 |
+—–+——–+
6+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
+—–+——–+
9| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
| 332 | 天津 |
+—–+——–+
9+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
+—–+——–+
9+—–+——–+
| id | name |
+—–+——–+
| 131 | 北京 |
| 289 | 上海 |
+—–+——–+
11+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
| 332 | 天津 |
+—–+——–+
11+—–+——–+
| id | name |
+—–+——–+
| 131 | 成都 |
| 289 | 上海 |
| 332 | 天津 |
+—–+——–+
11+—–+——–+
| id | name |
+—–+——–+
| 131 | 北京 |
| 289 | 上海 |
+—–+——–+
测试结果和理解上是一致的。测试结果和理解上是一致的。测试结果和预测的有所不同。在时序11中,事务B并没有读取到事务A插入的‘天津’行而产生幻读。然而,这种幻读的影响在时序12中体现出来。事务B因为事务A已插入了‘天津’行而无法重复插入相同主键行。似乎mysql只读数据过程中避免了幻读现象,而在写数据过程中却没能避免。更多的介绍可以参考MySQL的InnoDB的幻读问题_jackbillow_新浪博客以上空结果表示查询阻塞。从结果上看,和断言是一致的

总结

对SQL的四种隔离级别的理解基本正确。针对REPEATABLE READ,mysql似乎在读数据过程避免了幻读现象,然而在写数据过程上没有避免。

以上是关于mysql隔离级别容易理解的方法的主要内容,如果未能解决你的问题,请参考以下文章

mysql隔离级别容易理解的方法

深入理解mysql事务隔离级别

如何更改mysql事务隔离级别

数据库事务的四个隔离级别,mysql在哪一个级别

mysql 的事务隔离级别 及各个隔离级别应用场景,详细

如何查看mysql数据库隔离级别