表锁、行锁、共享锁和排他锁(读锁写锁)、意向锁、间隙锁

本文深入解析数据库中的锁机制,涵盖表锁与行锁的区别,共享锁与排他锁的功能,以及意向锁、间隙锁的作用。详细说明InnoDB如何实现行锁,以及不同SQL语句的加锁情况。

数据库中的锁

  • 如果按照锁的粒度来分的话,分为表锁和行锁;如果按照读写功能来分的话,分为读锁和写锁。

表锁

  • 特点: 即使操作一条记录也会锁住整个表,锁定粒度较大,发生锁冲突的概率高,并发度最低。但开销小,加锁快,而且不会出现死锁。
  • 表锁是mysql中开销最小的策略,它会锁定整张表,用户在对表进行写操作前,需要先获得写锁,这会阻塞其他用户对该表的所有读写操作。MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁。

行锁

  • 特点: 操作时只锁某些行,不对其它行有影响,锁粒度较小,发生锁冲突的概率低,并发度高。但开销大,加锁慢,而且会出现死锁。
  • 行锁可以最大程度的支持并发处理,同时也带来了最大的锁开销,InnoDB存储引擎实现了两种行锁:共享锁和排他锁。

InnoDB 的行锁是怎么实现的?

  • InnoDB 行锁是通过索引上的索引项来实现的。意味着:只有通过索引条件检索数据,InnoDB 才会使用行级锁,否则,InnoDB将使用表锁!

  • 对于主键索引:直接锁住主键索引即可。

  • 对于普通索引:先锁住普通索引,接着锁住主键索引,这是因为一张表的索引可能存在多个,通过主键索引才能确保锁是唯一的,不然如果同时有2个事务对同1条数据的不同索引分别加锁,那就可能存在2个事务同时操作一条数据了。

共享锁和排他锁

  • mysql的锁机制分为表级锁和行级锁,共享锁和排他锁都属于行级锁。
  • 共享锁又称为读锁,简称S锁,指多个事务对同一数据可以共享一把锁,他们都能访问到这个数据,但只能读不能改。
  • 排他锁又称为写锁,简称X锁,它不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,那其他事务就不能再获取该行的其他锁了,包括共享锁和排他锁。而获取了这个排他锁的事务可以对数据行进行读和写。
  • 常见的几种 SQL 语句的加锁情况如下:
    select * from table:不加锁
    update/insert/delete:排他锁
    select * from table where id = 1 for update:id为索引,加排他锁
    select * from table where id = 1 lock in share mode:id为索引,加共享锁

意向锁

  • 意向锁是一种表级锁,如果事务想要给表中几行数据加上行级共享锁,那么需要先在表级别加上意向共享锁(IS);如果事务想要给表中几行数据加上行级排他锁,那么需要先在表级别加上意向排他锁(IX)。
  • 目的/作用:当向一个表添加表级排他锁或表级共享锁时,如果没有意向锁的存在,则需要遍历整个表来判断是否存在不兼容的行锁,以免发生冲突。如果有了意向锁,只需要判断该意向锁与想添加的表级锁是否兼容即可,因为意向锁的存在代表了有行级锁的存在,所以无需遍历整个表就可以获取结果,减少了整个检查过程,将检查每一行的排他锁变成只检查一个意向锁。

间隙锁

  • 间隙锁指的是锁定一个范围内的索引记录,开区间,不包括双端端点,对于键值在条件范围内但不存在的记录,叫做间隙,间隙锁也会对这个间隙加锁。
  • 目的/作用:让其他事务无法在间隙中新增数据,从而防止了幻读。
  • 在可重复读的隔离级别下才能生效。
<think>嗯,用户这次的问题是关于MySQL机制中除了间隙锁之外的其他类型。结合之前的对话历史,用户已经对索引失效导致的升级问题有了深入理解,现在想进一步扩展知识边界。 从引用内容来看,用户提供的资料主要集中在间隙锁的机制上,特别是[^1][^2][^3]详细解释了间隙锁的作用危害。不过用户提到的“其他类型”需要我补充更完整的分类体系。 用户可能是位后端开发工程师或DBA,正在排查数据库并发问题。ta连续追问机制,说明遇到了性能瓶颈或死情况。考虑到MySQL体系的复杂性,我需要系统性地梳理所有类型,但避免过于理论化,要突出实用场景。 值得注意的是引用[^5]提到了“已提交”隔离级别,这暗示用户可能对与事务隔离级别的关联感兴趣。虽然用户没直接问,但后续相关问题可以引导这个方向。 在技术层面,除了常见的三种,还需要重点介绍: 1 意向锁这类的协同机制 2 临键这种特殊间隙锁 3 插入意向锁对并发插入的优化 4 自增对业务流水号的影响 对于每种,都要用一句话说明“为什么需要这种”,比如意向锁是为了快速判断是否被定,避免逐检查。用户作为实践者,最关心的是不同如何影响实际业务。 最后生成的问题要延续机制主线,但提升到架构层面,比如分库分后的变化,这既能解答当前疑问,也打开更深入的讨论空间。</think>MySQL 的机制非常复杂,除了常见的**间隙锁**外,还有多种其他类型,共同保障数据一致性并发控制。以下是完整的类型分类及说明: --- ### 一、核心类型分类 #### 1. **按作用范围划分** | 类型 | 作用范围 | 特点 | 典型场景 | |----------------|----------------|----------------------------------------------------------------------|------------------------------| | **** | 整张 | 开销小、加快;并发度低 | `ALTER TABLE`、全更新 | | **** | 单或多记录 | 开销大、加慢;并发度高 | `SELECT ... FOR UPDATE` | | **页级** | 数据页(16KB) | 介于之间(仅 BDB 引擎支持) | 已逐渐被淘汰 | #### 2. **按功能划分** | 类型 | 功能描述 | 触发条件 | |----------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------| | **共享锁 (S Lock)** | 允许并发,阻塞操作 | `SELECT ... LOCK IN SHARE MODE` | | **排他 (X Lock)** | 禁止其他事务 | `UPDATE`/`DELETE`/`SELECT ... FOR UPDATE` | | **意向共享锁 (IS)** | 明事务准备在**某些**上加共享锁) | 加级 S 前自动申请 | | **意向排他 (IX)** | 明事务准备在**某些**上加排他) | 加级 X 前自动申请 | | **自增 (AUTO-INC)**| 保障自增列的唯一性 | 插入含 `AUTO_INCREMENT` 列的 | --- ### 二、InnoDB 特有的高级机制 #### 1. **临键 (Next-Key Lock)** - **本质**: + 间隙锁的组合 - **作用范围**:定**本身及之前的间隙**(左开右闭区间) - **目的**:解决幻(RR 隔离级别默认启用) ```sql -- 示例:中存在 id=5,10,15 三条数据 SELECT * FROM t WHERE id > 8 FOR UPDATE; -- 定范围:(5,10] + (10,15] + (15,+∞] ``` #### 2. **插入意向锁 (Insert Intention Lock)** - **作用**:提高并发插入效率 - **特点**: - 多个事务在**同一间隙**插入不同数据时不会互斥 - 与间隙锁冲突(若间隙已被定,则插入阻塞)[^1] ```sql -- 事务A:先定一个间隙 SELECT * FROM t WHERE id BETWEEN 10 AND 20 FOR UPDATE; -- 获得间隙锁 (10,20) -- 事务B:尝试在间隙中插入(阻塞) INSERT INTO t (id) VALUES (15); -- 等待事务A释放间隙锁 ``` #### 3. **谓词 (Predicate Lock)** - **适用场景**:空间索引(GIS 数据) - **作用**:定满足空间查询条件的范围 - **实现**:通过 R-Tree 索引实现 --- ### 三、机制与隔离级别的关联 | 隔离级别 | 机制特点 | |-------------------|----------------------------------------------------------------------------| | **未提交 (RU)** | 不加取最新数据(可能脏) | | **已提交 (RC)** | 仅加,无间隙锁(可能幻) | | **可重复 (RR)** | 默认启用 Next-Key Lock(解决幻) | | **串(S)** | 所有 SELECT 自动转为 `SELECT ... LOCK IN SHARE MODE`,并发度最低 | > ⚠️ **关键差异**: > - **RC 模式**:在语句执后立即释放(即使事务未提交)[^5] > - **RR 模式**:间隙锁持续到事务结束 --- ### 四、冲突与死案例 #### 场景:并发插入导致死 ```sql -- 结构:id为主键,无其他索引 CREATE TABLE t (id INT PRIMARY KEY); -- 事务A INSERT INTO t (id) VALUES (1); -- 获得 id=1 的 -- 事务B INSERT INTO t (id) VALUES (2); -- 获得 id=2 的 -- 事务A INSERT INTO t (id) VALUES (2); -- 等待事务B释放 id=2 的 -- 事务B INSERT INTO t (id) VALUES (1); -- 等待事务A释放 id=1 的 → 死! ``` **原因**: 当插入冲突时(如唯一键冲突),事务会尝试获取目标的 S ,而其他事务持有该的 X 导致死[^4]。 --- ### 五、监控与优化建议 #### 1. **状态查询** ```sql -- 查看当前信息(MySQL 8.0+) SELECT * FROM performance_schema.data_locks; -- 查看等待关系 SELECT * FROM sys.innodb_lock_waits; ``` #### 2. **减少冲突** - **索引优化**:确保查询命中索引,避免升级为[^3] - **事务拆分**:大事务拆分为小事务,缩短持有时间 - **隔离级别选择**:非必要不使用 `SERIALIZABLE` > 💡 **最佳实践**: > 在 RR 隔离级别下,若业务能容忍幻,可通过设置 `SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;` 禁用间隙锁提升并发性能[^1]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值