MySQL MVCC
MySQL
事务
事务具备 ACID 特性,具体描述如下:
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行[3]。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束[3]。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行[3]。
持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中[3]。
在典型的应用程序中,多个事务并发运行,经常会导致操作相同的数据来完成各自任务,如果不对操作的数据做任何限制则会出现以下问题。
脏读:一个事务读取了另一个事务还未提交的数据。
丢失修改:在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
例:A 事务、B 事务都对数据 C 做了减一操作,但是最后 C 只减去了一,一个事务的修改丢失了
不可重复读:在同一个事务内读取数据结果不一致
幻读:类似于不可重复读,它发生在同一个事务两次读取中间,另一事务插入了一批数据,导致第二次读取结果多了一些不存在的记录
MVCC
MySQL 在 InnoDB 引擎实现了 MVCC(Mutli-Version-Concurrency-Control),来保证事务的 ACID 特性
读操作
当前读
在 MySQL 中,当前读是一种读取数据的操作方式,它直接读取数据的最新版本,读取时要保证其他事务不能修改当前记录,会对当前记录进行加锁,当前读有两种实现方式
一致性读
在默认隔离级别(RR)下,MySQL 使用一致性读在实现当前读,在事务开始的时刻创建一个一致性视图,该视图反映了事务开始时刻的数据。在事务执行期间,不论其他事务对数据进行了任何的修改,事务始终使用一致性视图来读取数据,这样保证了不会发生不可重复的问题。
锁定读
锁定读通过加共享锁/排他锁来保证数据的一致性,共享锁允许多个事务读取统一数据,排他锁则阻塞其他事务读取和修改数据,锁定读适用于严格控制并发的场景,加锁带来的性能开销较大。
| 语句 | 加锁方式 |
|---|---|
| SELECT … FOR UPDATE | 排他锁 |
| SELECT … LOCK IN SHARE MODE | 共享锁 |
| UPDATE、DELETE、INSERT | 排他锁 |
快照读
快照读是在读取数据时取一个一致性视图的数据,在不同的事务隔离级别下,效果不同。
| 隔离级别 | 视图创建时机 | 效果 |
|---|---|---|
| READ COMMITTED | 每次 SELECT 都生成新快照 | 每次读都能看到最新已提交数据 |
| REPEATABLE READ | 事务开始时生成快照 | 整个事务期间读到的都是同一版本 |