MySQL 事务基础知识
1. 数据库事务概述
1.1 存储引擎支持情况
用于查看当前MySQL支持的存储引擎有哪些,并确认这些存储引擎是否都支持事务处理
mysql> show engines;
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
|Engine|Support|Comment|Transactions|XA|Savepoints|
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
|FEDERATED|NO|Federated MySQL storage engine|NULL|NULL|NULL|
|MEMORY|YES|Hash based, stored in memory, useful for temporary tables|NO|NO|NO|
|InnoDB|DEFAULT|Supports transactions, row-level locking, and foreign keys|YES|YES|YES|
|PERFORMANCE_SCHEMA|YES|Performance Schema|NO|NO|NO|
|MyISAM|YES|MyISAM storage engine|NO|NO|NO|
|MRG_MYISAM|YES|Collection of identical MyISAM tables|NO|NO|NO|
|BLACKHOLE|YES|/dev/null storage engine (anything you write to it disappears)|NO|NO|NO|
|CSV|YES|CSV storage engine|NO|NO|NO|
|ARCHIVE|YES|Archive storage engine|NO|NO|NO|
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
9 rows in set (0.00 sec)


能看出在 MySQL 中,只有InnoDB 是支持事务的。
1.2 事务基本概念
- 事务: 由多个逻辑操作组成的集合。
- 事务处理的原则: 按照确保每个事务作为一个独立执行单位的原则进行处理。即使在出现故障的情况下也不会更改其执行模式。
当在一个事务中包含多个操作时:
- 要么系统将所有修改提交(Commit),这些修改将永久保存;
- 要么系统将拒绝所有修改(Rollback),导致整个事物回滚至初始状态。
1.3 事务的 ACID 特性
- 原子性(atomicity):
原子性是指事务作为一个独立的工作单元,在执行过程中必须满足以下两个条件:一是事务必须全部成功;二是如果发生失败,则必须进行重做。
- 一致性(consistency):
一些网站在阐述一致性时存在错误,并且可查阅Wikipedia关于Consistency的相关介绍。
按照定义阐述的一致性是指,在事务执行前后数据从一个 合法的状态 转换为另一个 合法的状态 。这种状态是从语义层面而非语法层面进行的区分,并与具体的业务逻辑相关。
那什么是合规的数据状态呢?它指的是符合既定规则的状态。简单来说,“合规”是由你个人来决定的标准(例如基于现实世界的限制)。若达到该条件,则数据处于一致的状态;若不符合该条件,则数据处于不一致的状态!当事务中的某个操作出现故障时,系统会自动回滚当前未完成的操作并恢复至事务开始前的状态。
- 隔离型(isolation):
该事务具有独立性其主要特征在于其运行过程不会受到任何外部操作的影响。具体而言在同一个事务内部的所有操作及其依赖的数据资源与其它并发操作处于完全独立的状态并且在并行执行过程中各参与事务之间也不会产生任何互相影响。
如果不采取适当的隔离措施将会发生什么情况?假设有账户A初始资金为200元另一账户B当前资金为零则该系统将经历以下操作:假定系统允许非隔离操作则A账户将分两次进行转账操作每次转移50元分别完成两个事务流程在这种情况下系统将无法正确执行这些交易从而导致资金分配异常例如第一次转账后B账户应获得50元但因为未实现严格的原子化操作该笔资金可能并未成功转移从而引发交易失败或者部分转移导致资金损失这种情况可能会对整个系统的可用性和可靠性造成严重影响
UPDATE accounts SET money = money - 50 WHERE NAME = 'AA';
UPDATE accounts SET money = money + 50 WHERE NAME = 'BB';

- 持久性(durability):
持久性是指一个事务一旦被提交请求并完成锁定后生成修改记录 ,其修改记录将被锁定并长期保存 ,而其他操作以及数据库故障不应对其产生任何影响。
持久性由事务日志来确保。这些记录主要包括重做记录和回滚记录。在我们使用事务操作修改数据时,在发生系统崩溃的情况下会发生什么呢?首先会将这些变化信息存储在重做记录中,在完成所有更新操作后再恢复相应的数据变更。这种做法的好处在于即使发生系统崩溃事件后仍能恢复之前未提交的数据变更并将其应用到适当的位置上从而确保整个事务能够持续完成而不受影响。
总结:
ACID属性构成事务的核心要素,在其四个关键特征中,“原子性”扮演基础角色,“隔离性”则采用技术手段实现,“一致性”需满足的一致性要求,并最终目标就是确保数据持久存储
数据库事务即被称为由数据库设计者为了简便起见而将需要保证原子性、隔离性和一致性以及持久性的若干个数据库操作组合在一起的一个整体。
1.4 事务的状态
众所周知,在数据库领域中,“事务`(Transaction)是一个核心且抽象的基本概念”。具体而言,“事务实际上对应着一个或多个数据库操作序列”。基于这些操作的不同执行阶段,“MySQL将事务大致划分为几个不同的状态”,从而实现对数据一致性与不可重复性的有效管理。
活动的(active)
当事务关联到数据库操作正在进行中时,则称该事务处于 活动状态 之中。
部分提交的(partially committed)
当事务中的最后一个操作完成后,并且由于操作都在内存中进行而导致的影响并未 刷新到磁盘 时,则称该事务处于 部分提交 状态
失败的(failed)
当事务处于参与活动的状态或部分提交状态时,在遇到数据库内部错误、操作系统故障或直接断电等情况下就可能无法继续推进;如果此时人为终止当前事务的状态,则称该事务已处于失败状态。
中止的(aborted)
当事务进行一定程度后出现故障时,则必须将所有已修改的操作归还至事物开始前的状态;换句话说就是撤销该故障对数据库的影响过程即称为回滚;至此整个事物已回复至正常运行状态。
UPDATE accounts SET money = money - 50 WHERE NAME = 'AA';
UPDATE accounts SET money = money + 50 WHERE NAME = 'BB';
提交的(committed)
一旦某个事务处于未完全提交状态,并且其修改后的数据已被归档至磁盘时,则称该事务已达到了提交状态。
一个基本的状态转换图如下所示:

图中可见,在事务处于提交状态或已终止状态时,一个事务的生命周期才算结束。对于已完成提交操作的事务而言,系统会永久保存其对数据库所做的修改;而对于已被强行终止处理的事务,则会将其所有修改重放回至终止前的状态。
2. 如何使用事务
使用事务有两种方式,分别为 显式事务 和 隐式事务 。
2.1 显式事务
步骤1: START TRANSACTION 或者 BEGIN ,作用是显式开启一个事务。
mysql> BEGIN;
#或者
mysql> START TRANSACTION;
在操作过程中通常会伴随多个修饰项
READ ONLY:该事务的标识符为 只读事务 ,即表示该事务的所有数据库操作仅能进行读取操作,并非允许进行修改操作。
补充:在只读事务中仅禁止修改任何其他事务均可访问的数据。对于临时表(如通过CREATE TMEPORARY TABLE创建的表),由于它们仅在当前会话期间可见,则所有只读事务实际上仍可对这些临时表执行插入、删除及更新等基本操作。
表示这一事务涉及的数据处理既包括读取又包括修改
WITH CONSISTENT SNAPSHOT :启动一致性读。
比如:
START TRANSACTION READ ONLY; # 开启一个只读事务
START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT # 开启只读事务和一致性读
START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT # 开启读写事务和一致性读
注意:
- 通过设定事务的操作权限来实现对数据库信息的不同访问方式
- 一个事务的操作权限只能选择一种类型:要么仅具有Read Only功能(只能查看),要么允许进行Read Write操作(既能查看又能修改)
- 因此,在执行START TRANSACTION语句时这两个参数无法一同添加
- 如果不显式指定操作权限,默认情况下它会采用Read Write模式
步骤2: 一系列事务中的操作(主要是DML,不含DDL)
步骤3: 提交事务 或 中止事务(即回滚事务)
# 提交事务。当提交事务后,对数据库的修改是永久性的。
mysql> COMMIT;
# 回滚事务。即撤销正在进行的所有没有提交的修改
mysql> ROLLBACK;
# 将事务回滚到某个保存点。
mysql> ROLLBACK TO [SAVEPOINT]
其中关于SAVEPOINT相关操作有:
# 在事务中创建保存点,方便后续针对保存点进行回滚。一个事务中可以存在多个保存点。
SAVEPOINT 保存点名称;
# 删除某个保存点
RELEASE SAVEPOINT 保存点名称;
2.2 隐式事务
MySQL中有一个系统变量 autocommit :
mysql> show variables like 'autocommit';
+---------------+-------+
|Variable_name|Value|
+---------------+-------+
|autocommit|ON|
+---------------+-------+
1 row in set (0.01 sec)
当然,如果我们想关闭这种 自动提交 的功能,可以使用下边两种方法之一:
- 明确地使用
START TRANSACTION或BEGIN语句启动一个事务。- 将系统变量
autocommit的值设置为 OFF,在此期间自动提交功能被临时关闭。
- 将系统变量
SET autocommit = OFF;
#或
SET autocommit = 0;
UPDATE accout SET balance = blacnce - 10 WHERE id = 1; # 此时这条 DML 操作是一个独立的事务
UPDATE accout SET balance = blacnce + 10 WHERE id = 1; # 此时这条 DML 操作是一个独立的事务
2.3 隐式提交数据的情况
数据定义语言(Data definition language,缩写为:DDL)
数据库对象具体来说就是指那些用于存储和管理数据的基本结构类型如数据库(DB)、表(Table)、视图(View)以及存储过程(Stored Procedure)等。当我们使用这些关键字如CREATE``ALTER``DROP等语句去修改这些数据库对象时会使得操作被隐式地提交到当前的事务中即这些操作会被视为同一个整体进行处理。
例如:
当执行一个新增记录的操作后系统会自动将这个操作加入当前事务中直到所有指定的操作都被完成或发生错误。
BEGIN;
SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其他语句
CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务
隐式使用或修改mysql数据库中的表
在执行这些修改指令的时候,默认情况下所有的修改操作会被整合到同一个事务中进行处理。
- 事务控制或关于锁定的语句
在事务未提交或发生回滚的情况下进行START TRANSACTION或BEGIN语句的开启会导致上一交易隐式地被提交。
BEGIN;
SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其他语句
BEGIN; # 此语句会隐式的提交前边语句所属于的事务
注意:当上一个
BEGIN事务,没有做提交的时候,又再执行了一个BEGIN事务,则上一个,在这个 BEGIN 上一个开启的事务,就会被隐式的自动提交到事务了 。
BEGIN;
SELECT ... # 事务中的一条语句
UPDATE ... # 事务中的一条语句
... # 事务中的其他语句
BEGIN; # 此语句会隐式的提交前边语句所属于的事务
当前 autocommit 设置为 OFF ,当我们将其手动设置为 ON 时,则会自动提交与之相关的事务。
使用 LOCK TABLES 和 UNLOCK TABLES 这类锁定操作也会自动提交与之相关的事务。
- 加载数据的语句
在使用LOAD DATA语句进行批量导入至数据库的过程中,该操作会自动提交前一阶段指令所涉及的事务。
- 关于MySQL复制的一些语句
这些START SLAVE、STOP SLAVE、RESET SLAVE和CHANGE MASTER TO等命令将隐式地提交与之相关的事务。
- 其他的一些语句
采用ANALYZE TABLE等SQL指令进行操作时,默认会自动地提交与之相关的事务
2.4 使用举例1:提交与回滚
我们看下在 MySQL 的默认状态下,下面这个事务最后的处理结果是什么。
情况1:
CREATE TABLE user(name varchar(20), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO user SELECT '张三';
COMMIT;
BEGIN;
INSERT INTO user SELECT '李四';
INSERT INTO user SELECT '李四';
ROLLBACK;
SELECT * FROM user;

结果(1 行数据):
mysql> commit;
Query OK, 0 rows affected (0.00 秒)
mysql> BEGIN;
Query OK, 0 rows affected (0.00 秒)
mysql> INSERT INTO user SELECT '李四';
Query OK, 1 rows affected (0.00 秒)
mysql> INSERT INTO user SELECT '李四';
Duplicate entry '李四' for key 'user.PRIMARY'
mysql> ROLLBACK;
Query OK, 0 rows affected (0.01 秒)
mysql> select * from user;
+--------+
|name|
+--------+
|张三|
+--------+
1 行于数据集 (0.01 秒)

情况2:
CREATE TABLE user (name varchar(20), PRIMARY KEY (name)) ENGINE=InnoDB;
BEGIN;
INSERT INTO user SELECT '张三';
COMMIT;
INSERT INTO user SELECT '李四';
INSERT INTO user SELECT '李四';
ROLLBACK;
结果(2 行数据):
mysql> SELECT * FROM user;
+--------+
|name|
+--------+
|张三|
|李四|
+--------+
2 行于数据集 (0.01 秒)
情况3:
CREATE TABLE user(name varchar(255), PRIMARY KEY (name)) ENGINE=InnoDB;
SET @@completion_type = 1;
BEGIN;
INSERT INTO user SELECT '张三';
COMMIT;
INSERT INTO user SELECT '李四';
INSERT INTO user SELECT '李四';
ROLLBACK;
SELECT * FROM user;

结果(1 行数据):
mysql> SELECT * FROM user;
+--------+
|name|
+--------+
|张三|
+--------+
1 行于数据集 (0.01 秒)

当我们将 autocommit 设置为
0时,
不论是通过START TRANSACTION还是BEGIN来开启事务,
都需要通过COMMIT来提交以使事务生效,
使用ROLLBACK则会使得该事务被撤销。当我们将 autocommit 设置为
1
每条 SQL 指令都会自动提交。不过此时如果选择显式开启事务
则该事务仅在提交后才完成
否则在发生回滚时则会撤销该事务。
2.5 使用举例2:测试不支持事务的engine
myisam 存储引擎,不支持事务,InnoDB 存储引擎,支持事务。
CREATE TABLE test1(i INT) ENGINE=InnoDB;
CREATE TABLE test2(i INT) ENGINE=MYISAM;
针对于InnoDB表
BEGIN;
INSERT INTO test1 VALUES(1);
ROLLBACK;
SELECT * FROM test1;
结果:没有数据,回滚成功。
针对于MYISAM表:
BEGIN;
INSERT INTO test1 VALUES(1);
ROLLBACK;
SELECT * FROM test2;
结果:有一条数据
2.6 使用举例3:SAVEPOINT (保存回滚点)
创建表并添加数据:
CREATE TABLE account(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(15),
balance DECIMAL(10,2)
);
INSERT INTO account(NAME,balance)
VALUES
('张三',1000),
('李四',1000);

BEGIN;
UPDATE account SET balance = balance - 100 WHERE NAME = '张三';
UPDATE account SET balance = balance - 100 WHERE NAME = '张三';
SAVEPOINT s1; # 设置保存点
UPDATE account SET balance = balance + 1 WHERE NAME = '张三';
ROLLBACK TO s1; # 回滚到保存点
结果:张三:800.00
ROLLBACK;
结果:张三:1000.00(回到了 BEGIN 设置事务的地方)
3. 事务隔离级别
注意: 是事务的隔离级别,所以是对配置了事务上才有效果,作用的。
MySQL是一个基于客户端/服务器架构的软件系统,在同一台服务器上可以同时连接多个客户端实现数据通信。每个客户端在建立一个会话后即可与服务器进行交互交流,在这个过程中都可以独立地向数据库发送请求语句。这些请求语句可能属于同一个事务也可能分布在不同的事务中,在这种情况下对数据库资源进行统一管理显得尤为重要。理论上讲,在任何一个事务对特定数据进行访问时都应当保证其他事务能够及时响应避免冲突这种情况在实际应用中可能会导致性能下降因此我们需要在保证事务处理的隔离特性的同时尽量提高数据库处理大量并发事务时的整体性能水平以达到最佳平衡点
3.1 数据准备
CREATE TABLE student (
studentno INT,
name VARCHAR(20),
class varchar(20),
PRIMARY KEY (studentno)
) Engine=InnoDB CHARSET=utf8;
然后向这个表里插入一条数据:
INSERT INTO student VALUES(1, '小谷', '1班');
现在表里的数据就是这样的
mysql> select * from student;
+-----------+--------+-------+
|studentno|name|class|
+-----------+--------+-------+
|1|小谷|1班|
+-----------+--------+-------+
1 row in set (0.00 sec)
3.2 数据并发问题
当处理事务的隔离性与并发性时,如何做出权衡?接着观察那些访问相同数据的事务,在不保证串行执行的情况下(即在一个事务完成前另一个就可以运行),可能出现哪些问题:
- 脏写( Dirty Write )
对于两个事务 Session A 和 Session B 来说,在以下情况下发生:当其中一个事务(如 Session A)对另一个事务(如 Session B)已经存在的数据进行了修改,并且该被修改的数据属于未提交的状态时,则称这种情况为脏写行为。

Session A 和 Session B 各开启了一个事务,Sesssion B 中的事务先将studentno列为1的记录的name列更新为'李四',然后Session A中的事务接着又把这条studentno列为1的记录的name列更新为'张三'。如果之后Session B中的事务进行了回滚,那么Session A中的更新也将不复存在,这种现象称之为脏写。这时Session A中的事务就没有效果了,明明把数据更新了,最后也提交事务了,最后看到的数据什么变化也没有。这里大家对事务的隔离性比较了解的话,会发现默认隔离级别下,上面Session A中的更新语句会处于等待状态,这里只是跟大家说明一下会出现这样的现象。
- 脏读( Dirty Read )
对于两个事务 Session A 和 Session B,在Session B已修改但未提交的情况下,Session A已获取了相应的字段记录内容。如果随后发生Session B的撤销操作,则Session A所获取的内容将被视为临时无效。

在Session A和Session B中各启动了一个事务,在这个过程中,
首先,
Session B的操作会将studentno=1这一记录的学生姓名字段更新
为此,
在后续操作中,
当Session A尝试查询该条学生信息时,
若发现该学生姓名仍显示"张三",
但随后却发现实验数据已被重置(提交前发现发生了脏读问题)。
这种情况被称为 脏读( dirty read)。
- 不可重复读( Non-Repeatable Read )
对于两个事务Session A、Session B,在完成一次操作后,Session A 获得了一个字段,并随后由 Session B 执行了对该字段进行更新操作。在 Session A 完成再次读取该字段后发现其值已经发生变化,则表明发生了不可重复读的情况。

在Session B期间执行了几项 隐式事务 操作(特别指明这类操作的特点在于一旦完成就会被提交),这些操作均会修改studentno字段设为1的相关记录中的列name属性值,在每次执行完一项操作后发现Session A中的所有相关操作都能够获取到最新的更新数据这一现象也可被统称为 不可重复读行为
不可重复读:可以说数据内容在当前事务中被取出时得到的不同值,并非相同或一致,并已被其他事务修改。无法获得相同的记录信息。
- 幻读( Phantom )
对于两个事务Session A和B来说,在同一个表中先由Session A 获取某一个字段的数据后,Session B又向该表中 添加了一系列新的记录。随后,在这种情况下如果 Session A 再次调用‘读取’方法的话就会发现表格中有新增的数据项出现。这表明发生了‘幻读’现象。

在Session A中首先依据studentno > 0这一筛选标准查询学生表,在name列为‘张三’的相关记录上获得了初步结果;随后提交了一个名为‘隐式事务’的操作,并往学生表中追加一条新的数据记录;接着,在应用相同的标准筛选后发现结果集中包含了来自前一操作新增的数据项,并因此被定义为‘幻读’现象;最后我们将这些新增的数据项统称为‘幻影记录’
幻测:其核心在于基于某个相同条件连续重复地获取记录,在后续操作中发现未被先前捕捉到的记录。

3.3 SQL中的四种隔离级别
在介绍几种潜在的并发事务执行问题时,请注意这些问题是轻重缓急并存的。为此建议按照其严重性对这些情况进行排序:
脏写 > 脏读 > 不可重复读 > 幻读
我们愿意以牺牲一部分 isolate level 为代价换取一部分 performance,在这里就能体现:设定一定数量 of isolate levels,在设定较低 level 的情况下, concurrent problems will occur more frequently.
READ UNCOMMITTED:在这一隔离级别下(有时称为"无持久化读"),所有参与者的操作均可以完整地了解其他参与者尚未完成的操作结果(即未提交变更)。这种情况下无法避免出现脏读现象、不可重复读现象以及幻读现象。READ COMMITTED:"已提交读"意味着每个参与者仅能观察到已经完成并经提交的数据变更(即已持久化的数据)。这种情况下满足最基础的隔离原则:即一个参与者在操作时只能看到已经被其他参与者已完成并经提交的数据变更(即已持久化的数据)。这种情况下可以避免脏读现象和不可重复读现象的发生(但仍然可能存在幻读现象)。这种隔离级别是大多数数据库系统的默认设置(但在MySQL中并非如此)。它能够避免脏-read问题但仍然无法解决不可重复-read和幻-read的问题。REPEATABLE READ:"可重复性read"意味着如果一个参与者在一个特定的数据行上执行了一个read操作,则该参与者将能够从另一个参与者对该行进行修改并提交后获得相同的结果中获得相同的值。换句话说,在这种情况下如果一个参与者在一个特定的数据行上执行了一个read操作,则该参与者将能够从另一个参与者对该行进行修改并提交后获得相同的结果中获得相同的值。在这种情况下可以避免脏-read以及不可重复-read的问题但仍然可能存在幻-read的现象。MySQL默认采用的是这种隔离级别。SERIALIZABLE:"串行化"隔离级别意味着所有参与者的操作均能在逻辑上被视为一个单一的操作序列(即使这些操作实际上是在物理层面上同时进行的)。在这种情况下不仅所有的脏-read、不可重复-read以及幻-read等问题都能得到完全消除而且所有的并发问题也能得到完全消除——包括那些可能由于不一致的数据状态导致的问题——但代价是性能表现得非常糟糕。
在SQL标准中明确规定,在各个隔离级别下,并行操作可能导致不同程度的冲突

脏写没有被提及吗?因为这个脏写问题十分严重,并且所有隔离级别都不允许存在脏写情况。
不同的隔离级别分别表现出各自独特的现象,并伴随着不同的锁和并发机制。随着隔离等级的提升,在大多数情况下(尤其是在高负载场景下),数据库的并发性能会随之下降。根据现有研究,在现有研究范围内通常涉及四种主要的事务隔离级别。

3.4 MySQL支持的四种隔离级别

MySQL的预设隔离等级为REPEATABLE READ;我们可以通过调整事务的隔离等级来实现其修改。
# 查看隔离级别,MySQL 5.7.20的版本之前:
mysql> SHOW VARIABLES LIKE 'tx_isolation';
+---------------+-----------------+
|Variable_name|Value|
+---------------+-----------------+
|tx_isolation|REPEATABLE-READ|
+---------------+-----------------+
1 row in set (0.00 sec)
# MySQL 5.7.20版本之后,引入transaction_isolation来替换tx_isolation
# 查看隔离级别,MySQL 5.7.20的版本及之后:
mysql> SHOW VARIABLES LIKE 'transaction_isolation';
+-----------------------+-----------------+
|Variable_name|Value|
+-----------------------+-----------------+
|transaction_isolation|REPEATABLE-READ|
+-----------------------+-----------------+
1 row in set (0.02 sec)
#或者不同MySQL版本中都可以使用的:
SELECT @@transaction_isolation;

mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
|Variable_name|Value|
+-----------------------+-----------------+
|transaction_isolation|REPEATABLE-READ|
+-----------------------+-----------------+
1 row in set (0.01 sec)

mysql> select @@transaction_isolation;
+-------------------------+
|@@transaction_isolation|
+-------------------------+
|REPEATABLE-READ|
+-------------------------+
1 row in set (0.00 sec)
3.5 如何设置事务的隔离级别
通过下面的语句修改事务的隔离级别:
SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别;
#其中,隔离级别格式:
> READ UNCOMMITTED
> READ COMMITTED
> REPEATABLE READ
> SERIALIZABLE
或者:
SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别'
#其中,隔离级别格式:
> READ-UNCOMMITTED
> READ-COMMITTED
> REPEATABLE-READ
> SERIALIZABLE
关于设置时使用GLOBAL或SESSION的影响:
- 使用 GLOBAL 关键字(在全局范围影响):
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET GLOBAL TRANSACTION_ISOLATION = 'SERIALIZABLE';
则:
- 当前已经存在的会话无效
- 只对执行完该语句之后产生的会话起作用
使用 SESSION 关键字(在会话范围影响):
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
#或
SET SESSION TRANSACTION_ISOLATION = 'SERIALIZABLE';
则:
- 该会话中的所有后续操作均受其影响
- 即使在处理其他事务时也会对其后的操作产生影响
- 该指令可以在多个已运行的操作中执行而不干扰当前任务
当启动服务器时旨在调整事务的默认隔离级别。可以通过设置参数t|_ transaction isolation|_ 来实现这一目标。例如,在设置参数t|_ transaction isolation|_ 时指定其值为SERIALIZABLE,则会将默认隔离级别由原先采用的是REPEATABLE-READ切换至SERIALIZABLE。
小结:
数据库为事务操作设置了多种隔离级别,在不同的隔离级别下会呈现出不同程度的干扰效果;采用较高隔离级别的事务操作能够保证数据的一致性,在一定程度上提升系统的稳定性;然而这也会相应地降低其并发能力。
3.6 不同隔离级别举例
初始化数据:
TRUNCATE TABLE account;
INSERT INTO account VALUES (1,'张三','100'), (2,'李四','0');

演示1. 读未提交之脏读
设置隔离级别为未提交读:

被称作脏读的这种情况是指当前事务正在访问某组数据库,并对其进行了更新操作。但这些更新操作尚未被提交至数据库系统中。此时,在同一时间段内有另一个事务同样也在进行对该组数据库的读取操作。随后会将该组数据库的数据引用到其他相关的操作中进行处理。
演示2:读已提交

演示3. 不可重复读
设置隔离级别为可重复读,事务的执行流程如下:

当我们配置当前对话框的隔离级别为可重传式时,在这种情况下允许该会话被反复执行;也就是说,在这种情况下无论其他事务是否提交都会返回相同的查询结果集
演示4:幻读



4. 事务的常见分类
从事务理论的角度来看,可以把事务分为以下几种类型:
- 平凡事务(Flat Transaction)
- 带有保存点的平凡事务(Flat Transaction with Savepoint)
- 链式事务(Chaining Transaction)
- 嵌套式事务(Nested Transaction)
- 分布式的事务(Distributed Transaction)
