mysql并发修改配置表会出问题吗_mysql设计建议

18次阅读

mysql并发更新配置表易丢数据,因REPEATABLE READ不防“读-改-写”竞态;应加version校验、唯一索引、行锁或拆分表,并建立发布流程。

mysql并发修改配置表会出问题吗_mysql设计建议

会出问题,尤其是没加锁或没用事务控制时,UPDATE 同一行配置项大概率导致丢失更新(lost update)。

为什么并发改同一张配置表容易丢数据

MySQL 默认隔离级别是 REPEATABLE READ,但它不阻止两个事务同时读到旧值、各自计算后写回——这就是典型的“读-改-写”竞态。比如两个服务同时读到 status = 1,都改成 2UPDATE,最终只生效一次。

  • 没加 WHERE 条件或条件不精确(如用 name = 'timeout' 但没建唯一索引),可能误改多行
  • UPDATE config SET value = ? WHERE key = 'log_level' 这种语句,无版本号或时间戳校验,无法感知冲突
  • 应用层缓存了配置,数据库改了但缓存没清,造成“已更新却未生效”的假象

推荐的并发安全写法(带校验)

核心思路:让更新本身携带“预期状态”,失败即重试或报错,而不是静默覆盖。

  • version 字段,每次更新都检查并自增:
    UPDATE config SET value = 'debug', version = version + 1 WHERE key = 'log_level' AND version = 5;

    返回 affected_rows == 0 就说明被别人抢先改了

  • ON DUPLICATE KEY UPDATE(需先建唯一键):
    INSERT INTO config (key, value, updated_at) VALUES ('retry_times', '3', NOW()) ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = NOW();
  • 对关键开关类配置(如 is_maintenance_mode),直接用 select ... for UPDATE 显式加行锁(仅限 InnoDB)

配置表设计避坑点

不是所有字段都适合放进一张泛型 config 表。结构松散会放大并发风险,也难加约束。

  • 避免用 key/value 大宽表存所有配置;应按业务域拆分,比如 app_configpayment_config,每张表字段明确、类型固定
  • key 字段必须加 UNIQUE 索引,否则 UPDATE ... WHERE key = ? 可能锁住多行甚至全表
  • 不要用 TEXT 存简单字符串,优先用 VARCHAR(255);大配置(如 jsON 模板)可单独字段,但读写要分离,避免每次改小配置都加载大字段
  • 记录操作人和时间很重要:updated_by VARCHAR(64)updated_at DATETIME(3),出问题能快速追溯

最麻烦的不是怎么写 SQL,而是配置变更缺乏发布流程——比如开发直接连线上库 UPDATE,还没通知下游服务 reload。并发问题往往只是表象,背后是治理缺失。

text=ZqhQzanResources