INSERT与UPDATE会相互阻塞的主要原因是数据库行级锁机制,当UPDATE锁定行时INSERT等待反之亦然,导致并发冲突。
MySQL锁机制解释
在MySQL的InnoDB存储引擎中,UPDATE操作会为修改的行加排他锁(X锁),这会阻塞其他事务对同一行的INSERT操作,因为INSERT也需要获取该行的锁。
同样,INSERT操作在插入新行时,如果新行与现有索引冲突,也可能导致锁等待,从而阻塞后续的UPDATE。
例如,当一个事务执行UPDATE table SET col=1 WHERE id=10时,它持有id=10的X锁,另一个事务试图INSERT INTO table (id) VALUES(10)就会被阻塞直到前一个事务提交。
PostgreSQL事务隔离
在PostgreSQL中,UPDATE会锁定目标行,防止其他事务插入相同主键或唯一键的值,从而造成INSERT阻塞。
行锁是MVCC的一部分,但UPDATE后的可见性变化会导致INSERT在检查唯一约束时等待锁释放。
实际场景中,高并发下频繁的UPDATE和INSERT容易引发死锁或长时间阻塞,需要优化索引和事务粒度。
SQL Server锁升级问题
SQL Server中,UPDATE从行锁可能升级到页锁或表锁,阻塞大范围INSERT。
INSERT操作获取意图独占锁(IX锁),但如果UPDATE持有X锁,INSERT必须等待。
使用READ COMMITTED SNAPSHOT可以缓解,但不完全消除阻塞。
Oracle并发控制
Oracle的UPDATE加TX锁(事务锁)和行锁,INSERT在插入时验证唯一性会等待。
多版本控制下,阻塞主要来自索引键冲突。
建议使用分区表或细化WHERE条件减少锁范围。
实际生产经验
在电商订单表中,UPDATE库存时锁定商品行,导致批量INSERT订单阻塞数秒。
优化后,将UPDATE拆分成小事务,或用SELECT FOR UPDATE提前锁行。
监控锁等待时间,超过阈值报警。
通用数据库原理
关系数据库确保ACID,锁是实现一致性的核心,INSERT/UPDATE冲突源于共享资源。
间隙锁(Gap Lock)进一步加剧阻塞,防止幻读。
REPEATABLE READ隔离级别下更明显。
FAQ
Q: 如何避免INSERT和UPDATE阻塞?
A: 缩短事务时间,使用乐观锁,或调整隔离级别为READ COMMITTED。
Q: 什么是行锁和表锁?
A: 行锁只锁单行,表锁锁整表,UPDATE常从行锁升级。
Q: 高并发下怎么优化?
A: 加索引避免全表扫描,异步处理非关键更新。
Q: 死锁怎么处理?
A: 设置锁超时,分析锁日志,重试事务。