InnoDB 锁体系详细讲解

InnoDB 锁体系详细讲解
InnoDB Locks
InnoDB 锁体系详细讲解
1 / 1

InnoDB 锁可以理解为:数据库为了在多人同时读写时,既保证数据正确,又尽量提高并发性能而设计的一套交通规则。


1. 为什么数据库需要锁?

假设有一张账户表:

accounts
+----+--------+
| id | money  |
+----+--------+
| 1  | 1000   |
+----+--------+

现在两个事务同时执行:

事务 A:

UPDATE accounts SET money = money - 100 WHERE id = 1;

事务 B:

UPDATE accounts SET money = money - 200 WHERE id = 1;

如果数据库不加控制,两个事务可能同时读到 money = 1000,然后分别写回:

  • A 写成 900
  • B 写成 800

最终可能只剩 800,看起来好像 A 的扣款丢了。

这类问题叫做 并发问题

数据库用锁来避免这些问题。


2. 事务是什么?

理解 InnoDB 锁之前,先要知道事务。

事务是一组 SQL 操作,要么全部成功,要么全部失败。

START TRANSACTION;

UPDATE accounts SET money = money - 100 WHERE id = 1;
UPDATE accounts SET money = money + 100 WHERE id = 2;

COMMIT;

这表示转账:

  • 账户 1 扣 100
  • 账户 2 加 100

如果中间出错,就应该全部撤销。

事务有四个经典特性:ACID。

特性 含义
A Atomicity 原子性 要么全做,要么全不做
C Consistency 一致性 数据从一个正确状态变到另一个正确状态
I Isolation 隔离性 多个事务之间互不干扰到一定程度
D Durability 持久性 提交后数据永久保存

锁主要服务于 隔离性一致性


3. InnoDB 是什么?

MySQL 有不同的存储引擎,比如:

  • InnoDB
  • MyISAM
  • Memory

现在最常用的是 InnoDB

InnoDB 支持:

  • 事务
  • 行级锁
  • 外键
  • 崩溃恢复
  • MVCC

所以我们讲 MySQL 锁,大多数时候其实是在讲 InnoDB 的锁


4. InnoDB 锁体系的大图

InnoDB 的锁可以从几个角度理解:

InnoDB 锁体系
├── 按锁粒度
│   ├── 表锁
│   └── 行锁
│
├── 按锁模式
│   ├── 共享锁 S Lock
│   └── 排他锁 X Lock
│
├── 按行锁算法
│   ├── Record Lock 记录锁
│   ├── Gap Lock 间隙锁
│   └── Next-Key Lock 临键锁
│
├── 意向锁
│   ├── IS 意向共享锁
│   └── IX 意向排他锁
│
├── 特殊锁
│   ├── 插入意向锁
│   ├── 自增锁
│   └── 元数据锁 MDL
│
└── MVCC
    ├── 快照读
    └── 当前读

这张图先不用全部记住。我们逐个拆。


一、共享锁和排他锁

5. 共享锁:S Lock

共享锁又叫 读锁

含义是:我正在读这条数据,别人也可以读,但别人不能改。

比如:

SELECT * FROM accounts WHERE id = 1 LOCK IN SHARE MODE;

MySQL 8.0 也可以写:

SELECT * FROM accounts WHERE id = 1 FOR SHARE;

这个语句会给读取到的记录加共享锁。

共享锁之间是兼容的。

也就是说:

操作 是否可以同时进行
事务 A 读,事务 B 读 可以
事务 A 读,事务 B 改 不可以

6. 排他锁:X Lock

排他锁又叫 写锁

含义是:我正在修改这条数据,别人不能读锁定读,也不能改。

常见的语句会加排他锁:

UPDATE accounts SET money = money - 100 WHERE id = 1;
DELETE FROM accounts WHERE id = 1;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;

排他锁很霸道。

当前锁 其他事务加共享锁 其他事务加排他锁
共享锁 S 可以 不可以
排他锁 X 不可以 不可以

简单记:

  • S 锁:大家可以一起读
  • X 锁:我要写,别人别碰

二、表锁和行锁

7. 表锁

表锁就是锁住整张表。

例如:

LOCK TABLES accounts WRITE;

表锁粒度大,影响范围广。

如果一张表被写锁锁住,其他事务基本没法正常写这张表。

优点:

  • 管理简单
  • 开销小

缺点:

  • 并发性能差

8. 行锁

行锁就是只锁某几行。

比如:

UPDATE accounts SET money = money - 100 WHERE id = 1;

如果 id 是索引,InnoDB 通常只锁 id = 1 这一行。

优点:

  • 并发性能高
  • 不同行之间可以同时修改

缺点:

  • 管理复杂
  • 可能死锁
  • 如果没用好索引,可能锁很多行

InnoDB 的核心优势之一就是:支持行级锁


三、InnoDB 行锁不是锁“行”,而是锁“索引”

这是非常重要的一点。

很多初学者会以为:

UPDATE users SET name = 'A' WHERE id = 10;

就是锁住表里 id = 10 的那一行。

更准确地说:

InnoDB 的行锁是加在索引记录上的。

也就是说,如果你的查询条件命中了索引,InnoDB 可以精确锁住相关索引记录。

如果没有索引,InnoDB 可能扫描很多记录,锁的范围就会扩大。

例如有表:

CREATE TABLE users (
  id INT PRIMARY KEY,
  name VARCHAR(50),
  age INT
);

id 是主键索引。

执行:

UPDATE users SET name = 'Tom' WHERE id = 1;

这通常只锁主键索引上 id = 1 的记录。

但如果 age 没有索引:

UPDATE users SET name = 'Tom' WHERE age = 18;

InnoDB 需要扫描很多行来判断谁的 age = 18,锁的范围可能大得多。

所以一个非常实用的结论是:

想减少锁冲突,首先要让 SQL 正确使用索引。


四、Record Lock:记录锁

9. 什么是记录锁?

Record Lock 就是锁住一条索引记录。

比如表里有:

id: 1, 5, 10

执行:

SELECT * FROM users WHERE id = 5 FOR UPDATE;

如果 id = 5 存在,InnoDB 会给 id = 5 这条索引记录加排他锁。

此时另一个事务执行:

UPDATE users SET name = 'Jerry' WHERE id = 5;

会被阻塞。

但是它可以更新其他行:

UPDATE users SET name = 'Jerry' WHERE id = 10;

一般不会受影响。


五、Gap Lock:间隙锁

10. 什么是间隙?

假设索引里有这些值:

1, 5, 10

那么索引之间有几个“空隙”:

(-∞, 1)
(1, 5)
(5, 10)
(10, +∞)

这些空隙就叫 gap,也就是间隙。

Gap Lock 就是锁住某个范围的“空隙”,防止其他事务往这个范围里插入新数据。


11. 为什么需要间隙锁?

为了防止 幻读

幻读是这样的:

事务 A:

START TRANSACTION;

SELECT * FROM users WHERE age BETWEEN 10 AND 20;

查到 3 条记录。

这时候事务 B 插入一条:

INSERT INTO users(id, age) VALUES(100, 15);
COMMIT;

事务 A 再查一次:

SELECT * FROM users WHERE age BETWEEN 10 AND 20;

发现变成了 4 条。

好像多出来一条“幻影记录”,这就叫幻读。

为了避免这种情况,InnoDB 在某些隔离级别下会使用 Gap Lock,锁住范围,阻止别人插入满足条件的新记录。


12. 间隙锁的特点

Gap Lock 锁的是“空隙”,不是已有记录。

比如索引值:

1, 5, 10

如果锁住 (5, 10) 这个间隙,那么其他事务不能插入:

INSERT INTO users(id) VALUES(6);
INSERT INTO users(id) VALUES(7);
INSERT INTO users(id) VALUES(9);

但是不一定影响已有的 510 记录本身。

间隙锁之间通常不互斥。

也就是说,两个事务可以同时持有同一个间隙的 Gap Lock。

这听起来有点奇怪,但它的主要目的不是保护已有数据,而是防止插入。


六、Next-Key Lock:临键锁

13. 什么是 Next-Key Lock?

Next-Key Lock = Record Lock + Gap Lock。

它锁住:

一个索引记录 + 它前面的间隙

例如索引值:

1, 5, 10

Next-Key Lock 可能锁:

(-∞, 1]
(1, 5]
(5, 10]
(10, +∞)

注意括号:

  • ( 表示不包含
  • ] 表示包含

所以 (1, 5] 表示:

  • 锁住 15 之间的间隙
  • 也锁住 5 这条记录

14. 为什么 Next-Key Lock 很重要?

InnoDB 在默认隔离级别 REPEATABLE READ 下,为了解决幻读,常常使用 Next-Key Lock。

例如:

SELECT * FROM users WHERE id BETWEEN 5 AND 10 FOR UPDATE;

它不仅要锁住已有的 id = 5id = 10 等记录,还要锁住范围内的间隙,防止别人插入新的 id = 6id = 7

这样事务里再次查询时,就不会突然多出新记录。


七、隔离级别和锁的关系

MySQL 事务隔离级别有四种:

隔离级别 脏读 不可重复读 幻读
READ UNCOMMITTED 可能 可能 可能
READ COMMITTED 不可能 可能 可能
REPEATABLE READ 不可能 不可能 InnoDB 通常能避免
SERIALIZABLE 不可能 不可能 不可能

MySQL InnoDB 默认是:

REPEATABLE READ

可以查看:

SELECT @@transaction_isolation;

15. 脏读是什么?

事务 A 修改了数据但还没提交:

UPDATE accounts SET money = 0 WHERE id = 1;

事务 B 读到了 money = 0

后来事务 A 回滚了。

那事务 B 读到的就是从来没有真正生效的数据。

这叫脏读。


16. 不可重复读是什么?

事务 A 第一次读:

SELECT money FROM accounts WHERE id = 1;

读到 1000

事务 B 修改并提交:

UPDATE accounts SET money = 900 WHERE id = 1;
COMMIT;

事务 A 第二次读同一行,读到 900

同一个事务里,同一条记录前后读到不同结果,这叫不可重复读。


17. 幻读是什么?

事务 A 第一次查范围:

SELECT * FROM users WHERE age >= 18;

有 10 条。

事务 B 插入一条 age = 20 的记录并提交。

事务 A 第二次查:

SELECT * FROM users WHERE age >= 18;

有 11 条。

同一个事务里,同一个范围前后查到的“行数”变了,这叫幻读。


八、MVCC:为什么普通 SELECT 不加锁也能安全读?

18. MVCC 是什么?

MVCC 全称是:

Multi-Version Concurrency Control
多版本并发控制

它的核心思想:

数据库给数据保存多个版本,读操作可以读某个历史版本,不一定要等写操作完成。

这就像文档有版本历史:

  • 你正在看昨天的版本
  • 别人正在编辑今天的版本
  • 你们不一定互相阻塞

InnoDB 的普通 SELECT 通常是 快照读,不加行锁。

例如:

SELECT * FROM users WHERE id = 1;

REPEATABLE READ 下,事务第一次普通查询时会生成一个一致性视图,后续普通查询继续看这个视图。

所以即使别人提交了修改,你在当前事务里普通查询看到的结果也可能不变。


19. 快照读和当前读

InnoDB 里读分两类。

快照读

普通 SELECT

SELECT * FROM users WHERE id = 1;

特点:

  • 不加锁
  • 读历史版本
  • 依赖 MVCC
  • 并发性能高

当前读

这些语句读取最新数据,并且会加锁:

SELECT * FROM users WHERE id = 1 FOR UPDATE;
SELECT * FROM users WHERE id = 1 FOR SHARE;
UPDATE users SET name = 'Tom' WHERE id = 1;
DELETE FROM users WHERE id = 1;
INSERT INTO users VALUES (...);

特点:

  • 读最新版本
  • 会加锁
  • 可能阻塞别人
  • 也可能被别人阻塞

简单记:

类型 示例 是否加锁 读什么
快照读 普通 SELECT 通常不加锁 历史一致版本
当前读 SELECT FOR UPDATE / UPDATE / DELETE 加锁 最新数据

九、意向锁

20. 意向锁是什么?

意向锁是表级锁,但它不是为了真正锁整张表,而是为了告诉别人:

我接下来要在这张表里的某些行上加锁。

有两种:

含义
IS Intention Shared Lock,意向共享锁
IX Intention Exclusive Lock,意向排他锁

比如:

SELECT * FROM users WHERE id = 1 FOR SHARE;

会先在表上加 IS 锁,然后在行上加 S 锁。

UPDATE users SET name = 'Tom' WHERE id = 1;

会先在表上加 IX 锁,然后在行上加 X 锁。


21. 为什么需要意向锁?

假设事务 A 已经锁了表里的某一行:

UPDATE users SET name = 'Tom' WHERE id = 1;

现在事务 B 想锁整张表:

LOCK TABLES users WRITE;

数据库需要判断:

这张表里有没有某些行已经被别人锁住?

如果没有意向锁,它可能要扫描整张表的每一行,看有没有行锁,成本很高。

有了意向锁以后就简单了:

  • A 在表上有 IX 锁
  • B 想加表级写锁
  • 一看 IX 和表级写锁冲突,就知道不能加

所以意向锁是一个“提示牌”。

它提高的是锁冲突判断效率。


十、插入意向锁

22. 插入意向锁是什么?

插入意向锁是 Insert Intention Lock。

当事务要往某个间隙里插入数据时,会先加插入意向锁。

例如索引里有:

1, 10

事务 A 插入 5

INSERT INTO users(id) VALUES(5);

事务 B 插入 6

INSERT INTO users(id) VALUES(6);

它们都在 (1, 10) 这个间隙里。

如果没有其他锁阻止,它们通常可以并发插入,因为插入的位置不同。

插入意向锁的作用是:

表示我打算在这个 gap 里插入一条记录。

它和普通 Gap Lock 的关系比较关键:

  • 多个插入意向锁之间通常不冲突
  • 插入意向锁会被已有的 Gap Lock / Next-Key Lock 阻塞

十一、自增锁

23. 自增锁是什么?

如果表有自增主键:

CREATE TABLE orders (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(50)
);

执行:

INSERT INTO orders(name) VALUES('A');

MySQL 会自动生成 id。

为了保证自增值分配正确,InnoDB 有自增锁机制。

早期自增锁粒度比较粗,后来 MySQL 做了优化。

可以通过参数查看:

SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';

常见值:

名称 含义
0 traditional 传统模式,锁比较强
1 consecutive 连续模式,默认常见
2 interleaved 交错模式,并发更高,但复制场景要注意

你零基础阶段不必深究,只要知道:

自增列插入时,InnoDB 需要机制保证生成的自增 id 不乱。


十二、MDL 元数据锁

24. MDL 是什么?

MDL 全称:

Metadata Lock
元数据锁

它不是 InnoDB 独有,而是 MySQL Server 层的锁。

它保护的是表结构元数据。

比如:

  • 表名
  • 字段
  • 索引
  • 表结构

当你执行:

SELECT * FROM users;

MySQL 会加 MDL 读锁。

意思是:

我正在读这张表,别人不要突然把表结构改了。

当你执行:

ALTER TABLE users ADD COLUMN email VARCHAR(100);

MySQL 会加 MDL 写锁。

意思是:

我要改表结构,别人先别用这张表。


25. MDL 常见问题

一个很经典的问题:

事务 A:

START TRANSACTION;
SELECT * FROM users WHERE id = 1;
-- 不提交

事务 B:

ALTER TABLE users ADD COLUMN age INT;

事务 B 可能被阻塞。

因为事务 A 还持有 MDL 读锁。

更麻烦的是,后续其他对 users 的查询也可能排队,被卡住。

所以线上执行 DDL,例如 ALTER TABLE,需要特别小心。


十三、不同 SQL 会加什么锁?

下面是常见情况。

26. 普通 SELECT

SELECT * FROM users WHERE id = 1;

通常:

  • 快照读
  • 不加行锁
  • 使用 MVCC

27. SELECT FOR UPDATE

SELECT * FROM users WHERE id = 1 FOR UPDATE;

通常:

  • 当前读
  • 加排他锁 X
  • 其他事务不能修改这些记录
  • 常用于“查出来后马上要改”的场景

例如抢库存:

START TRANSACTION;

SELECT stock FROM products WHERE id = 1 FOR UPDATE;

UPDATE products SET stock = stock - 1 WHERE id = 1;

COMMIT;

28. SELECT FOR SHARE

SELECT * FROM users WHERE id = 1 FOR SHARE;

通常:

  • 当前读
  • 加共享锁 S
  • 其他事务可以读
  • 其他事务不能改

29. UPDATE

UPDATE users SET name = 'Tom' WHERE id = 1;

通常:

  • 当前读
  • 加排他锁 X
  • 修改完成后锁不一定立刻释放,要等事务提交或回滚

30. DELETE

DELETE FROM users WHERE id = 1;

通常:

  • 当前读
  • 加排他锁 X

31. INSERT

INSERT INTO users(id, name) VALUES(1, 'Tom');

通常:

  • 会加插入意向锁
  • 会对插入的记录加排他锁
  • 如果遇到唯一键冲突,还会涉及唯一索引检查相关锁

十四、锁什么时候释放?

这个很重要。

在 InnoDB 事务里,大部分行锁会持有到事务结束。

也就是:

COMMIT;

或者:

ROLLBACK;

才释放。

例如:

事务 A:

START TRANSACTION;

UPDATE users SET name = 'Tom' WHERE id = 1;

-- 此时不提交

事务 B:

UPDATE users SET name = 'Jerry' WHERE id = 1;

事务 B 会等待。

直到事务 A:

COMMIT;

或者:

ROLLBACK;

事务 B 才能继续。

所以,实际开发里要记住:

事务一定要尽快提交,不要开着事务做慢操作。

比如不要这样:

START TRANSACTION;

UPDATE orders SET status = 'paid' WHERE id = 1;

-- 这里调用第三方支付接口,等了 10 秒

COMMIT;

这会导致锁持有时间很长。

更好的方式通常是:把外部慢操作放在事务外,事务里只做数据库必须保证一致性的短操作。


十五、死锁

32. 什么是死锁?

死锁就是两个事务互相等对方释放锁,谁也走不下去。

例如:

事务 A:

START TRANSACTION;
UPDATE accounts SET money = money - 100 WHERE id = 1;

事务 B:

START TRANSACTION;
UPDATE accounts SET money = money - 200 WHERE id = 2;

然后事务 A 继续:

UPDATE accounts SET money = money + 100 WHERE id = 2;

A 等 B 释放 id = 2

事务 B 继续:

UPDATE accounts SET money = money + 200 WHERE id = 1;

B 等 A 释放 id = 1

于是:

A 锁着 1,等 2
B 锁着 2,等 1

这就是死锁。


33. InnoDB 如何处理死锁?

InnoDB 会检测死锁。

一旦发现死锁,它会选择一个事务回滚,让另一个事务继续。

被回滚的事务会报错,常见错误:

Deadlock found when trying to get lock; try restarting transaction

应用程序应该捕获这个错误,并在合适场景下重试事务。


34. 如何减少死锁?

常见经验:

  1. 多个事务访问多行数据时,保持固定顺序。

比如转账时,总是先锁较小的账户 id,再锁较大的账户 id。

-- 先锁 id 小的
SELECT * FROM accounts WHERE id IN (1, 2) ORDER BY id FOR UPDATE;
  1. 事务尽量短。

不要在事务中做网络请求、文件处理、复杂计算。

  1. 给查询条件建合适索引。

避免锁范围扩大。

  1. 避免一次事务更新太多数据。

大批量更新可以分批做。

  1. 捕获死锁错误并重试。

死锁在高并发系统里不一定能完全避免,重点是降低概率并能恢复。


十六、锁等待和锁超时

35. 锁等待是什么?

事务 B 想更新一行,但事务 A 已经锁住了这行。

事务 B 就会等待。

如果等太久,会超时。

常见错误:

Lock wait timeout exceeded; try restarting transaction

相关参数:

SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';

默认通常是 50 秒。


36. 死锁和锁等待超时的区别

项目 死锁 锁等待超时
原因 两个或多个事务循环等待 一个事务等另一个事务太久
数据库处理 主动检测并回滚一个事务 等到超时时间后报错
典型错误 Deadlock found Lock wait timeout exceeded
是否一定有环 不一定

十七、索引对锁范围的影响

这是 InnoDB 锁里最实用、也最容易踩坑的部分。

假设表:

CREATE TABLE users (
  id INT PRIMARY KEY,
  age INT,
  name VARCHAR(50),
  INDEX idx_age(age)
);

数据:

id: 1, age: 10
id: 2, age: 20
id: 3, age: 30

37. 主键等值查询

SELECT * FROM users WHERE id = 2 FOR UPDATE;

如果 id = 2 存在,通常只锁这一条主键记录。

锁范围很小。


38. 唯一索引等值查询

如果有:

email VARCHAR(100) UNIQUE

执行:

SELECT * FROM users WHERE email = 'a@test.com' FOR UPDATE;

如果记录存在,通常锁唯一索引上的这一条记录,以及对应主键记录。

因为唯一索引可以确定只有一条。


39. 普通索引等值查询

SELECT * FROM users WHERE age = 20 FOR UPDATE;

age 不是唯一索引。

可能有很多人 age = 20。

InnoDB 不只要锁 age = 20 的记录,还可能锁相关间隙,防止新的 age = 20 插入。


40. 范围查询

SELECT * FROM users WHERE age BETWEEN 10 AND 30 FOR UPDATE;

范围查询更容易触发 Next-Key Lock。

它会锁住范围里的记录和间隙。

所以范围条件在高并发下更容易造成锁等待。


41. 没有索引的查询

UPDATE users SET name = 'Tom' WHERE name = 'Alice';

如果 name 没有索引,InnoDB 可能扫描大量记录。

实际锁住的行可能远超你的预期。

这就是为什么线上慢 SQL 和锁问题经常同时出现。

一句话:

SQL 越精准命中索引,锁越精准;SQL 越模糊,锁越容易扩大。


十八、一个完整例子:抢库存

假设商品表:

CREATE TABLE products (
  id INT PRIMARY KEY,
  stock INT NOT NULL
);

数据:

INSERT INTO products(id, stock) VALUES(1, 10);

错误写法:

SELECT stock FROM products WHERE id = 1;

-- 应用判断 stock > 0

UPDATE products SET stock = stock - 1 WHERE id = 1;

问题是高并发下,很多人可能同时读到 stock = 10,然后都去扣。

更好的写法之一:

START TRANSACTION;

SELECT stock FROM products WHERE id = 1 FOR UPDATE;

-- 应用判断 stock > 0

UPDATE products SET stock = stock - 1 WHERE id = 1;

COMMIT;

这样 FOR UPDATE 会锁住商品记录。

同一时间只有一个事务能检查并扣减。

更简洁的写法是原子更新:

UPDATE products
SET stock = stock - 1
WHERE id = 1 AND stock > 0;

然后看影响行数:

  • 影响 1 行:扣库存成功
  • 影响 0 行:库存不足

这个通常更好,因为事务更短,锁持有时间更少。


十九、如何查看锁问题?

MySQL 8.0 可以看这些表。

42. 查看当前事务

SELECT * FROM information_schema.innodb_trx;

43. 查看锁

SELECT * FROM performance_schema.data_locks;

44. 查看锁等待

SELECT * FROM performance_schema.data_lock_waits;

45. 查看最近一次死锁

SHOW ENGINE INNODB STATUS\G

里面有一段:

LATEST DETECTED DEADLOCK

可以看死锁详情。


二十、最核心的记忆版

如果你是零基础,先记这几条就够用了。

46. 第一层:读写锁

共享锁 S:别人可以一起读,但不能写
排他锁 X:别人不能读锁定读,也不能写

47. 第二层:InnoDB 锁索引

InnoDB 行锁锁的是索引记录。
没有合适索引,锁范围可能变大。

这条非常关键。


48. 第三层:三种行锁算法

Record Lock:锁已有索引记录
Gap Lock:锁记录之间的空隙,防止插入
Next-Key Lock:Record Lock + Gap Lock

49. 第四层:普通 SELECT 通常不加锁

普通 SELECT:快照读,靠 MVCC
SELECT ... FOR UPDATE:当前读,加排他锁
UPDATE / DELETE:当前读,加排他锁

50. 第五层:锁一般事务结束才释放

COMMIT 或 ROLLBACK 后释放锁。
事务越长,锁持有越久,冲突越多。

二十一、最后用一句话串起来

InnoDB 的锁体系可以这样理解:

InnoDB 通过 MVCC 让普通读尽量不加锁,通过行级锁保护正在修改的数据,通过 Record Lock、Gap Lock、Next-Key Lock 控制记录和范围,通过意向锁协调表锁和行锁,最终在事务隔离性和并发性能之间取得平衡。

如果只用一个生活类比:
MVCC 像是给读者看历史版本,行锁像是编辑某一段时贴上的“正在修改”标记,间隙锁像是在一段范围内拉了警戒线,防止别人突然插入新内容。

Read more

Linux 运维文件写入操作

Linux 运维文件写入操作

面向 Linux 运维/SRE 的文件写入操作参考手册。既讲每条命令怎么用,也讲它背后的机制(为什么这么行为),配真实输出示例与边界情况,最后给出常见陷阱速查表与标准动作模板。 目录 1. 总览:运维"写文件"的全景 2. Shell 重定向:机制与基础符号 3. 重定向顺序的坑:为什么 2>&1 > f 不行 4. 文件描述符与 exec:持久打开、交换、关闭 5. 防止误覆盖:noclobber 与 >| 6. Here 文档与 Here 字符串 7. tee:

By Admin
Linux 定时任务(附学习指南)

Linux 定时任务(附学习指南)

Linux 系统的定时任务(Scheduled Tasks)是运维和开发中最常用的自动化手段之一。系统中最核心的两套定时任务工具是 cron(定时器) 和 at(一次性任务队列)。下面从原理到实战逐层展开。 一、cron:周期性定时任务 1. cron 是什么 cron 是一个守护进程(daemon),负责在约定的时间点自动执行用户定义的任务。它对应的服务名在大多数发行版中是 crond,相关的命令和文件包括: 命令/文件 作用 crond cron 守护进程 crontab 用户管理自己的定时任务 /etc/crontab 系统级定时任务(注意有用户字段,格式不同) /etc/cron.d/ 系统级定时任务的扩展目录(每个文件类似 /etc/crontab) /etc/cron.hourly/、daily/、weekly/

By Admin
自定义你的DSH

自定义你的DSH

DSH 界面主题定制插件 给 DSH 换一套界面主题 把设计 Token 变成所见即所得的「DIY 主题」设置面板。配色、字体、背景、阴影、圆角,改完立即生效,不用写一行代码。 GitHub 仓库 更多内容 DeepSeek Harness(DSH)是 DeepSeek 推出的 AI 编程助手框架。通过 dsh web 启动浏览器界面,就能和 AI 对话、读写文件、执行命令、规划任务。功能强大,但外观一直比较朴素,默认只有浅色、深色、跟随系统三档。 我写了一个插件 dsh-ui-customizer,把界面定制做成了所见即所得的「主题设置面板」:进入 设置

By Admin