目录
1.mysql有哪些锁及作用
MySQL 中的锁机制主要用于在并发环境中管理对数据的访问,确保数据的一致性和完整性。InnoDB 存储引擎作为 MySQL 中支持事务的主流引擎,提供了丰富的锁类型来应对不同的并发场景。以下是一些主要的锁类型及其作用:
1. 行锁(Row Locks)
- 作用:锁定单个数据行,防止其他事务同时对同一行进行写操作,支持高并发下的精细化访问控制。
- 类型:
- 共享锁(Shared Locks / S Locks):允许事务读取一行数据,阻止其他事务对该行加排他锁(即写锁)。
- 排他锁(Exclusive Locks / X Locks):允许事务修改一行数据,阻止其他事务对该行加任何锁(包括读锁和写锁)。
2. 间隙锁(Gap Locks)
- 作用:锁定索引记录之间的间隙,防止其他事务在该间隙内插入新记录,主要用于防止幻读(Phantom Reads)。
- 场景:在可重复读(Repeatable Read)隔离级别下,InnoDB 使用 Next-Key Locks,其中包含了 Gap Locks。当进行范围查询时,除了锁定查询命中的记录,还会锁定查询范围内的间隙。
3. Next-Key Locks
- 作用:结合了行锁和间隙锁,锁定一个记录及其前一个间隙。在可重复读隔离级别下,Next-Key Locks 能有效防止幻读。
- 场景:当查询条件涉及索引列时,InnoDB 通常会使用 Next-Key Locks。锁定范围包括索引记录本身及其左侧的间隙。
4. 意向锁(Intention Locks)
- 作用:意向锁是一种表级别的锁,用于表示事务对表中某一行的加锁意图,分为意向共享锁(IS Locks)和意向排他锁(IX Locks)。
- 场景:在事务申请行锁之前,先在表级别加意向锁。这样,当多个事务同时请求不同行的锁时,可以通过检查意向锁来快速判断是否存在锁冲突,避免了逐行检查的开销。
5. 表锁(Table Locks)
- 作用:锁定整张表,阻止其他事务对表进行读写操作,适用于全表扫描、DDL 操作等场景。
- 类型:
- 表共享锁(Table Read Locks / Shared Table Locks):允许事务读取表中的数据,阻止其他事务对该表加表写锁或进行 DDL 操作。
- 表排他锁(Table Write Locks / Exclusive Table Locks):允许事务修改表中的数据,阻止其他事务对该表加任何锁(包括表读锁和表写锁)或进行 DDL 操作。
6. 元数据锁(Metadata Locks, MDL)
- 作用:在访问表的元数据(如表结构)时自动加锁,确保在并发 DDL 操作时,其他会话不会对正在被修改的表进行不兼容的操作,如读取、修改或删除表结构。
- 类型:
- MDL 读锁(Shared MDL Locks):在查询表结构时自动加锁,多个会话可以同时持有。
- MDL 写锁(Exclusive MDL Locks):在执行 DDL 操作时加锁,阻止其他会话对表进行读取或写入操作。
7. 自增锁(Auto-Increment Locks)
- 作用:在使用 AUTO_INCREMENT 列时,确保为新行生成的自增值是唯一的,不会被并发插入的事务重复使用。
- 场景:当向包含 AUTO_INCREMENT 列的表中插入新行时,InnoDB 会获取自增锁,确保生成并分配唯一的自增值。
综上所述,MySQL 中的锁种类丰富,涵盖了行级、间隙级、表级以及元数据级,每种锁都有其特定的作用和适用场景,共同协作以实现对数据并发访问的有效控制,确保数据的一致性和完整性。在实际应用中,理解和合理使用这些锁类型对于优化并发性能、避免死锁和数据冲突至关重要。
2.隔离级别和锁的关系
MySQL 的事务隔离级别与锁机制密切相关,它们共同决定了在并发事务环境下数据的一致性和并发性能。隔离级别定义了事务之间数据访问的隔离程度,而锁则是实现这些隔离级别所采用的具体控制手段。以下是隔离级别与锁之间的具体关系:
1.读未提交(Read Uncommitted)
最低级别,允许事务看到其他未提交事务的修改。这种级别下,读操作通常不加锁或仅使用非常短暂的共享锁,可能导致脏读、不可重复读和幻读问题。
2.读已提交(Read Committed)
- 在这个级别,一个事务只能看到已经提交的数据。读操作一般采用快照读(Snapshot Read)或当前读(Current Read),前者依赖于MVCC(多版本并发控制)机制,无需加锁;后者则需要加共享锁,直到当前读操作完成。
- 写操作仍然需要加排他锁,但在事务提交后立即释放,从而减少锁的持续时间,降低锁冲突。
3.可重复读(Repeatable Read)
- MySQL InnoDB 引擎的默认隔离级别。在此级别,一个事务在整个执行过程中看到的数据视图是不变的,即多次读取同一数据会得到相同的结果。
- 快照读继续使用 MVCC 机制,无需加锁,保证了在事务期间的可重复读。
- 当前读(如
SELECT ... FOR UPDATE
或SELECT ... LOCK IN SHARE MODE
,以及所有写操作)会使用行锁,并且在可重复读隔离级别下,InnoDB 还会使用间隙锁和Next-Key Locks来防止其他事务插入“幻影”记录,从而避免幻读问题。
4.串行化(Serializable)
- 最高级别,提供完全的隔离,事务按顺序依次执行,效果等同于单线程执行。
- 实现上,通常通过更加严格的锁策略,如对查询涉及的所有数据范围加锁(不仅仅是所选行,还包括其间的间隙),或者使用Serializable Snapshot Isolation(SSI)等高级并发控制技术来模拟串行执行的效果。在这种级别下,虽然可以完全避免脏读、不可重复读和幻读,但可能导致大量的锁等待和锁冲突,显著降低系统的并发性能。
总结来说,不同的事务隔离级别对应着不同的数据一致性保证和锁使用策略:
- 低级别(如读未提交)允许更多的并发,但可能会出现各种数据不一致现象。
- 高级别(如可重复读、串行化)提供更强的数据一致性保证,但可能会增加锁的使用和等待,影响并发性能。
在实际应用中,选择合适的事务隔离级别需要权衡数据一致性和系统性能的需求。同时,了解不同隔离级别下锁的行为有助于诊断和优化并发事务中的性能问题,避免死锁和数据竞争。
3.InnoDB 中的锁算法
- Record lock:单个行记录上的锁
- Gap lock:间隙锁,锁定一个范围,不包括记录本身
- Next-key lock:record + gap 锁定一个范围,包含记录本身
4.什么是快照读和当前读
快照读
就是读取的是快照数据,不加锁的简单 Select 都属于快照读。
SELECT * FROM player WHERE ...
当前读
就是读的是最新数据,而不是历史的数据。加锁的 SELECT,或者对数据进行增删改都会进行当前读。
SELECT * FROM player LOCK IN SHARE MODE;
SELECT FROM player FOR UPDATE;
INSERT INTO player values ...
DELETE FROM player WHERE ...
UPDATE player SET ...
5.什么是 MVCC 以及实现
MVCC(Multiversion Concurrency Control,多版本并发控制)是一种在数据库管理系统中实现并发控制的机制,尤其在支持事务的存储引擎中广泛使用,如 MySQL 的 InnoDB 存储引擎。
MVCC 的核心思想是为数据库中的每一行数据维护多个版本,使得不同的事务可以访问同一数据的不同版本,从而实现并发访问时的数据一致性与隔离性,同时避免了大量的锁操作,提高了系统的并发性能。
MVCC 的实现主要包括以下几个关键要素:
1. 事务版本号(Transaction ID)
- 每个事务在开始时都会被分配一个全局唯一的事务ID(Transaction ID),用于标识事务的执行顺序。事务ID通常是递增的,新启动的事务ID大于已提交事务的ID。
2. 数据行的隐藏列
- InnoDB 为每个数据行添加了两个隐藏列:
trx_id
和roll_pointer
(或称为undo_no
)。trx_id
存储了最后修改该行的事务ID。roll_pointer
指向该行在 undo 日志(回滚日志)中的位置,用于回溯到该行的前一个版本。
3. undo 日志(Undo Logs)
- undo 日志记录了对数据行的修改历史,包括修改前的值和修改操作类型(如 INSERT、UPDATE、DELETE)。当事务回滚时,可以通过 undo 日志恢复数据到之前的版本。
- undo 日志按照事务ID的顺序进行组织,每个事务都有自己的 undo 日志段,用于存储该事务执行过程中产生的所有 undo 记录。
4. 快照读与当前读
- 快照读(Snapshot Read):在可重复读(Repeatable Read)隔离级别下,事务执行普通的 SELECT 查询时,看到的是事务开始时的数据快照。InnoDB 通过比较事务ID和数据行的
trx_id
,只返回事务开始前已提交的行版本。对于未提交的事务修改或事务开始后才提交的修改,快照读事务均不可见。 - 当前读(Current Read):当使用
SELECT ... FOR UPDATE
、SELECT ... LOCK IN SHARE MODE
或执行数据修改(INSERT、UPDATE、DELETE)操作时,会进行当前读。当前读直接查看并锁定当前最新的数据行版本,不受事务开始时快照的影响。
5. Read View(读视图)
- 读视图是事务进行快照读时创建的一个数据视图,记录了事务开始时系统中活跃的事务ID范围。读视图用于确定事务在快照读时能看到哪些数据版本。
- low_limit_id:小于该值的事务ID都是在当前事务开始前已经提交的。
- up_limit_id:大于该值的事务ID都是在当前事务开始后才开启的,其修改对当前事务不可见。
- creator_trx_id:当前事务的ID。
- trx_ids:一个集合,存储了在当前事务开始时还未提交但之后可能提交的事务ID。
MVCC 的工作流程大致如下:
- 当事务开始时,InnoDB 创建一个读视图。
- 当事务进行快照读时,根据读视图判断数据行的可见性:
- 如果数据行的
trx_id
小于low_limit_id
,说明该行在事务开始前已经提交,且未被其他未提交事务修改,因此对该事务可见。 - 如果数据行的
trx_id
大于等于creator_trx_id
,说明该行是当前事务自身或在其之后开始的事务修改的,对该事务不可见。 - 如果数据行的
trx_id
在low_limit_id
和creator_trx_id
之间,需要检查trx_ids
集合。如果在集合中,说明该行被其他未提交事务修改,对该事务不可见;否则,该行可见。
- 如果数据行的
- 若数据行不可见,InnoDB 会通过
roll_pointer
回溯到 undo 日志中找到对该事务可见的前一个版本。
通过以上机制,MVCC 实现了在不使用(或极少使用)锁的情况下,为每个事务提供一致性的数据视图,有效避免了事务间的读写阻塞,提高了并发性能。同时,MVCC 与 InnoDB 的行锁、间隙锁等其他并发控制机制相结合,确保了事务的隔离性和数据的一致性。