`
OuYangGod
  • 浏览: 53774 次
  • 性别: 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事务隔离级别

    MySQL通过InnoDB存储引擎实现了事务处理,并支持四种隔离级别。可以通过`SET TRANSACTION ISOLATION LEVEL`语句来设置当前会话的事务隔离级别。此外,InnoDB还提供了一些特定的特性,如Next-Key Locks,以帮助解决幻...

    mysql事务隔离级别1

    在MySQL的InnoDB存储引擎中,有四种不同的事务隔离级别: 1. **读未提交(READ-UNCOMMITTED)**:在这个级别,一个事务可以读取到其他未提交事务的修改。这意味着脏读是可能的,即一个事务能看到另一个事务未提交的...

    MySQL数据库事务隔离级别详解

    MySQL数据库的事务隔离级别是数据库管理系统中用于控制事务处理中并发操作的重要机制。在多用户同时访问数据库的情况下,事务隔离级别能够确保数据的一致性和完整性,避免并发操作带来的各种问题,如脏读、不可重复...

    MySQL内核:InnoDB存储引擎 卷1.pdf.zip

    1. **事务支持**:InnoDB支持事务的四种隔离级别,包括读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,MySQL默认级别)和串行化(SERIALIZABLE)。这使得InnoDB能保证数据...

    MySql Innodb 引擎特性详解

    3. **读写阻塞**:在不同的事务隔离级别下,InnoDB引擎中的读写操作会受到不同程度的阻塞,这主要取决于所选的隔离级别。 4. **高效缓存**:InnoDB支持数据和索引的缓存,通过调整配置文件中的`innodb_buffer_pool...

    MySQL innodb 技术内幕

    InnoDB 存储引擎通过使用 MVCC 来获取高并发性,并且实现 SQL 标准的 4 种隔离级别,同时使用一种被称为 next-key locking 的策略来避免幻读现象。 ### 1.3.2 MyISAM 存储引擎 MyISAM 存储引擎是不支持事务的存储...

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

    本文档将介绍MySQL中InnoDB引擎事务隔离级别与锁之间的关系,并结合美团技术团队的经验分享,为大家提供一份详细的教程。 事务隔离级别是数据库事务处理的一个重要概念,它定义了事务与事务之间的隔离程度,主要...

    深入理解Mysql事务隔离级别与锁机制.zip

    MySQL的InnoDB存储引擎默认使用可重复读隔离级别,通过多版本并发控制(MVCC)来实现,以减少锁的竞争,提高并发性能。 然后是锁机制,它是实现不同隔离级别的关键手段: 1. **共享锁(S锁/读锁)**:允许一个事务...

    MySQL InnoDB小结1

    InnoDB存储引擎支持事务处理,提供了四种事务隔离级别:读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,InnoDB默认级别)和串行化(SERIALIZABLE)。不同的隔离级别有不同...

    mysql innodb死锁问题详解.docx

    2. 检查隔离级别:查看数据库的事务隔离级别,包括Read Uncommitted、Read Committed、Repeatable Read和Serializable。不同的隔离级别会影响事务的并发行为,可能导致锁冲突。 3. 分析线程状态:使用`SHOW FULL ...

    mysql原理之隔离级别1

    MySQL 数据库中的事务隔离级别是确保数据库在高并发环境下数据一致性的重要机制。SQL 标准定义了四个隔离级别,它们分别是 Read Uncommitted、Read Committed、Repeatable Read 和 Serializable,每种级别都针对不同...

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

    【MySQL InnoDB 事务隔离级别详解】 在数据库管理系统中,事务是确保数据一致性的重要机制,而InnoDB存储引擎则是MySQL中支持事务的主要引擎。事务的四大特性,即原子性(Atomicity)、一致性(Consistency)、隔离...

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

    总结来说,MySQL的事务隔离级别是通过特定的算法实现的,例如InnoDB存储引擎使用多版本并发控制(MVCC)来支持这些隔离级别。每个级别都有其适用场景,选择合适的隔离级别取决于应用程序的需求和对并发性能的影响。...

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

    MySQL的InnoDB支持四种隔离级别: 1. **未提交读(Read Uncommitted)**:允许读取未提交的数据,可能导致脏读,即一个事务读取到了另一个事务未提交的修改。 2. **已提交读(Read Committed)**:只允许读取已提交...

    mysql数据库事务隔离级别借鉴.pdf

    实际上,在可重复读隔离级别下,MySQL通过一种名为Next-Key Locks的机制,防止了幻读,但只在InnoDB存储引擎且使用了唯一索引的情况下有效。如果在无索引或者非唯一索引的情况下,幻读仍有可能发生。 总的来说,...

    MySQL技术InnoDB存储引擎_姜承尧_第2版

    书中会详细讲解四种隔离级别——读未提交(READ UNCOMMITTED)、读已提交(READ COMMITTED)、可重复读(REPEATABLE READ,MySQL默认级别)和串行化(SERIALIZABLE),以及它们在并发控制中的区别和应用场景。...

    MySQL技术内幕 InnoDB存储引擎.pptx

    InnoDB的工作机制包括事务管理、锁机制、并发控制、恢复机制等内容,让读者能够理解InnoDB在处理并发读写、事务隔离级别、崩溃恢复等方面的原理和机制。此外,本书还对InnoDB的性能优化进行了详细的分析,提出了很多...

Global site tag (gtag.js) - Google Analytics