TCL:事务控制语言,负责处理 ACID 事务,支持 commit、rollback 指令
事务的属性:原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)
隔离级别:读未提交 read uncommitted、读已经提交 read committed、可以重复读 repeatable read、可串行化 serializable
概述
- InnoDB 引擎,支持事务
- 事务:若干条语句组成,一系列操作
- 关系型数据库中支持事务,必须支持其四个属性: ACID
特性 | 描述 |
---|---|
原子性(atomicity) | 一个事务是一个不可分割的工作单位,事务中包括的所有操作要么全部做完,要么什么都不做 |
一致性(consistency) | 事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的,多个事务并行执行和串行执行的结果一致,也就是说结果是可预期的 |
隔离性(isolation) | 一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰,隔离性就是在一个事务处理期间,其他事务能不能访问的问题 |
持久性(durability) | 持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响(即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态) |
- automicity: all changes to the data must be performed successfully or not at all
- consistency: data must be in a consistent state before and after the transaction
- isolation: no other process can change the data while the transaction is running
- durability: the changes made by a transaction must persist
MySQL 隔离级别
引起的问题
隔离性不好,事务的操作就会互相影响,带来不同严重程度的后果。
隔离性不好会带来如下几个方面的问题:
- 更新丢失 Lost Update
提交或者回滚一个事务,把其它事务已提交的更新的数据覆盖了
事务 A 和 B,更新同一个数据,B 的更新覆盖了 A 的更新,A的更新就丢失了 - 脏读 Ditry Read(Uncommitted Data)
一个事务读到另一个事务未提交的更新数据
事务 A 和 B,事务 B 读取到了事务 A 未提交的数据(这个数据可能是一个中间值,也可能事务 A 后来回滚事务)。事务 A 是否最后提交并不关心。只要读取到了这个被修改的数据就是脏读 - 不可重复读 Unrepeatable read
一个事务两次读同一行数据,可是这两次读到的数据不一样
事务 A 在事务执行中相同查询语句,得到了不同的结果,不能保证同一条查询语句重复读相同的结果就是不可以重复读。例如,事务 A 查询了一次后,事务 B 修改了数据,事务 A 又查询了一次,发现数据不一致了 - 幻读 Phantom read
一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行
事务 A 中同一个查询要进行多次,事务 B 插入数据,导致 A 返回不同的结果集,就是幻读。数据集有记录增加/减少了,可以看做是增加/减少了记录的不可重复读
数据库隔离级别
如下,隔离级别由高到低:
隔离级别 | 描述 |
---|---|
READ UNCOMMITTED | 读取到未提交的数据 |
READ COMMITTED | 读已经提交的数据,ORACLE 默认隔离级别 |
REPEATABLE READ | 可以重复读,MySQL 的默认隔离级别 |
SERIALIZABLE | 可串行化。事务间完全隔离,事务不能并发,只能串行执行 |
- 读未提交 read uncommitted:能够读到别的事务还没提交的数据。完全没有隔离性,会出现脏读,当然还会出现更新丢失,不可重读读,幻读问题出现
- 读已经提交 read committed:能够读取到其他事务已经提交(commit)的数据,解决了脏读。但不能解决不可重复读和幻读的问题,因为其他事务前后修改了数据或者增删了数据
- 可以重复读 repeatable read:事务中同一条查询语句返回同样的结果,即可以重复读数据。
- 可以重复读的实现方案:1. 对 select 数据加锁,不允许其他事务删除、修改操作;2. 第一次 select 时对最后一次确切提交的事务做快照
- 可以重复读解决了不可以重复读问题,但可能会出现幻读,因为其他事务可以增删数据
- 可串行化 serializable:事务串行执行。解决了更新丢失、脏读、不可重复读、幻读所有问题,但执行效率低
- 隔离级别越高,串行化越高,数据库执行效率低;隔离级别越低,并行度越高,性能越高;隔离级别越高,当前事务处理的中间结果对其它事务不可见程度越高
数据库设置隔离级别
-- 设置会话级或者全局隔离级别,一般用会话级
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL
{READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
-- 查询隔离级别
SELECT @@global.tx_isolation;
SELECT @@tx_isolation;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- 禁用自动提交
SET AUTOCOMMIT = 0
START TRANSACTION
或BEGIN
开始一个事务- 使用
COMMIT
提交事务后,变更成为永久变更 ROLLBACK
可以在提交事务之前,回滚变更,事务中的操作就如同没有发生过一样(原子性)SET AUTOCOMMIT
语句可以禁用或启用默认的autocommit
模式,用于当前连接。SET AUTOCOMMIT = 0
禁用自动提交事务。如果开启自动提交,如果有一个修改表的语句执行后,会立即把更新存储到磁盘
实验:开两个连接MariaDB的session(两个xshell连接同一虚拟机,并连接数据库操作)并设置session的隔离级别,分别在两个session执行select语句深入理解隔离级别