MySQL

事务

事务具备 ACID 特性,具体描述如下:

  • 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行[3]

  • 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束[3]

  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行[3]

  • 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中[3]

在典型的应用程序中,多个事务并发运行,经常会导致操作相同的数据来完成各自任务,如果不对操作的数据做任何限制则会出现以下问题。

  • 脏读:一个事务读取了另一个事务还未提交的数据。

  • 丢失修改:在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。

    例:A 事务、B 事务都对数据 C 做了减一操作,但是最后 C 只减去了一,一个事务的修改丢失了

  • 不可重复读:在同一个事务内读取数据结果不一致

  • 幻读:类似于不可重复读,它发生在同一个事务两次读取中间,另一事务插入了一批数据,导致第二次读取结果多了一些不存在的记录

MVCC

MySQL 在 InnoDB 引擎实现了 MVCC(Mutli-Version-Concurrency-Control),来保证事务的 ACID 特性

读操作

当前读

在 MySQL 中,当前读是一种读取数据的操作方式,它直接读取数据的最新版本,读取时要保证其他事务不能修改当前记录,会对当前记录进行加锁,当前读有两种实现方式

  1. 一致性读

    在默认隔离级别(RR)下,MySQL 使用一致性读在实现当前读,在事务开始的时刻创建一个一致性视图,该视图反映了事务开始时刻的数据。在事务执行期间,不论其他事务对数据进行了任何的修改,事务始终使用一致性视图来读取数据,这样保证了不会发生不可重复的问题。

  2. 锁定读

    锁定读通过加共享锁/排他锁来保证数据的一致性,共享锁允许多个事务读取统一数据,排他锁则阻塞其他事务读取和修改数据,锁定读适用于严格控制并发的场景,加锁带来的性能开销较大。

语句 加锁方式
SELECT … FOR UPDATE 排他锁
SELECT … LOCK IN SHARE MODE 共享锁
UPDATE、DELETE、INSERT 排他锁

快照读

快照读是在读取数据时取一个一致性视图的数据,在不同的事务隔离级别下,效果不同。

隔离级别 视图创建时机 效果
READ COMMITTED 每次 SELECT 都生成新快照 每次读都能看到最新已提交数据
REPEATABLE READ 事务开始时生成快照 整个事务期间读到的都是同一版本