mysql并发事务解决
不同隔离级别下,mysql解决并发事务的方式不同。主要由锁机制和MVCC(多版本并发控制)机制来解决并发事务问题。
1. mysql中的锁有哪些?
-
表级锁:
- 场景:表级锁适用于需要对整个表进行操作的情况,例如在执行DDL语句(如
ALTER TABLE
)时需要锁定整个表。 - 隔离级别中的使用:表级锁通常在所有隔离级别下都会使用,因为它们可以在需要时锁定整个表,从而防止并发修改。
- 场景:表级锁适用于需要对整个表进行操作的情况,例如在执行DDL语句(如
-
行级锁:
-
共享锁(Shared Lock) :解决了并发事务 读-读 读-写 问题
- 场景:共享锁允许多个事务同时读取同一行数据,适用于读取操作。例如,当一个事务读取数据时,可以使用共享锁防止其他事务对数据进行写操作。
- 隔离级别中的使用:共享锁在“读已提交”(Read Committed)及以上的隔离级别使用,以防止其他事务对数据进行不一致的修改。
-
排他锁(Exclusive Lock) :解决了并发事务 写-写 问题
- 场景:排他锁用于对数据进行写操作,确保在同一时间只有一个事务可以对数据进行修改。
- 隔离级别中的使用:排他锁在所有隔离级别下都会使用,因为它们确保数据在被修改时不会被其他事务修改。
-
-
间隙锁(Gap Lock) :
- 场景:间隙锁用于防止并发事务在范围查询中插入新数据,确保数据一致性。
- 隔离级别中的使用:间隙锁主要在“可重复读”(Repeatable Read)隔离级别下使用,以防止其他事务在查询范围内插入新数据,导致幻读问题。
-
Next-Key Lock:
- 场景:Next-Key Lock可以看作是间隙锁的一个增强版本,结合了行锁和间隙锁的特性,用于防止并发事务在范围查询中插入新数据或修改已有数据,同时也防止幻读问题。
- 隔离级别中的使用:Next-Key Lock也是在“可重复读”(Repeatable Read)隔离级别下使用,与间隙锁一起,用于防止幻读问题的发生。
在MySQL中,根据隔离级别的不同,使用的锁也会有所不同,以确保在不同的并发情况下保证数据的一致性和隔离性。
2. MVCC原理
MVCC概念
MySQL中的InnoDB存储引擎利用MVCC(多版本并发控制)来优化并发性能,并确保事务间的隔离性。解决了并发事务 写-读 问题。MVCC允许不同的事务在同一时刻看到数据库的不同版本状态,以此来减少锁定需求,尤其对于读密集型应用而言,可以显著提升并发读取性能。
MVCC核心组件
-
隐藏字段
-
每一行记录除了我们通常定义的列之外,还包含一些隐藏的系统字段:
- DB_TRX_ID(事务ID): 记录最后一次修改该行记录的事务ID。
- DB_ROLL_PTR(回滚指针): 指向对应的undo日志记录,用于获取该行的前一个版本。
- DB_ROW_ID(行ID): 在某些情况下作为聚簇索引的补充,用于非唯一二级索引定位记录。
-
-
Undo Log (回滚日志)
- 当事务对数据进行修改时,InnoDB会产生 undo log 记录原来的值,形成版本链。
- 每次更新操作都会生成一个新的版本,并将旧版本链接到undo log中。
- Undo日志不仅用于事务回滚,也用于MVCC提供历史版本数据给读事务。
-
Read View (一致性读视图)
-
在开启事务时,InnoDB会创建一个Read View用来确定事务执行过程中哪些版本的数据对它是可见的。
-
Read View包含了以下关键信息:
- m_ids: 当前系统中活跃事务的最小和最大事务ID。
- active_trx_list: 活跃事务列表,这些事务可能修改了数据但还未提交。
- 创建Read View时系统全局事务ID计数器的值。
-
MVCC的工作原理
MVCC是“维持一个数据的多个版本,使读写操作没有冲突”的一个抽象概念
。 这个概念需要具体功能去实现,这个具体实现就是快照读
。
-
快照读:在可重复读(Repeatable Read)隔离级别下,普通的
SELECT
语句不会加锁而是采用一致性读(快照读),根据当前事务的Read View来读取创建视图时刻之前已经提交的数据版本。-
根据以下规则判断某行记录对于当前事务是否可见:
- 如果DB_TRX_ID小于Read View的最低事务ID(min trx id),表示该行在Read View创建前就已经提交,因此是可见的。
- 如果DB_TRX_ID大于或等于Read View的最低事务ID,但不在活跃事务列表中,同样视为已提交且可见。
- 若DB_TRX_ID大于或等于Read View的最低事务ID且在活跃事务列表中,说明是未提交事务更改的数据,不可见。InnoDB会查询undo log中的历史版本数据,直到找到最接近的已提交数据版本,将其提供给当前事务使用。
- 若DB_TRX_ID等于当前事务的事务ID,表示是当前事务自己修改的数据,也是可见的。
-
-
事务结束时的清理:
- 当事务提交时,其修改过的记录的旧版本可以在适当的时机被purge线程清除,以回收存储空间。
- 已经不再被任何事务使用的旧版本数据会被从undo日志中移除。
通过上述机制,MVCC能够在很大程度上降低事务之间的互斥,提高并发性能,同时保证事务的ACID特性(原子性、一致性、隔离性和持久性)。在实际应用中,尤其是在高并发的OLTP系统中,MVCC是保证数据库高性能并发处理的重要手段。
MVCC机制生效条件
MVCC机制只在读已提交和可重复读隔离级别下才会生效。
- 读已提交(READ COMMITTED) : 在这个隔离级别下,每次
SELECT
语句执行时,都会获取最新的已提交数据,这意味着每次查询都可能看到不同的数据版本,因为每次查询都会获取一个最新的快照。然而,与Repeatable Read相比,这里的“快照”并不是事务开始时固定的视图,而是每次查询时动态获取的。 - 可重复读(REPEATABLE READ) : 这是MySQL InnoDB存储引擎的默认事务隔离级别。在这个级别下,同一个事务内的普通
SELECT
语句确实不会加锁,而是始终读取事务启动时存在的已提交数据版本,也就是说,同一个事务内多次执行相同的SELECT
语句结果总是相同的,不会受到其他事务提交的影响。
总结来说,所谓的MVCC指的就是在使用READ COMMITTD、REPEATABLE READ这两种隔离级别的事务在执行普通的SEELCT操作时访问记录的版本链的过程,这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。