【数据库中的锁机制】

数据库的锁介绍

按粒度分类:

  1. 表锁
    表锁是数据库中最基础的一种锁,作用范围是整张表。当事务对一张表加上表锁后,其他事务对该表的访问(读或写)将受到限制,直到锁释放。innodb和myisam数据库引擎都支持表锁。
  2. 行锁
    行锁是指数据库在执行写操作或带锁读操作时,只锁定被操作的行,不会锁住整张表,是一种细粒度锁。innodb支持行锁
  3. 页锁
    页锁(Page Lock) 是一种中等粒度的锁机制,它介于 行锁 和 表锁 之间,锁定的是数据页(即一组行记录的集合)。每页通常包含多行数据(如一个数据块 4KB 或 8KB)。页锁并不锁单独的行或整张表,而是锁整个数据页。

按读写分类:

  1. 共享锁:允许多个事务同时读取,但不能修改
  2. 排他锁:只能有一个事务拥有,同时禁止其他读写

InnoDB 特有的锁:

  1. 行锁(Record Lock) 锁定某一行记录(SELECT … FOR UPDATE)。
  2. 间隙锁(Gap Lock) 锁住两个记录之间的“空隙”,防止幻读。
  3. 临键锁(Next-Key Lock) 行锁 + 间隙锁,用于锁定当前行和前一个间隙(防止幻读)。
  4. 插入意向锁(Insert Intention Lock) 插入操作时加的表级锁,配合间隙锁使用,防止插入冲突。
  5. 意向锁(IS、IX) 表示事务打算加某种行锁(S或X),用于提高锁检测性能。

锁的行为场景

  1. MVCC 读共享:
    SELECT(普通查询)不具有锁,可在读已提交和可重复读的隔离级别下产生(MVCC 快照读) 快照读,不加锁,提高并发性能。
  2. LOCK IN SHARD MODE
    SELECT … LOCK IN SHARE MODE 加锁 行级共享锁(S 锁) + 意向共享锁(IS) 允许其他事务读,不允许写
  3. FOR UPDATE
    SELECT … FOR UPDATE 加锁 行级排他锁(X 锁) + 意向排他锁(IX) 当前读,禁止其他事务读写该行。
    4.排他锁
    UPDATE / DELETE 加锁 行级排他锁(X 锁) + 间隙锁(如有范围) 当前读 + 锁住目标数据及可能范围。
    INSERT 加锁 插入意图锁 + 间隙锁 防止多个事务同时插入到相同位置。
    REPLACE 加锁 删除旧记录(X 锁)+ 插入新记录(意图锁) 是 INSERT + DELETE 的复合操作。
    INSERT IGNORE 加锁 有主键/唯一约束 → 先加 S 锁查重 不存在则插入,存在则忽略
  4. 表锁
    ALTER / DROP / TRUNCATE 加锁,表级元数据锁(MDL 写锁) 阻塞其他所有读写。
    CREATE INDEX / ANALYZE TABLE 加锁 表级元数据锁(MDL 写锁) DDL 操作期间,阻塞所有 DML 查询。

事务隔离级别影响加锁行为

  1. READ UNCOMMITTED 读未提交,所有查询都不加锁,能看到其他事务尚未提交的修改(脏读),不会触发行锁、间隙锁、Next-Key Lock。
  2. READ COMMITTED 读已提交,当前读(SELECT FOR UPDATE / UPDATE / DELETE) 加 行锁(Record Lock),不加间隙锁 → 幻读可能发生,快照读(普通 SELECT)每次都读取最新版本。
  3. 当前读(SELECT FOR UPDATE / UPDATE / DELETE) 加 行锁(Record Lock),不加间隙锁 → 幻读可能发生,快照读(普通 SELECT)每次都读取最新版本。
  4. SERIALIZABLE(串行化),所有读取都加共享锁(S 锁),强制串行执行,所有事务都像排队一样执行,严格防止幻读,但并发性差。

案例

行锁案例

--创建表
CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(50)
) ENGINE=InnoDB;

BEGIN;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
-- 加上了 id=1 的行锁(排他锁)

BEGIN;
UPDATE users SET name = 'Tom' WHERE id = 1;
-- 阻塞:必须等待 A 提交

间隙锁 gap Lock

-- 如果数据为 [10, 20, 30]
SELECT * FROM users WHERE id BETWEEN 10 AND 20 FOR UPDATE;
--间隙锁的范围 gap(10, 20)
--行锁 row(20)

主键、唯一索引、普通索引对行锁的影响

  1. 使用主键、唯一索引精确查找 精确行锁。
  2. 范围查找(BETWEEN, LIKE, >) 行锁 + 间隙锁。
  3. 无索引(全表扫描),表锁。
  4. 普通索引或非唯一索引,行锁或多个行锁。

事务的隔离级别对锁的影响

主键等值更新: RC:行锁 RR:行锁
唯一索引等值更新:RC:行锁 RR:行锁
非唯一索引等值更新:RC:行锁 RR:临键锁
范围更新:RC:仅命中行加行锁 RR:临键锁+间隙锁
无索引更新:RC:全表行锁(逐行检查) RR:全表行锁+间隙锁
唯一性检查:RC:短暂S锁 RR:可能加间隙锁

RR隔离级别的情况下,插入数据都会涉及什么锁:

  1. 表级意向排他锁(IX Lock)
    事务开始时,先对表加 IX 锁(Intention Exclusive Lock)
    作用:表明"该事务打算修改表中的某些行"
    特点:不阻塞其他事务的读操作(如 SELECT … LOCK IN SHARE MODE)
  2. 唯一性检查锁(S Lock)
    检查主键/唯一键冲突时,对冲突行或间隙加锁:
    若存在冲突行 → 加 S 锁(共享锁) 在冲突行上
    若不存在冲突行 → 加 间隙锁(Gap Lock) 在目标间隙
    示例:
INSERT INTO users (id, name) VALUES (15, 'Alice');
-- 若 id=15 已存在:对 id=15 行加 S 锁
-- 若 id=15 不存在:在 (10,20) 间隙加 Gap Lock(假设 id=10 和 id=20 存在)
  1. 插入意向锁(Insert Intention Lock)
    在目标插入位置加 插入意向锁(特殊的间隙锁)
    作用:表明"事务准备在此间隙插入新记录"
    特点:
    允许多个事务在同一间隙的不同位置并发插入
    与已存在的 Gap Lock/Next-Key Lock 互斥(可能被阻塞)
  2. 行级排他锁(X Lock)
    插入成功后,对新插入的行加 X 锁(排他锁)
    锁持续到事务结束(确保事务内数据一致性)

RR隔离级别,不同场景下的锁行为

场景 1:无冲突插入

INSERT INTO orders (order_id, amount) VALUES (1001, 99.9);

加锁流程:

  1. 表级 IX 锁
  2. 检查 order_id=1001 无冲突 → 在目标间隙加 插入意向锁(如 order_id 在 (1000,1005) 之间)
  3. 插入成功后对新行 order_id=1001 加 X 锁

场景 2:唯一键冲突

-- 假设 order_id=1001 已存在
INSERT INTO orders (order_id, amount) VALUES (1001, 88.8);

加锁流程:

  1. 表级 IX 锁
  2. 发现 order_id=1001 存在 → 对冲突行加 S 锁
  3. 抛出 Duplicate entry 错误,事务回滚释放锁

场景 3:被间隙锁阻塞

-- 事务1(先执行)
SELECT * FROM orders WHERE order_id BETWEEN 1000 AND 1005 FOR UPDATE; 
-- 对 (1000,1005] 加临键锁(Next-Key Lock)
-- 事务2(后执行)
INSERT INTO orders (order_id, amount) VALUES (1002, 50.0); 

被事务1的临键锁阻塞(插入意向锁与临键锁互斥)

三、自增主键的特殊锁
若表有自增主键(AUTO_INCREMENT),还会加 自增锁(AUTO-INC Lock):

CREATE TABLE logs (
  id INT AUTO_INCREMENT PRIMARY KEY,
  content TEXT
);

INSERT INTO logs (content) VALUES ('log1'); -- 加自增锁

锁行为:

  1. 简单插入(值确定):加轻量级锁(申请自增值后立即释放)
  2. 批量插入(如 INSERT … SELECT):加表级自增锁直到语句结束

RC的隔离级别下,插入一条数据会添加什么锁?

  1. 表级意向排他锁(IX Lock)
    事务开始时对表加 IX 锁(Intention Exclusive Lock)
    作用:表明事务打算修改表中的某些行
    特点:不阻塞其他事务的读操作
  2. 唯一性检查锁(短暂 S 锁)
    检查主键/唯一键冲突时:
    若目标行存在 → 对冲突行加 S 锁(共享锁)
    若目标行不存在 → 不加间隙锁(与 RR 级别的关键区别)
    锁立即释放:检查完成后立即释放 S 锁(不等待事务结束)
  3. 插入意向锁(Insert Intention Lock)
    在目标插入位置加插入意向锁
    特点:
    允许多个事务在同一间隙并发插入
    仅与已存在的 Gap Lock 互斥(但在 RC 级别几乎没有 Gap Lock)
  4. 行级排他锁(X Lock)
    插入成功后,对新插入的行加 X 锁(排他锁)
    锁持续到事务结束(COMMIT/ROLLBACK 时释放)

RC和RR锁机制的区别:

间隙锁 (Gap Lock): RC: 几乎不使用 RR: 大量使用
唯一性检查未命中: RC: 不加锁 RR: 加间隙锁
插入意向锁冲突: RC: 只与现有 Gap Lock 互斥 RR: 与 Gap Lock/Next-Key Lock 互斥
幻读 (Phantom Read):RC:允许发生 RR:通过锁机制防止

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值