02-SQLite 为了防止多人同时乱写,把整个数据库文件“当一本账本加锁”
目录
1. 总体原则:多读单写
2. 锁是加在“整个数据库文件”上的
3. 四种主要锁:可以当成“读者证 / 写者预约 / 独占使用证”
1)SHARED(共享锁)——“看书证”
2)RESERVED(保留锁)——“我要写了,先打个招呼”
3)PENDING(待定锁)——“准备清场”
4)EXCLUSIVE(排他锁)——“整本账本我一个人用”
4. 写事务完整大致流程(简化版)
5. 面试考点:为什么 SQLite 不适合高并发写入?
1. 总体原则:多读单写
多个读可以同时读,但写的时候只能一个人写,而且写的时候别人不能读。
就像一本纸质账本:
-
很多人可以一起翻看(多读)
-
但如果有人要拿笔改账:
-
只能一个人写
-
写的时候,别人不能再同时看、也不能写
-
这就是 SQLite 在非 WAL 模式下的并发模型。
2. 锁是加在“整个数据库文件”上的
注意一个关键点:
SQLite 是对整个数据库文件加锁,
不是像 MySQL 那样对“行 / 页”加锁。
所以一旦需要写,影响的范围是整个库文件,而不是一小块。
3. 四种主要锁:可以当成“读者证 / 写者预约 / 独占使用证”
SQLite 里几种重要锁,你不用记内部细节,只要理解大概角色:
1)SHARED(共享锁)——“看书证”
-
读事务持有
-
多个连接可以同时拿 SHARED 锁
→ 所以可以 多读并发
流程:
无锁 → SHARED → 释放
2)RESERVED(保留锁)——“我要写了,先打个招呼”
-
写事务要修改前,先拿一个 RESERVED 锁
-
拿到 RESERVED 后:
-
允许别的连接继续用 SHARED 锁读(但不能再有新的写者)
-
保证:潜在写者只有一个
-
可以理解为:
“我接下来要写了,你们还可以再看一会儿,但别再有第二个人说要写。”
3)PENDING(待定锁)——“准备清场”
-
写事务准备升级为 EXCLUSIVE(真正独占写)时,先进入 PENDING 状态
-
这个状态下:
-
不再允许新的读者获取 SHARED 锁
-
等现有的读者看完、释放 SHARED 锁
-
可以理解为:
“书要收回来改内容了,先不借给新人看,
等正在看的人都还回来,再开始改。”
4)EXCLUSIVE(排他锁)——“整本账本我一个人用”
-
写事务真正写回数据库文件时持有
-
持有 EXCLUSIVE 时:
-
不允许其他连接读
-
也不允许其他连接写
-
流程:
无锁 → (可能先 SHARED 读) → RESERVED → PENDING → EXCLUSIVE → 释放
可以理解为:
“现在我一个人拿着账本写,别人都不能碰。”
4. 写事务完整大致流程(简化版)
一个写事务,大概是这样:
-
读当前数据 → 可能先拿
SHARED -
决定要写 → 升级到
RESERVED(预定写) -
准备提交修改 → 进入
PENDING(不让新人再进来读) -
等现有读者都结束 → 升级到
EXCLUSIVE -
把修改写回数据库文件
-
COMMIT/ROLLBACK→ 释放锁
而读事务就简单得多:
BEGIN 读 → 拿 SHARED 锁 → 读完 → 释放
5. 面试考点:为什么 SQLite 不适合高并发写入?
你可以这样回答:
SQLite 对的是整个数据库文件加锁,
在非 WAL 模式下,写入需要拿到EXCLUSIVE排他锁,
也就是说同一时刻只能有一个写者,且写的时候会阻塞其他读写。在大量并发写入的场景下,
很多连接会抢同一个写锁,导致频繁的锁竞争和database is locked错误,
所以 SQLite 不太适合高并发写入场景,更适合“多读、少写”的本地、小型应用。
你也可以再加一句(理解):
它是一个“单文件、嵌入式、小型数据库”,
设计目标不是支撑像 MySQL 那种大规模高并发写,而是简单稳。
