本节摘要:事务和锁影响并发和数据一致。本节讲清楚隔离级别、锁参数、MVCC、死锁检测,平衡一致性与并发。
四种隔离级别(从低到高):
MySQL InnoDB 默认 RR,PostgreSQL/Oracle 默认 RC。
权衡:
MVCC:每行多版本,读不阻塞写,写不阻塞读。
原理:
好处:
代价:
MySQL InnoDB MVCC:
PostgreSQL MVCC:
innodb_lock_wait_timeout:行锁等待超时(秒,默认 50)。
innodb_deadlock_detect:死锁检测(8.0 默认 ON)。
lock_wait_timeout:元数据锁等待超时(MySQL)。
PG lock_timeout:锁等待超时(毫秒)。
PG MVCC 旧版本靠 VACUUM 清理。autovacuum 自动 VACUUM:
autovacuum:ON(默认),开启自动清理。
autovacuum_nap_time:轮询间隔(默认 1min),多久检查一次。
autovacuum_vacuum_threshold / autovacuum_analyze_threshold:触发阈值。
autovacuum_vacuum_scale_factor / autovacuum_analyze_scale_factor:触发比例。
autovacuum_max_workers:并发 worker 数(默认 3)。
问题:
innodb_purge_threads:purge 线程数(默认 4)。
innodb_max_purge_lag:purge 滞后阈值。
问题:
1. 减少锁范围
2. 锁顺序一致
3. 避免长事务
4. 合适隔离级别
5. 监控锁
⚠️ 常见误读:以为"隔离级别越高越好"。级别高一致性强但并发低(锁多)。多数业务 RC 够用,避免脏读,业务可接受不可重复读。强一致才用 RR/SERIALIZABLE。
💡 关键直觉:事务锁——隔离级别(READ UNCOMMITTED 脏读/RC 不可重复读多数够用/RR 幻读 MySQL 默认/SERIALIZABLE 最安全并发最低,级别高一致强并发低)。MVCC(多版本读不阻塞写,读不加锁快,旧版本占空间需清理,长事务阻塞清理表膨胀)。锁参数(lock_wait_timeout 调短快速失败、deadlock_detect ON 自动检测回滚高并发可 OFF)。autovacuum(PG MVCC 旧版本靠 VACUUM 清理,nap_time 轮询、threshold/scale_factor 触发阈值大表调低 0.05、max_workers 并发,跟不上表膨胀)。MySQL purge(purge_threads 调高、长事务阻塞 purge undo 堆积,监控 History list length)。锁优化(短事务减锁时间、WHERE 精确锁少行、索引行锁非表锁、锁顺序一致避死锁、避免长事务拆小、合适隔离 RC 多数/RR 强一致注意间隙锁、监控 innodb status/pg_locks)。
事务与锁的参数核心是隔离级别的选择,给一个工程决策矩阵。读已提交(多数商业库默认):杜绝脏读,允许不可重复读;适合绝大多数 OLTP 业务——订单、支付、库存的常规读写。可重复读(部分开源库默认):会话内一致性视图,配合间隙锁防幻影;代价是锁范围扩大、死锁概率上升,死锁频发的系统降级到读已提交常有意外的平静。串行化:正确性完美、并发近乎归零,只适合对账、审计这类"准准确确比快重要"的后台任务。快照隔离(部分库提供):读不加锁、写冲突检测,读多写少的报表场景的甜点。选择的元原则:隔离级别是"业务语义的需求",不是"越高越好的品质"——转账业务需要读已提交加显式行锁就足够,硬上串行化是把性能白白祭天;反过来,对一致性有真实要求的场景(超卖防护)就要在应用层加乐观锁或用足够强的隔离,含糊的中间态是最危险的。把这张矩阵贴在团队 Wiki,每次新业务的技术评审过一遍"这个业务的隔离需求是什么",锁参数的调优就前置成了设计决策。
锁参数章收官谈死锁的系统性治理。第一步,检测与记录:死锁检测开到最灵敏,每次死锁的完整现场(双方事务的语句、锁的粒度、持有与等待关系)自动留存——死锁日志是锁设计缺陷的免费诊断报告。第二步,模式归类:把一段时间的死锁记录按模式聚类,通常会发现八成的死锁集中在两三个模式(同两表反序更新、唯一键并发插入、间隙锁与范围更新的冲突)——治理对象是模式不是个案。第三步,对症改造:反序更新改统一访问序(所有事务按主键升序更新)、并发插入改预取号段、间隙锁冲突评估隔离级别降级或改写条件——每类模式都有成熟解药。三步法跑通后,死锁率应该进入个位数的月度量级;此时若还有零星死锁,多为业务逻辑的天然竞争(秒杀类),交给应用层的乐观锁去解。死锁治理是锁章节知识的综合应用场:检测参数(发现)、隔离级别(成因分析)、锁粒度(改造)全部上阵——把它当作本章的毕业考试题来准备。
锁参数章给一个现场流程——发生严重锁等待时按此解剖。第一步,抓现场:立刻导出当前锁等待关系(谁持锁、谁等待、等了多久、各自在执行什么语句)——现场几分钟后可能自行解除,证据不可再生。第二步,定性:区分"长事务持锁"(某事务开了一小时没提交——应用连接泄漏或忘提交)与"热点竞争"(大量短事务挤同一行——秒杀或序列号)——两者药方完全不同。第三步,止血:长事务杀掉(评估业务影响后),热点竞争临时扩行(把单行计数改成多行取模轮询)或限流。第四步,根治:长事务修应用(连接池加泄漏检测、事务边界收紧),热点改设计(预分配、异步化、队列化)。第五步,归档:现场数据、定性结论、根治方案入库,成为下次秒判的先例。五步流程的血泪经验在第一步——多数团队的问题不是不会处理,是处理完才发现没留证据,同样的坑第二年再踩一遍。
锁章收官建议一次"默认值审读"——把库的锁相关默认参数列出来,对照业务读一遍,这是多数团队没做过但一小时能完成的事。审读清单:锁等待超时(默认常见几十秒——对在线业务太长,用户早刷新了页面,事务还挂着;收到五秒内)、死锁检测间隔(默认通常够用,高并发微调收紧)、隔离级别默认值(不同库默认不同,你的业务知道自己在哪个级别吗——多数团队答不上来,这就是审读的价值)、最大锁数量与锁内存(超高并发系统的隐形天花板,知道在哪即可)。审读的产出是一页"锁参数与业务对照表"——每行写清默认值、我们的值、为什么。做完这页纸,锁层就从"出了事再查文档"变成"心里有账"——参数治理的颗粒度就到这了,再往下是第 2 章的语句与索引功夫。
收尾提醒:锁参数的一切调整都要以"锁等待监控"为伴——没有锁等待的指标面板,锁参数就是盲调;上线监控在先、调整参数在后,这个顺序不是流程洁癖,是因果律。面板上的等待时长分布与死锁计数,就是锁层健康的心电图,学会读它,锁章的功课才算完整。
补一个与监控联动的收尾:锁参数治理完成后,把"锁等待总量趋势"加入周报——不是为了告警(告警已有),是为了让趋势可见:锁等待的缓慢上升(每月百分之几)是业务并发自然增长与热点形成的先导指标,提前看到它,扩行改造与热点治理就能在事故前立项。锁层的终局管理不是消灭锁(不可能),而是让锁的增长曲线始终在视野里、在计划里——这又是全书"预测优于救火"总纲的一次具体落地。
再补一个跨文化的观察:不同业务团队对锁等待的耐受度天差地别(交易团队秒级告警、报表团队分钟级无感),所以锁参数从不宜全局一刀切——分级配置(按应用或按资源队列区分超时与优先级)才是成熟形态;这也再次说明参数调优的尽头是业务理解,懂业务脾气的参数才调得准。