豆爸的手册
  • 简介
  • 计算机基础
    • 浮点数的二进制表示
  • 架构设计
    • SSO
  • 服务器
    • 开启 gzip 压缩功能
    • 使用Liunx的crontab配置定时任务
    • OpenSSL生成秘钥对
    • 什么是线程安全
    • nginx基本配置与参数说明
    • Nginx日志配置参数
    • Linux命令
      • iostat
    • CGI, FashCGI, PHP-FPM
    • nginx中rewrite模块break和last原理详解
    • OOM
    • XXE漏洞的简单理解和测试
    • Apache 配置反向代理
    • 阿里云OSS STS上传配置
  • PHP
    • Laravel框架
      • Laravel 使用Apache服务器无法获取header中Authorization
      • Laravel5.1 表单数组验证
      • Laravel5 如何验证路由中的变量
      • Laravel 清除表单字段前后空白的Middleware
      • Laravel 获取执行的SQL语句
      • Laravel 将stdClass转换成Eloquent Model
      • 实际开发中如何活用 Closure
      • IoC 容器
    • Symfony框架
    • PHPExcel支持的样式
    • 计算地球上2个经纬度之间的距离
    • 创建一个自己的 Composer/Packagist 包
    • PHP Trait
    • 关于PHP浮点数
    • PHP7.2使用openssl替换mcrypt
    • rpc是什么?php中流行的rpc框架有哪些
  • MySQL
    • MySQL事务隔离级别
    • MySQL使用可重复读作为默认隔离级别的原因
    • FIND_IN_SET vs IN
    • MySQL慢查询
    • 是否使用SQL_CALC_FOUND_ROWS
    • GROUP BY性能优化
    • MySQL分页优化
    • MySQL在2个值之间获取随机数
    • MySQL数据库
      • 建表规约
      • 索引规约
      • SQL 语句
      • ORM 映射
    • MySQL 5.6 原生Online DDL解析
    • mysql使用utf8mb4经验吐血总结
  • HTTP
    • HTTP:Content-Type
    • 从HTTP到HTTPS再到HSTS
    • 主流浏览器中如何清除HSTS设置
    • 也许,这样理解HTTPS更容易
  • JavaScript
    • 跨域资源共享 CORS 详解
  • Git
    • 撤销合并
    • 从其他分支checkout文件或文件夹
    • 批量删除分支和标签
  • 前端
    • Grid布局
    • Flex布局
    • 浅谈OSS跨域功能
  • 书摘
    • 高效程序员的45个习惯
  • OpenResty
    • 新手上路
  • 敏捷开发
    • 为什么Scrum Master不叫Scrum Manager?
  • Postman
    • 使用Newman执行collections的时候,如果上传文件
    • 同步API定义到Postman
  • RESTful API最佳实践
  • 开发工具
  • 设计模式原则
  • Charles 从入门到精通
  • 阿里云OSS STS上传配置
  • 流式分页
Powered by GitBook
On this page

Was this helpful?

  1. MySQL

MySQL事务隔离级别

PreviousMySQLNextMySQL使用可重复读作为默认隔离级别的原因

Last updated 5 years ago

Was this helpful?

MySQL四种事务隔离级别

隔离级别

脏读

不可重复读

幻读

未提交读

可能

可能

可能

已提交读

不可能

可能

可能

可重复读

不可能

不可能

可能

可串行化

不可能

不可能

不可能

  • 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

  • 已提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

  • 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读(MySQL默认隔离级别为可重复读)

  • 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻

创建测试数据库,并插入数据:

mysql> desc account;
+--------+---------+------+-----+---------+-------+
| Field  | Type    | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| id     | int(11) | NO   | PRI | NULL    |       |
| amount | float   | YES  |     | NULL    |       |
+--------+---------+------+-----+---------+-------+
2 rows in set

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |   1000 |
|  2 |   1000 |
+----+--------+
2 rows in set

我们打开2个终端模拟2个用户操作。

未提交读(Read Uncommitted)

用户A操作如下:

mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected

mysql> start transaction;
Query OK, 0 rows affected

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |   1000 |
|  2 |   1000 |
+----+--------+
2 rows in set

用户B操作如下(不提交事务):

mysql> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected

mysql> start transaction;
Query OK, 0 rows affected

mysql> update account set amount=amount+200 where id = 1;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

用户A查询数据:

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |   1200 |
|  2 |   1000 |
+----+--------+
2 rows in set

我们将事务隔离级别设置为Read Uncommitted的时候,即使事务并没有commit,但是我们仍然能够读到未提交的数据。所以这是所有隔离级别中最低的。

我们在一个事务中可以读取到其他事务未提交的数据,这种我们称之为脏读(Dirty Read)。因为事务并未提交,所以数据库中的数据并未发生变化。

已提交读(Read Committed)

用户B将隔离级别设置为Read Committed:

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |   1000 |
|  2 |   1000 |
+----+--------+
2 rows in set

用户A执行更新操作,先不commit:

mysql> start transaction;
Query OK, 0 rows affected

mysql> update account set amount=amount-200 where id=1;
Query OK, 1 row affected
Rows matched: 1  Changed: 1  Warnings: 0

用户B查询数据库:

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |   1000 |
|  2 |   1000 |
+----+--------+
2 rows in set

用户A执行commit操作:

mysql> commit;
Query OK, 0 rows affected

用户B再次查询数据库:

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |    800 |
|  2 |   1000 |
+----+--------+
2 rows in set

我们将事务隔离级别设置为Read Committed的时候,当前事务只能读取到其他事务提交的数据,未提交的数据读取不到。

用户B在同一事务中2次读取的结果不同,我们称之为不可重复读(NonRepeatable Read)。

可重复读(Repeated Read)

用户B将隔离级别设置为Repeated Read:

mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected

mysql> start transaction;
Query OK, 0 rows affected

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |    800 |
|  2 |   1000 |
+----+--------+
2 rows in set

用户A插入数据:

mysql> insert into account(id, amount) values(3, 1000);
Query OK, 1 row affected

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |    800 |
|  2 |   1000 |
|  3 |   1000 |
+----+--------+
3 rows in set

用户B再次查询,但是仍然得到是2条数据:

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |    800 |
|  2 |   1000 |
+----+--------+
2 rows in set

当我们执行插入操作时,报错:

mysql> insert into account(id, amount) values(3, 1000);
1062 - Duplicate entry '3' for key 'PRIMARY'
mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |    800 |
|  2 |   1000 |
+----+--------+
2 rows in set

我们将事务隔离级别设置为Repeated Read的时候,不论其他事务有没有提交,每次读取的结果集都相同。

数据已经发生变化,但是读取的结果集还是保持一致,出现上面的现象,我们称之为幻读(Phantom Read) 。

串行读(Serializable)

用户B将隔离级别设置为串行读(Serializable):

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected

mysql> start transaction;
Query OK, 0 rows affected

mysql> select * from account;
+----+--------+
| id | amount |
+----+--------+
|  1 |    800 |
|  2 |   1000 |
+----+--------+
2 rows in set

用户A插入数据,则会出现等待,直到出现超时报错:

mysql> insert into account(id, amount) values (3, 1000);
1205 - Lock wait timeout exceeded; try restarting transaction

如果在A等待的过程中,B提交了事务,则A会执行成功。

我们将事务隔离级别设置为Serializable的时候,事务将会挂起对表的写操作,这是隔离级别中最严的隔离级别,但是也会对性能造成影响。

在实际的情况中,我们需要根据具体的操作情况,选择隔离级别。

http://www.jianshu.com/p/4e3edbedb9a8
http://www.cnblogs.com/zhoujinyi/p/3437475.html