什么是InnoDB的锁机制?谈谈你对它的理解?或者说说它有哪些锁吧?
1 个回答
不能击败我的,会让我变得更强大。赵若冰InnoDB 存储引擎支持 **多种锁机制** 以提高并发性能,同时保证数据一致性。锁可以按照不同的维度进行分类。 ## **1. 按锁的级别分类** ### **1.1 共享锁(S 锁,Shared Lock)** - **又称读锁**,用于**查询操作**,允许多个事务同时读取数据,但**不允许修改**数据。 - 例如: ```sql SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE; ``` - **其他事务仍然可以加共享锁,但不能加排他锁(X 锁)**。 ### **1.2 排他锁(X 锁,Exclusive Lock)** - **又称写锁**,当一个事务对数据加 X 锁后,**其他事务不能对该数据加任何锁**。 - 例如: ```sql SELECT * FROM users WHERE id = 1 FOR UPDATE; ``` - **获得排他锁的事务可以读写数据**,但其他事务必须等待该事务提交或回滚后才能访问该数据。 ## **2. 按加锁方式分类** ### **2.1 自动锁** - 事务执行过程中,**InnoDB 自动加锁**,例如 `UPDATE`、`DELETE` 操作时自动加排他锁。 ### **2.2 显式锁** - 通过 **`LOCK IN SHARE MODE`**(共享锁) 或 **`FOR UPDATE`**(排他锁) 进行显式加锁。 ## **3. 按锁的粒度分类** ### **3.1 表级锁** - **影响整个表**,一般用于 `LOCK TABLES` 语句。 - **锁冲突较多,影响并发性能**。 ### **3.2 行级锁** - **锁住特定的行**,提高并发性能,避免不必要的锁冲突。 - **InnoDB 默认使用行级锁**,但如果**没有合适的索引,可能会升级为表锁**。 ## **4. 按作用方式分类** ### **4.1 乐观锁** - **不依赖数据库锁**,而是使用**版本号或时间戳机制**进行并发控制。 - 常见实现方式: ```sql UPDATE users SET balance = balance - 100, version = version + 1 WHERE id = 1 AND version = 5; ``` ### **4.2 悲观锁** - **依赖数据库锁**,保证并发安全,但降低了性能。 - 通过 `SELECT ... FOR UPDATE` 加排他锁实现: ```sql SELECT * FROM users WHERE id = 1 FOR UPDATE; ``` ## **5. 特殊类型的锁** ### **5.1 意向锁(Intention Lock)** - **表级锁**,用于表示事务**未来打算对某些行加锁**。 - **两种类型**: - **IS(Intention Shared)**:事务**希望获取共享锁**,表级意向锁不会阻塞其他共享锁。 - **IX(Intention Exclusive)**:事务**希望获取排他锁**,表示未来会对某些行加 X 锁。 **示例**: ```sql SELECT * FROM users WHERE id = 1 LOCK IN SHARE MODE; -- 申请 IS 锁 UPDATE users SET age = 30 WHERE id = 1; -- 申请 IX 锁 ``` ### **5.2 记录锁(Record Lock)** - 只**锁住索引记录**,防止其他事务修改该行。 - 例如: ```sql SELECT * FROM users WHERE id = 1 FOR UPDATE; ``` ### **5.3 间隙锁(Gap Lock)** - **锁住索引记录之间的间隙**,防止其他事务在间隙中插入新记录,避免幻读。 - **仅在 REPEATABLE READ(RR)级别及以上生效**。 - 例如: ```sql SELECT * FROM users WHERE age BETWEEN 10 AND 20 FOR UPDATE; ``` - 假设 `users` 表中 `age` 只有 15,**事务 A** 进行上述查询后,**事务 B** 无法插入 `age=12` 这样的数据。 ### **5.4 Next-Key Lock(临键锁)** - **记录锁 + 间隙锁** 结合,锁住当前索引记录 **及其前后的间隙**,避免幻读。 - **MySQL 默认使用 Next-Key Lock** 以避免某些幻读场景。 ### **5.5 插入意向锁(Insert Intention Lock)** - **当事务插入数据时,先获取插入意向锁**,多个事务可以同时获取相同间隙的插入意向锁。 - **仅当多个事务尝试插入相同索引位置时才会发生冲突**。 ### **5.6 AUTO-INC 锁** - **用于自增主键的并发控制**,确保每次 `INSERT` 操作的主键值是连续的。 - 由 `innodb_autoinc_lock_mode` 控制: - `0`(传统模式):串行执行 `INSERT` 语句,保证严格递增。 - `1`(默认模式):`INSERT ... SELECT` 使用表锁,普通 `INSERT` 使用轻量锁。 - `2`(并行模式):不使用表锁,允许高并发插入,但主键可能不连续。 ## **6. 典型加锁示例** ### **6.1 行锁示例** ```sql -- 事务 A START TRANSACTION; SELECT * FROM users WHERE id = 1 FOR UPDATE; ``` ```sql -- 事务 B START TRANSACTION; SELECT * FROM users WHERE id = 1 FOR UPDATE; -- 阻塞,等待事务 A 释放锁 ``` ### **6.2 间隙锁示例** ```sql -- 事务 A START TRANSACTION; SELECT * FROM users WHERE age BETWEEN 10 AND 20 FOR UPDATE; ``` ```sql -- 事务 B INSERT INTO users (age, name) VALUES (15, 'Alice'); -- 阻塞 ``` ### **6.3 插入意向锁示例** ```sql -- 事务 A START TRANSACTION; INSERT INTO users (age, name) VALUES (12, 'Alice'); -- 获取插入意向锁 ``` ```sql -- 事务 B START TRANSACTION; INSERT INTO users (age, name) VALUES (14, 'Bob'); -- 不会阻塞 ``` 由于 `12` 和 `14` 插入到不同位置,**事务 A 和 B 可以同时执行**。 ## **7. 锁冲突表** | 锁类型 | 兼容情况 | |-------------|---------| | **S 锁** vs S 锁 | ✅ 兼容 | | **S 锁** vs X 锁 | ❌ 冲突 | | **X 锁** vs X 锁 | ❌ 冲突 | | **IS 锁** vs IS 锁 | ✅ 兼容 | | **IS 锁** vs IX 锁 | ✅ 兼容 | | **IX 锁** vs IX 锁 | ✅ 兼容 | | **IS 锁** vs S 锁 | ✅ 兼容 | | **IX 锁** vs S 锁 | ❌ 冲突 | | **IX 锁** vs X 锁 | ❌ 冲突 | ## **8. 总结** - **InnoDB 提供多种锁机制** 以支持高并发和事务隔离。 - **S 锁(共享锁)适用于读取,X 锁(排他锁)适用于写入**。 - **MVCC 解决了快照读的幻读问题**,间隙锁和 Next-Key Lock 解决了当前读的幻读问题。 - **InnoDB 默认使用行锁**,但如果没有索引,可能会升级为表锁。 - **高并发场景下,应避免长事务和不必要的锁竞争**。发布于 2025-03-11 20:43 •IP属地 四川举报评论收藏
公众号进入网站体验更佳

