MySQL 事务
# 事务特性: ACID
https://zh.wikipedia.org/wiki/ACID (opens new window)
- Atomicity(原子性):一个事务中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
- Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
- Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
# 事务隔离级别
事务的隔离级别,属于 ACID 中的 Isolation(隔离性)
未提交读(READ UNCOMMITTED) 最低的隔离级别,事务可以看到其他事务“尚未提交”的修改,会产生“脏读”(dirty reads)
提交读(READ COMMITTED) 一个事务提交之后,数据变更才可以被其他事务马上看到
可重复读(REPEATABLE READS) 一个事务提交之后,数据变更才会被其他事务看到。但是另一个事务执行过程中,看到的数据总是一致的,直到当前事务提交,才能看到最新值,会产生“幻读”(phantom reads)
可串行化(SERIALIZABLE) 要求在选定对象上的读锁和写锁保持直到事务结束后才能释放,可以避免“幻读”(phantom reads)
脏读:一个事务能读取另外一个事务修改但未提交的数据
不可重复读:在一次事务中,一行数据查询两遍得到不同的结果
幻读:在事务执行过程中,当两个完全相同的查询语句执行得到不同的结果集。这种现象称为“幻影读(phantom read) 参考:https://zh.wikipedia.org/wiki/事務隔離 (opens new window)
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
未提交读 | 可能 | 可能 | 可能 |
提交读 | - | 可能 | 可能 |
可重复读 | - | - | 可能 |
可串行化 | - | - | - |
# 事务隔离的实现
在 InnoDB 里,每个事务启动会先申请一个 transaction id,transaction id 是顺序递增的,并根据 transaction id 为所有数据生成一个快照视图(read-view),这个快照只是一个逻辑数据,并不是物理磁盘的数据不需要额外占用物理空间,这就是数据库的多版本并发控制(MVCC)。也就是数,一条记录会有多个版本,在不同事务隔离级别下会根据数据的版本计算可见范围。
# 查询数据库隔离级别
查询当前回话事务隔离级别
SELECT @@session.tx_isolation; -- 或 SELECT @@tx_isolation; -- MySQL 8 SELECT @@transaction_isolation
1
2
3
4
5查询全局事务隔离级别
select @@global.transaction_isolation, @@transaction_isolation; -- 或 show variables like '%tx_isolation%'; -- 修改事务级别(重启后失效,需要再服务器修改配置文件) SET GLOBAL tx_isolation='READ-COMMITTED'
1
2
3
4
5
6
# 修改事务级别
-- 修改事务级别
SET GLOBAL tx_isolation='READ-COMMITTED'
2
修改服务器配置(防止重启后配置还原)
[mysqld]
transaction-isolation=READ-COMMITTED
2
# 如何选择事务隔离级别
读未提交(数据不一致)和串行化(并发度低)一般是不会选择的,那么就是在 RC 和 RR 中选择。
通常在性能要求较高的场景中会选择使用 RC + binlog(row)组合。
- RR 会产生间隙锁,锁粒度更大,更容易造成死锁
- RC 的并发度低于 RR,性能更高
参考:https://time.geekbang.org/column/article/75173 (opens new window)