资讯专栏INFORMATION COLUMN

循环渐进 MySQL 事务隔离级别

W_BinaryTree / 2750人阅读

摘要:隔离级别事务隔离性的解释通常情况下,事务在提交之前对于其他事务不可见。数据库有四种隔离级别,当然也是如此。串行化串行化是最高隔离级别,强制事务串行执行。示例演示,客户端和设置隔离级别为可串行化。

本篇文章的重点在于总结MYSQL事务。

什么是事务

事务简言之就是一组 SQL 执行要么全部成功,要么全部失败。MYSQL 的事务在存储引擎层实现。

事务都有 ACID 特性:

原子性(Atomicity):一个事务必须被视为一个不可分割的单元;

一致性(Consistency):数据库总是从一种状态切换到另一种状态;

隔离性(Isolation):通常来说,事务在提交前对于其他事务不可见;

持久性(Durablity):一旦事务提交,所做修改永久保存数据库;

事务最常用的例子就是银行转账。假设 polo 需给 lynn 转账1000元,如下步骤:

确认 polo 账户余额高于1000元;

从 polo 的账户余额减去1000元;

将 lynn 的账户余额增加1000元;

SQL语句如下:

mysql> BEGIN;
mysql> SELECT balance FROM bank_account WHERE uid=10001;
mysql> UPDATE bank_account SET balance=balance-1000 WHERE uid=10001;
mysql> UPDATE bank_account SET balance=balance+1000 WHERE uid=10002;
mysql> COMMIT;

mysql 启动事务可使用 BEGIN 或 START TRANSACTION;上述三个步骤执行在一个事务中就能够保证数据的完整性,要么全部成功,要么全部失败。

MYSQL 提供两种事务型引擎:Innodb 和 NDBCluster。默认采用自动提交模式,执行一条语句自动 COMMIT。通过 AUTOCOMMIT 变量可启用或者禁用自动提交模式:

mysql> SHOW VARIABLES LIKE "AUTOCOMMIT";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> SET AUTOCOMMIT=1

AUTOCOMMIT=1 表示开启默认提交,0表示关闭默认提交需要手动提交。

隔离级别

事务隔离性的解释:通常情况下,事务在提交之前对于其他事务不可见。

数据库有四种隔离级别,当然 MYSQL 也是如此。分别是:

未提交读,READ UNCOMMITTED

已提交读,READ COMMITTED

可重复读,REPEATABLE READ

串行化,SEAIALIZABLE

关于隔离级别的两个理解

书本解释,每种级别都规定了一个事务中所做修改,哪些在事务内和事务间是可见的。

我的理解,隔离级别就是决定一个事务的修改另一个事务什么情况下能看到。

两者区别在于是否存在事务内可见性,但无论哪个级别在事务内的操作肯定是可见的,重点在事务间可见性。

下面开始说明 MYSQL 的四种隔离级别,先准备一张学生表:

mysql> CREATE TABLE `student` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `name` varchar(32) NOT NULL DEFAULT "",
 PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8 |

只有id(主键自增)与name字段

未提交读

事务中修改没有提交对其他事务也是可见的,俗称脏读。非常不建议使用。

示例演示,客户端A和B设置隔离级别为未提交读

mysql> SET SESSION TX_ISOLATION="READ-UNCOMMITTED";

客户端A与B开启事务并查询student

mysql> BEGIN; mysql> SELECT * FROM student;
Empty set (0.00 sec)

当前,客户端 A 和 B 都是空数据。此时在客服端 B 插入一条新的数据

mysql> INSERT INTO student(name) VALUES("polo");
Query OK, 1 row affected (0.00 sec)

此时事务还未提交,客服端 A 查看一下 student 表,如下:

mysql> SELECT * FROM student;
+----+------+
| id | name |
+----+------+
|  1 | polo |
+----+------+
1 row in set (0.00 sec)

可以看出,客户端 A 看到 B 未提交的修改。客户端 B 执行回滚操作,如下:

mysql> ROLLBACK

成功之后,客户端 A 查看 student 表:

mysql> SELECT * FROM student;
Empty set (0.00 sec)

输出显示,客户端A查看数据为空。

以上可以看出未提交读隔离级别的危险性,对于一个没有提交事务所做修改对另一个事务是可见状态,容易造成脏读。非特殊情况不得使用此级别

读提交读

多数数据库系统默认为此级别(MYSQL不是)。已提交读级别即为一个事务只能看到已提交事务所做的修改,也就解决了未提交读的问题,即脏读的问题。

示例演示,客户端A和B设置隔离级别为已提交读,执行如下命令:

mysql> SET SESSION TX_ISOLATION="READ-COMMITTED";

客户端 A与 B 开启事务并查询 student

mysql> BEGIN; 
mysql> SELECT * FROM student;
Empty set (0.00 sec)

结果显示,客户端A和B都为空。接着,客户端 B 插入一条新的数据但不执行提交:

mysql> INSERT INTO student (name) VALUES("polo");

接下来,客户端 A 查看一下 student 数据:

mysql> SELECT * FROM student;
Empty set (0.00 sec)

注意这里与上面不同了,在客户端B没有提交事务情况下无数据。下面客户端B提交事务:

mysql> COMMIT;

客户端 A 再查看下 student 表。

mysql> SELECT * FROM student; 
+----+------+
| id | name |
+----+------+
|  1 | polo |
+----+------+
1 row in set (0.00 sec)

这样我们就成功读取到了客户。

从上面的示例可以看出,提交读没有了脏读问题,但我们可以看到在客户端 A 的一个事务中执行两次同样的 SELECT 语句得到不同结果,因此已提交读又被称为不可重复读。同样筛选条件可能得到不同的结果。

可重复读

如其名所言,解决已提交读不可重复读取的问题。

示例演示,客户端A和B设置隔离级别为可重复读。首先设置隔离级别:

mysql> SET SESSION tx_isolation="REPEATABLE-READ"

客户端A与B开启事务并查看

mysql> BEGIN; 
mysql> SELECT * FROM student;
+----+------+
| id | name |
+----+------+
|  1 | polo |
+----+------+
1 rows in set (0.00 sec)

客服端 B 更新 polo 为 adam 并提交事务

mysql> UPDATE student SET name="adam" WHERE id=1;
mysql> COMMIT

客户端A查看student表,结果如下:

mysql> SELECT * FROM student;
+----+------+
| id | name |
+----+------+
|  1 | polo |
+----+------+
1 rows in set (0.00 sec)

客户端 A 查看数据未变,没有不可重复读问题。

客户端 A 提交事务,并查看student表。

mysql> COMMIT; mysql> SELECT * FROM student;
+----+------+
| id | name |
+----+------+
|  1 | polo |
+----+------+
1 rows in set (0.00 sec)

从上面的示例可知,可重复读两次读取内容一样。该级别并没有解决幻读的问题。但是MYSQL在可重复读基础上增加了MVCC机制解决了此问题,此处无法演示幻读的效果。

那什么是幻读?首先,可重复读锁定范围为当前查询到的内容,如执行

mysql> SELECT * FROM student WHERE id>=1

锁定的即 id>=1 查到的行,为行级锁。如另一事务执行并默认提交以下语句

mysql> INSERT INTO student (name) VALUES ("stephen");

新增的这行并没有被锁定,此时读取 student

mysql> SELECT * FROM student WHERE id>=1;
+----+---------+
| id | name    |
+----+---------+
|  1 | polo    |
|  2 | stephen |
+----+---------+
2 rows in set (0.00 sec)

出现了幻读。关于这个问题,除了使用 MYSQL 的 MVCC 机制,还可以用可串行化隔离级别解决此问题。

串行化

串行化是最高隔离级别,强制事务串行执行。执行串行了,那么也就解决了一切的问题,这个级别只有在对数据一致性要求非常严格且没用并发的情况下使用。

示例演示,客户端 A 和 B 设置隔离级别为可串行化。

mysql> SET SESSION tx_isolation="SERIALIZABLE";

首先,客户端 A 执行一下查询:

mysql> SELECT * FROM student WHERE id<4;
+----+---------+
| id | name    |
+----+---------+
|  1 | polo    |
|  2 | stephen |
+----+---------+
2 rows in set (0.00 sec)

接下来,客户端 B 执行数据新增:

mysql> INSERT INTO student (name) VALUES("yunteng");
好的!效果出现了,此时我们会发现INSERT语句被阻塞执行,原因就是A执行了查询表student同时满足id<4,已被锁定。如果查询表student条件为id<3,则新增语句可正常执行。

汇总图
隔离级别 英文 脏读 不可重复读 幻读 加锁读
未提交读 READ UNCOMMITTED
提交读 READ COMMITTED
可重复读 REPEATABLE READ
串行化 SERIALIZABLE

关于事务的隔离级别到此结束。具体使用何种情况还要根据具体的业务场景来决定。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/110686.html

相关文章

  • Mysql事务

    摘要:事务可以读取未提交的数据,这也称为脏读。当之前的事务在此读取该范围时,会产生幻读行。大多数情况下,只需要重新执行因死锁回滚的事务即可。注在非事务型的表上执行事务相关操作,不会发生提醒。 一:隔离级别 READ UNCOMMITTED(未提交读)在READ UNCOMMITTED级别下,在一个事务中的修改,即时没有提交,对其他事务也多是可见的。事务可以读取未提交的数据,这也称为脏读(Di...

    NusterCache 评论0 收藏0
  • MySql 事物及隔离级别

    摘要:二事务的四种隔离级别在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。在可重读事务隔离级别下时,读取创建版本号当前事务版本号,删除版本号为空或当前事务版本号。 一、事务的基本要素(ACID)   1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生...

    XFLY 评论0 收藏0
  • 高性能MySQL读书笔记-事务

    摘要:高性能第版美施瓦茨等著宁海元等译北京电子工业出版社第页。表示原子性一致性隔离性和持久性。一个运行良好的事务处理系统,必须具备这些标准特征。持久性一旦事务提交,则其所做的修改就会永久保存到数据库中。事务可以读取未提交的数据,这也被称为脏读。 一、MySQL逻辑架构 为了充分发挥MySQL的性能并顺利地使用,就必须理解其设计。 1. 逻辑架构 最上层的服务并不是MySQL所独有的,大多数基...

    lifefriend_007 评论0 收藏0
  • MySQL 数据库事务

    摘要:简介事务是一组原子性的查询或者说是一个独立的工作单元在事务内的语句要么全部执行成功要么全部执行失败事务的性质数据库事务拥有以下四个特性即性质原子性事务作为一个整体被执行包含在其中的对数据库的操作要么全部执行成功要么全部失败回滚对于一个事务来 简介 事务是一组原子性的 SQL 查询, 或者说是一个独立的工作单元. 在事务内的语句, 要么全部执行成功, 要么全部执行失败. 事务的 ACID...

    remcarpediem 评论0 收藏0
  • 可能是全网最好的MySQL重要知识点/面试题总结

    摘要:并发虽然是必须的,但可能会导致以下的问题。事务隔离级别有哪些的默认隔离级别是标准定义了四个隔离级别读取未提交最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读幻读或不可重复读。可串行化最高的隔离级别,完全服从的隔离级别。 标题有点标题党的意思,看了文章之后希望大家不会有这个想法,绝对干货!!!这篇花文章是我花了几天时间对之前总结的MySQL知识点做了完善后的产物,这篇文章可以用...

    hiyayiji 评论0 收藏0

发表评论

0条评论

W_BinaryTree

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<