贝利信息

mysql并发访问如何减少锁冲突_mysql设计优化方法

日期:2026-01-02 00:00 / 作者:P粉602998670
SELECT ... FOR UPDATE 在高并发下易锁表,因其在满足条件的行上加排他锁,若无索引则升级为表级锁或锁整个索引范围,且事务间更新顺序不一致易致死锁;应确保WHERE字段有有效索引、避免混合操作、缩短事务、优先用INSERT ... ON DUPLICATE KEY UPDATE,并根据读写比例选择合适隔离级别。

为什么 SELECT ... FOR UPDATE 在高并发下容易锁表?

本质是它会在满足条件的行上加排他锁(X锁),如果查询没走索引,InnoDB 会升级为表级锁或锁住整个索引范围;更常见的是多个事务按不同顺序更新同一组行,导致死锁或长时间等待。

INSERT ... ON DUPLICATE KEY UPDATE 替代“先查后更”逻辑

典型场景如计数器、状态机流转、幂等插入——这类操作若拆成 SELECT + INSERT/UPDATE,在并发下必然出现竞态:两个事务同时查到旧值,都执行更新,最终只生效一次。

INSERT INTO user_login_log (user_id, login_time, ip)
VALUES (123, NOW(), '192.168.1.1')
ON DUPLICATE KEY UPDATE login_time = VALUES(login_time), ip = VALUES(ip);

读多写少场景下,用 READ COMMITTED 隔离级别降低锁粒度

MySQL 默认隔离级别 REPEATABLE READ 会启用间隙锁(Gap Lock)防止幻读,但代价是更大范围的锁冲突;而 READ COMMITTED 只对实际命中的记录加行锁,不锁间隙,适合订单查询、商品详情等以读为主、写频次低的业务。

分库分表前,先确认是不是索引和语句本身的问题

很多团队一遇到并发慢就想着分片,结果发现慢查询日志里全是 type: ALLExtra: Using filesort —— 根本问题在缺失索引或 ORDER BY/GROUP BY 没利用索引。

真正需要分片的信号是单表超千万行且写入持续增长、二级索引维护成本明显上升,而不是单纯因为某条 UPDATE尔锁了 200ms。