90%的业务存储过程应以read committed为起点;sql server中set transaction isolation level必须置于begin transaction之前,嵌套调用时内层需自行set,mysql默认repeatable read含间隙锁,read committed才真正只锁行。

直接说结论:90% 的业务存储过程,READ COMMITTED 是最稳妥的起点;硬上 SERIALIZABLE 或默认沿用 REPEATABLE READ(尤其在 MySQL)反而容易引发死锁、间隙锁阻塞和性能抖动。
SQL Server 存储过程中 SET TRANSACTION ISOLATION LEVEL 必须在 BEGIN TRANSACTION 之前
这是最容易翻车的第一步。很多同学写了 SET TRANSACTION ISOLATION LEVEL READ COMMITTED,但放在 BEGIN TRANSACTION 后面,或者夹在 SELECT 语句中间——此时语句执行成功,但隔离级别根本没生效。
- 正确顺序只能是:
SET TRANSACTION ISOLATION LEVEL ...→BEGIN TRANSACTION→ 业务 SQL - 嵌套调用时,内层存储过程不能依赖外层已设的级别;哪怕
@@TRANCOUNT > 0,也必须自己SET,否则可能继承到READ UNCOMMITTED - 注释掉的
-- SET TRANSACTION ISOLATION LEVEL ...不会起作用,生产环境没人帮你全局取消注释
MySQL 中 REPEATABLE READ 默认带间隙锁,READ COMMITTED 才真“只锁行”
MySQL 的 REPEATABLE READ(默认)不是靠纯 MVCC 实现的,它会在范围查询时自动加间隙锁(Gap Lock)。比如你写 SELECT * FROM orders WHERE status = 'pending' FOR UPDATE,InnoDB 可能锁住所有 status 值为 'pending' 的间隙,新订单插入直接被卡住。
- 电商下单类场景(查库存 → 扣减),用
READ COMMITTED就够了:避免脏读,不锁间隙,INSERT 并发不受影响 - 如果业务真需要两次
SELECT结果一致(如对账报表),才考虑REPEATABLE READ,但务必确认 WHERE 条件能走索引,否则可能升级为全表间隙锁 -
SELECT @@transaction_isolation和SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED必须在START TRANSACTION前执行,否则报错 “Can’t change transaction isolation level when a transaction is active”
别把 READ COMMITTED 当成“不加锁”,它照样会阻塞写操作
在 SQL Server 默认配置(READ_COMMITTED_SNAPSHOT = OFF)下,READ COMMITTED 的每条 SELECT 都会加共享锁(S 锁),直到该语句执行完才释放。一个长耗时的报表查询,可能让后续 UPDATE 卡住几十秒。
- 检查执行计划:出现
Table Scan或Index Scan就要警惕,优先优化为Index Seek - 避免在事务开头就
SELECT *一堆无关字段,锁持有时间直接拉长 - 如果读多写少且能接受快照一致性,可启用数据库级
ALTER DATABASE SET READ_COMMITTED_SNAPSHOT ON;注意:此时会话级SET会被忽略,实际走的是行版本快照
SERIALIZABLE 在绝大多数存储过程中不该出现
它不是“最安全”,而是“最慢且最难调”。SQL Server 的 SERIALIZABLE 不仅锁住查到的行,还会锁住“可能插入新行的间隙”,哪怕你只查 WHERE id = 123,也可能锁住 id BETWEEN 100 AND 150 的整个范围。
- 典型翻车点:订单状态更新存储过程用了
SERIALIZABLE,批量补单时 20 个线程全卡在INSERT上,死锁图里全是 “等待键锁” - MySQL 的
SERIALIZABLE更激进:所有普通SELECT隐式变成SELECT ... LOCK IN SHARE MODE,写操作基本排队执行 - 真正需要它的场景极少,比如金融核心系统中某笔跨账期冲正操作,且无法拆解为幂等步骤——这时应单独封装、限流、监控,而不是全局设为
SERIALIZABLE
最常被忽略的一点:隔离级别不是数据库参数,是业务契约的落地表达。选错的本质,是你还没想清楚“这笔数据,别人改了我能不能接受?”——这个问题的答案,永远比 SET TRANSACTION ISOLATION LEVEL 那一行代码更重要。











