`
OuYangGod
  • 浏览: 52890 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

MySQL InnoDB隔离级别

阅读更多
上篇文章讨论了事务隔离级别,隔离级别这个东西在不同的数据库产品上,是有一些区别的,本篇重点讲讲mysql数据库。

四种标准的隔离级别MySQL数据库都支持,下面我们一个一个看过来先。

首先我们先创建一个简单的测试表。
CREATE TABLE tb1(
    id		INT			NOT NULL,
    value	DECIMAL		NOT NULL,
    PRIMARY KEY (id)
)ENGINE=INNODB;


Read Uncommitted读未提交
首先,会话S1查询tb1表,没有记录返回。
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql> 

接着会话S2往tb1表写入一条记录,但不提交。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1 values(1, 100);
Query OK, 1 row affected (0.00 sec)

mysql> 

接着在会话S1中再次查询tb1表,可以看到,会话S2未提交的脏数据被会话S1查询出来了。
mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql>

由此可见,在这个级别下,是会发生脏读的。

Read Committed读已提交
首先,会话S1查询tb1表,没有记录返回。
mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql>

接着,会话S2往tb1表写入一条记录,但不提交。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1 values(1, 100);
Query OK, 1 row affected (0.00 sec)

mysql>

这时,在会话S1中再次查询tb1表,依然没有记录返回,说明在这个级别下,未提交的数据是不会被查询出来的,能避免脏读
mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql>

这时,在会话S2中提交事务。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1 values(1, 100);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql>

再次看看会话S1中的情况。
mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql> select * from tb1;
Empty set (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql>

在会话S2中提交事务后,会话S1中的事务可以看到新的记录了,说明该级别不能防止不可重复读的问题。

Repeatable Read
再来看看Repeatable Read,首先会话S1查询tb1表,返回记录(1, 100)。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql>

接着会话S2更新记录(1, 100)-> (1, 101)并提交事务。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update tb1 set value = 101 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql>

在会话S1中看看情况。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql>

会话S1中查询到的还是原来的结果,如果提交或回滚事务后再次查询,看到的就是被会话S2更新后的数据了。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   100 |
+----+-------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql>

所以说这个级别可以防止不可重复读,但是对于幻读呢?我们来看看。
首先,会话S1查询tb1表,返回记录(1, 101)。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql>

接着会话S2插入一条新的记录(2, 200)并提交事务。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1(id, value) values(2, 200);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql>

再看看会话S1中的情况。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql>

从结果看到,幻读并没有发生,这个本人开始的认识有出入,因为在标准的事务隔离级别定义下,Repeatable Read是不能防止幻读产生的。这里是因为InnoDB使用了2种技术手段(MVCC AND GAP LOCK)实现了防止幻读的发生。

Serializable序列化
既然Repeatable Read已经可以防止幻读的发生了,那Serializable存在的意义何在呢?我们还是来看一个例子吧。

首先,会话S1(在Repeatable Read隔离级别下)查询tb1表。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql>

接着,会话S2在tb1中插入一条新数据(2, 200)并提交事务。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1(id, value) values(2, 200);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql>

回到会话S1中再次查询,从结果从看只有(1, 101)这条数据,但在尝试插入新数据(2, 200)时确提示主键重复错误了。
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
+----+-------+
1 row in set (0.00 sec)

mysql> insert into tb1(id, value) values(2, 200);
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
mysql>

如果隔离级别是Serialiable的话,上面的情况就不会发生了。来看看在Serialiable下的情况:

首先,会话S1查询tb1表。
mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from tb1;
+----+-------+
| id | value |
+----+-------+
|  1 |   101 |
|  2 |   200 |
+----+-------+
2 rows in set (0.00 sec)

mysql>

接着会话S2尝试在tb1中插入一条新的记录。
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into tb1(id, value) values(3, 300);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql>

会话S2的插入操作将会被挂起,直到会话S1中的事务结束,所以就不存在Repeatable级别下的问题了,但是Serialiable级别下相关于串行化执行事务了,并行性能太差,一般不会在生产环境使用。

隔离级别与锁的探讨
在我的上一篇文章《事务、事务并发》中已经提到S锁与X锁的概念,但是在测试中发现MySQL与其它数据库存在差异,比如在可重复读这个隔离级别下,查询操作并不会对数据记录加S锁,但更新操作还是会加X锁的。个人猜想,MySQL内部可能为每个数据行都维护了一个版本的概念,通过版本以及X锁来共同实现各种隔离级别的。

以下两种方式,可以显示地指定查询记录时加S锁或X锁。
select * from ... where ... lock in share mode

select * from ... where ... for update
分享到:
评论

相关推荐

    Mysql innodb 存储引擎全揭秘

    Innodb 通过多版本并发控制(MVCC)来获得高并发性,并且实现了sql标准的4种隔离级别,默认为repeatable_read 级别。同时使用一种 -- next-key locking 的锁策略来避免幻读现象的产生,还提供了插入缓冲(insert ...

    innodb如何巧妙的实现事务隔离级别详解

    锁机制是用来保证在并发情况下数据的准确性,而要保证数据准确通常需要事务的支持,而mysql存储引擎innodb是通过锁机制来巧妙地实现事务的隔离特性中的4种隔离级别。 事务ACID特性,其中I代表隔离性(Isolation)。...

    MySQL中Innodb的事务隔离级别和锁的关系的讲解教程

    主要介绍了MySQL中Innodb的事务隔离级别和锁的关系讲解教程,来自于美团技术团队的经验实际经验分享,需要的朋友可以参考下

    五分钟搞清楚MySQL事务隔离级别

    作者:伞U ...好久没碰数据库了,只是想起自己当时在搞数据库的...为了说明问题,我们打开两个控制台分别进行登录来模拟两个用户(暂且成为用户 A 和用户 B 吧),并设置当前 MySQL 会话的事务隔离级别。 一. read unco

    Mysql事务隔离级别原理实例解析

    再加上很多书都说可重复读解决了幻读问题,比如《mysql技术内幕–innodb存储引擎》等,不一一列举了,因此网上关于事务隔离级别的文章大多是有问题的,所以再开一文说明! 本文所讲大部分内容,皆有官网作为佐证,...

    MySQL(InnoDB).xmind

    个人总结的MySQL思维脑图,纯个人整理,欢迎大家参考。MySQL InnoDB 索引 事务 锁 隔离级别 面试

    MySQL的Innodb中的事务隔离级别和锁的关系

    这里通过分析MySQL中InnoDB引擎的加锁机制,来抛砖引玉,让读者更好的理解,在事务处理中数据库到底做了什么。  #一次封锁or两段锁?  因为有大量的并发访问,为了预防死锁,一般应用中推荐使用一次封锁法,是在...

    解读MySQL事务的隔离级别和日志登记模式选择技巧

    MySQL的四种事务隔离级别:Read-uncommitted、Read-committed、Repeatable-read、Seriailizable,相信大家都清楚各自异同,不清楚的朋友可以查看另外一篇技术文章:MySQL_InnoDB之事务与锁详解。但是对于第二类、第...

    MySQL 四种事务隔离级别详解及对比

    MySQL/InnoDB 提供SQL标准所描述的所有四个事务隔离级别。你可以在命令行用–transaction-isolation选项,或在选项文件里,为所有连接设置默认隔离级别。 例如,你可以在my.inf文件的[mysqld]节里类似如下设置该选项...

    通过实例分析MySQL中的四种事务隔离级别

    在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。数据库事务的隔离级别有4个,下面话不多说了,来一起看看详细的介绍吧。 数据库事务有四种隔离级别: 未提交读(Read Uncommitted):允许脏...

    MySQL存储引擎InnoDB的配置与使用的讲解

    innodb 通过多版本并发控制(MVCC)来获得高并发性,并且实现了SQL标准的4种隔离级别,默认为REPEATABLE级别。同时,使用一种被称为next-key locking的策略来避免幻读(phantom)现象的产生。除此之外,InnoDB存储引擎...

    InnoDB锁机制学习笔记

    MySQL的引擎简介,InnoDB的锁机制与事务隔离级别

    浅谈InnoDB隔离模式的使用对MySQL性能造成的影响

    在这篇文章里我将讨论一个相关的主题 – InnoDB 事务隔离模式,还有它们与MVCC(多版本并发控制)的关系,以及...REPEATABLE READ – 这是默认的隔离级别,通常它是相当不错的,对应用程序的便捷性来说也不错。它在第

    MySQL中InnoDB锁的介绍及用途

    一、InnoDB引擎对隔离级别的支持 事务隔离级别 脏读 不可重复读 幻读 读未提交(read-uncommitted) 可能 可能 可能 不可重复读(read-committed) 不可能 可能 可能 可重复读(repeatable-read) 不可能...

    面试刷题29:mysql事务隔离实现原理?

    mysql的事务是innodb存储引擎独有的,myisam存储引擎不支持事务。 事务最经典的例子就是转账了,事务要保证的是一组数据库的操作要么全部成功,要么全部失败。是为了保证高并发场景下数据的正确性而定义。 事务并非...

    MySQL中InnoDB存储引擎的加锁分析

    文档中深入浅出的,详细描述了一条 SQL 是如何实现加锁的,包含了各种索引组合和各种隔离级别下的分析;同时也详细地剖析了死锁的原理和解决办法。 适用人群: 1、想加深对 MySQL了解,想要深入学习数据库底层的人群...

    MySQL自整理超全精华版面试八股文

    MySQL事务的隔离级别通过什么实现? 什么是MVCC? 锁 MySQL锁定的类型有那些 InnoDB引孳的行锁是怎么实现的? InnoDBi引擎的行锁的三种算法 性能优化 执行计划分析explain SQL优化 数据库表结构设计优化 大表优化

    MySQL InnoDB存储引擎的深入探秘

    在MySQL中InnoDB属于存储引擎层,并以插件的形式集成在数据库中。从MySQL5.5.8开始,InnoDB成为其默认的存储引擎。InnoDB存储引擎支持事务、其设计目标主要是面向OLTP的应用,主要特点有:支持事务、行锁设计支持高...

    mysql8中文参考手册

    事务的隔离级别质数 Mysql词汇,如何使用MySQL的MySQL客户端程序来创建和使用一个简单的数据库。 备份你的数据库,你可以恢复你的数据,并在问题发生时再运行至关重要,如系统崩溃,硬件故障,或用户误删除数据。...

Global site tag (gtag.js) - Google Analytics