SQL并发写入一致性靠事务与锁协同保障,需精准控制锁粒度、缩短事务边界、按场景选行锁与隔离级别(RC多数够用)、防范死锁并统一DML顺序。

SQL并发写入时,数据一致性靠事务和锁共同保障。关键不是“要不要用”,而是“怎么用得准、用得轻”——锁粒度太粗会卡住读写,事务太长会拖慢整体吞吐,盲目关锁或乱设隔离级别反而引发脏写、幻读等问题。
事务边界要短:只包真正需要一致性的操作
事务不是越大越安全。长时间事务会持有锁不放,阻塞其他写入,还可能因超时或中断导致回滚成本飙升。
- 把查询、日志、通知等非核心DB操作移出事务体
- 避免在事务里调用外部HTTP接口或执行耗时计算
- 例如:用户下单需扣库存+写订单,这两步必须原子;但发短信、更新缓存可异步处理
按场景选锁:从行锁起步,必要时才升级
InnoDB默认在主键/唯一索引上走行级锁,这是高并发写入的基础。但若条件没走索引,会退化为表锁——这是很多“莫名其妙卡死”的根源。
- 写前先explain你的UPDATE/DELETE语句,确认type=range/ref,key有实际索引名
- WHERE中混用函数(如WHERE DATE(create_time) = '2024-01-01')或隐式类型转换,都会让索引失效
- 批量更新尽量用IN (id1,id2,...),别用循环单条执行;但IN列表不宜过长(一般≤1000),否则优化器可能放弃索引
隔离级别别硬套:RC多数够用,RR慎用于高冲突场景
READ-COMMITTED(RC)下,每次SELECT都读最新已提交数据,不加Gap Lock,冲突少、性能好;REPEATABLE-READ(RR)虽能防不可重复读,但会引入间隙锁,容易导致插入死锁。
- 电商库存扣减、消息队列消费位点更新等强写场景,RC + 显式SELECT ... FOR UPDATE更可控
- 银行转账类严格一致性需求,可用RR,但务必确保WHERE条件精准命中索引,减少间隙锁范围
- MySQL 8.0+支持SET TRANSACTION ISOLATION LEVEL READ COMMITTED临时切换,无需改全局配置
死锁不是故障,是设计信号:学会看和防
死锁无法完全避免,但高频出现说明逻辑或索引有问题。MySQL会自动回滚代价小的事务并报Deadlock found,这时重点不是重试,而是分析为什么两个事务会争同一组资源。
- 开启innodb_print_all_deadlocks=ON,日志里会记录完整死锁链(谁锁了什么、等待什么)
- 统一DML顺序:比如所有服务更新订单时,先改order表,再改order_item表;避免A按order→item、B按item→order的交叉加锁
- 应用层捕获Deadlock异常后,建议固定延迟(如100ms)再重试,避免瞬间重试加剧竞争
不复杂但容易忽略。锁是手段,不是目的;事务是契约,不是保险柜。真正稳的并发写入,来自对业务流程的拆解、对索引路径的确认、对冲突模式的预判。










