## 测试环境
mysql> select version();
+------------+
| version() |
+------------+
| 5.7.11-log |
+------------+

数据库事务特性 ACID,即

A(Atomicity)   -原子性

C(Consistency)- 一致性

I(Isolation)     - 隔离性

D(Durability)   - 持久性

MySQL 提供了 4 种不同的隔离级别,用来支持多版本并发控制(MVCC,Multi-Version Concurrency Control)。

默认的事务隔离级别是 REPEATABLE-READ(可重读):

mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-------------------------+---------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-------------------------+---------------------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-------------------------+---------------------------+

在该事务级别下,一个事务期间内,该事务不考虑其他提交语句。

0x00、测试准备

1. 创建测试表

mysql> CREATE TABLE `transaction_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`val` varchar(20) NOT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

2. 开启两个 MySQL 客户端进行测试

0x01、REPEATABLE-READ(可重读)

step 1:

在 Client 1 下开启事务,查询测试表中的数据:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> select * from transaction_test;
Empty set (0.00 sec)

step 2:

在 Client 2 下开启事务,并且往测试表中插入数据,但不提交事务:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | x | 2017-02-06 00:20:59 |
| 2 | y | 2017-02-06 00:20:59 |
| 3 | z | 2017-02-06 00:20:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

step 3:

在 Client 1 下查看表中数据:

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

仍然是空表。

step 4:

Client 2 提交事务:

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

step 5:

Client 1 下查看表中数据:

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

任然是空表。

step 6:

Client 1 提交事务,查看表中数据:

mysql> commit;
Query OK, 0 rows affected (0.00 sec) mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | x | 2017-02-06 00:20:59 |
| 2 | y | 2017-02-06 00:20:59 |
| 3 | z | 2017-02-06 00:20:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

当 Client 1 完成事务后,才能看到其他事务提交的数据。

0x02、READ-COMMITTED(读取提交内容)

step 1:

Client 1 中清空表,改变数据库隔离级别:

mysql> truncate table transaction_test;
Query OK, 0 rows affected (0.10 sec) mysql> set @@session.tx_isolation = 'READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec) mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ | READ-COMMITTED |
+-----------------------+------------------------+
1 row in set (0.00 sec)

step 2:

Client 1 开启事务,查询表中数据:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> select * from transaction_test;
Empty set (0.00 sec)

step 3:

Client 2 开启事务,向表中插入数据,但不提交事务:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | x | 2017-02-06 00:31:00 |
| 2 | y | 2017-02-06 00:31:00 |
| 3 | z | 2017-02-06 00:31:00 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

step 4:

Client 1 下查看表中数据:

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

仍然是空表。

step 5:

Client 2 提交事务:

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

step 6:

Client 1 下查看表中数据:

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | x | 2017-02-06 00:31:00 |
| 2 | y | 2017-02-06 00:31:00 |
| 3 | z | 2017-02-06 00:31:00 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

与 REPEATABLE-READ 不同的是,Client 1 没有结束事务也能看到其他事务提交的数据。

0x03、READ-UNCOMMITTED(读取未提交内容)

step 1:

Client 1 下清空表,设置隔离级别:

mysql> truncate table transaction_test;
Query OK, 0 rows affected (0.10 sec) mysql> set @@session.tx_isolation = 'READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec) mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ | READ-UNCOMMITTED |
+-----------------------+------------------------+
1 row in set (0.00 sec)

step 2:

Client 1 下开启事务,查询表数据:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> select * from transaction_test;
Empty set (0.00 sec)

step 3:

Client 2 下开启事务,向表中插入数据,但是不提交事务:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | x | 2017-02-06 00:43:59 |
| 2 | y | 2017-02-06 00:43:59 |
| 3 | z | 2017-02-06 00:43:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

step 4:

Client 1 中查询数据:

mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 1 | x | 2017-02-06 00:43:59 |
| 2 | y | 2017-02-06 00:43:59 |
| 3 | z | 2017-02-06 00:43:59 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

与 READ-COMMITTED 不同的是,在 Client 2 不提交事务的情况下,Client 1 也能读到其他事务插入的数据,即脏数据或者说产生了“脏读”。在一个事务期间读到了另一个事务在未提交之前产生的数据,那么第一个事务就读到了脏数据,产生了对第二个事务未提交数据的依赖,如果第二个事务回滚,那么第一个事务读到的数据是错误的脏数据。

“脏读”与“幻读”、“不可重复读”的区别是:幻读是读取结果集条数的对比,一个事务按相同的查询条件查询之前检索过的数据,发现检索出来的结果集条数变多或者减少(由其他事务插入、删除的),类似产生幻觉。

不可重复读是读取的数据本身的对比,一个事务在读取某些数据后的一段时间后,再次读取这个数据,发现其读取出来的数据内容已经发生了改变,就是不可重复读。

step 5:

Client 2 回滚事务:

mysql> rollback;
Query OK, 0 rows affected (0.04 sec) mysql> select * from transaction_test;
Empty set (0.00 sec)

step 6:

Client 1 查询表数据:

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

空表。

0x04、SERIALIZABLE(序列化)

step 1:

Client 1 下清空表,设置隔离级别:

mysql> truncate table transaction_test;
Query OK, 0 rows affected (0.21 sec) mysql> set @@session.tx_isolation ='SERIALIZABLE';
Query OK, 0 rows affected (0.00 sec) mysql> select @@global.tx_isolation, @@session.tx_isolation;
+-----------------------+------------------------+
| @@global.tx_isolation | @@session.tx_isolation |
+-----------------------+------------------------+
| REPEATABLE-READ | SERIALIZABLE |
+-----------------------+------------------------+
1 row in set (0.00 sec)

step 2:

Client 1 开启事务,查询表:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> select * from transaction_test;
Empty set (0.00 sec)

step 3:

Client 2 开启事务,向表中插入数据:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec) mysql> insert into transaction_test (val) values ('x'),('y'),('z');
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

此时 Client 2 插入数据(INSERT 操作)会被阻塞,直到第一个(Client 1)事务提交后,Client 2 的插入操作才能完成。

step 4:

Client 1 提交事务:

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

step 5:

Client 2 插入数据:

mysql> insert into transaction_test (val) values ('x'),('y'),('z');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from transaction_test;
+----+-----+---------------------+
| id | val | created |
+----+-----+---------------------+
| 4 | x | 2017-02-06 00:54:17 |
| 5 | y | 2017-02-06 00:54:17 |
| 6 | z | 2017-02-06 00:54:17 |
+----+-----+---------------------+
3 rows in set (0.00 sec)

参考:

[MySQL]对于事务并发处理带来的问题,脏读、不可重复读、幻读的理解

MySQL 4 种隔离级别的区别的更多相关文章

  1. MySQL两种引擎的区别

    Innodb引擎 Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别.该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL ...

  2. Mysql 两种引擎的区别

    MyISAM与InnoDB的区别是什么? 1. 存储结构 MyISAM:每个MyISAM在磁盘上存储成三个文件.第一个文件的名字以表的名字开始,扩展名指出文件类型..frm文件存储表定义.数据文件的扩 ...

  3. mysql几种连接方式区别

    mysql的几种join 2017年03月19日 14:49:07 carl-zhao 阅读数:7845 标签: mysqlsqljoin 更多 个人分类: MySQL 版权声明:本文为博主原创文章, ...

  4. mysql几种关联的区别

    1.平时都是用的逗号的模式:select * from a,b where a.id=b.id,逗号的模式等于inner join和join: 2.left join 和 right join相反,效 ...

  5. MySQL ACID及四种隔离级别的解释

    以下内容出自<高性能MySQL>第三版,了解事务的ACID及四种隔离级有助于我们更好的理解事务运作. 下面举一个银行应用是解释事务必要性的一个经典例子.假如一个银行的数据库有两张表:支票表 ...

  6. [转]Mysql几种索引类型的区别及适用情况

    此为转载文章,仅做记录使用,方便日后查看,原文链接:https://www.cnblogs.com/yuan-shuai/p/3225417.html Mysql几种索引类型的区别及适用情况   如大 ...

  7. MySQL中四种隔离级别的演示

    事务的隔离是并发操作中需要理解清楚的问题.MySQL中共有4种不同的隔离级别,这4种隔离级别分别是: 隔离级别类型 影响结果 READ UNCOMMITTED(未提交读) 事务将会读取到未提交的数据, ...

  8. MySQL数据库引擎介绍、区别、创建和性能测试的深入分析

    本篇文章是对MySQL数据库引擎介绍.区别.创建和性能测试进行了详细的分析介绍,需要的朋友参考下   数据库引擎介绍 MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的.要添加一个新的引擎 ...

  9. [转]MySQL数据库引擎介绍、区别、创建和性能测试的深入分析

    本篇文章是对MySQL数据库引擎介绍.区别.创建和性能测试进行了详细的分析介绍,需要的朋友参考下   数据库引擎介绍 MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的.要添加一个新的引擎 ...

随机推荐

  1. SpringCloud学习目录

    Spring Cloud直接建立在Spring Boot的企业Java创新方法上,它通过实现经过验证的模式来简化分布式.微服务风格的体系结构,从而为您的微服务带来弹性.可靠性和协调. 以上来自spri ...

  2. Vue渲染列表,在更新data属性后,列表未更新问题

    初始化代码如下var tableModel = new Vue({el: '#datatable',data: {items: listData}}); 当我对列表操作时,listData=>n ...

  3. Redis自学笔记:3.6入门-有序集合类型

    3.6有序集合类型 3.6.1介绍 在集合类型基础上,为集合中每个元素都关联了一个分数,故可以获得 分数最高(最低)的前N个元素,可以获得指定范围内的元素等 有序集合中每个元素不同,但它们的分数却可以 ...

  4. 安卓面试题 Android interview questions

    安卓面试题 Android interview questions 作者:韩梦飞沙 ‎2017‎年‎7‎月‎3‎日,‏‎14:52:44 1.      要做一个尽可能流畅的ListView,你平时在 ...

  5. [python] 查询mysql返回datetime类型数据的处理

    Python 查询Mysql,如果是datetime类型,在json序列化的时候会出现问题. 在网上查了一下,解决方案基本都是遍历dict数据,如果是datetime则转化为字符串. from dat ...

  6. SSH密钥登录让Linux VPS/服务器更安全

    查看 /var/log 登录日志文件,突然发现服务器被人扫描端口在进行暴力攻击 平常登录服务器,都是使用用户密码登录,看来这样的做法并不安全,不得不关闭密码登录了. 总结了一个putty使用密钥自动登 ...

  7. [AHOI2017/HNOI2017]大佬

    Description: 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事 ...

  8. [HDU1693]Eat the Trees

    Description: 给出n*m的方格,有些格子不能铺线,其它格子必须铺,可以形成多个闭合回路.问有多少种铺法? Hint: \(n,m<=12\) Solution: 与原来单回路那题转移 ...

  9. Java中类加载过程和对象创建过程

    类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...

  10. Sniffer初识

    Sniffer,中文可以翻译为嗅探器,是一种基于被动侦听原理的网络分析方式.使用这种技术方式,可以监视网络的状态.数据流动情况以及网络上传输的信息.当信息以明文的形式在网络上传输时,便可以使用网络监听 ...