直接用 CREATE TABLE config (k VARCHAR(64), v TEXT) 会踩三类坑:类型丢失(如 timeout 需手动转 int)、查询低效(LIKE 'feature_%' 无法走索引)、并发写错(ON DUPLICATE KEY UPDATE 可能死锁);应加主键/唯一索引、type 字段、前缀索引、JSON 提取列索引,并用事务+校验+分批+版本通知保障安全与一致性。

为什么不用 CREATE TABLE config (k VARCHAR(64), v TEXT) 直接开干
这种表结构看着省事,但上线后大概率会踩三类坑:类型丢失、查询低效、并发写错。比如存一个超时时间 timeout,值是 "30",下次读出来得手动转 int;想查所有开关类配置(feature_*)就得 LIKE 'feature_%',走不了索引;多个服务同时执行 INSERT ... ON DUPLICATE KEY UPDATE 也可能因间隙锁导致死锁。
更稳妥的做法是加字段约束和索引:
-
key设为PRIMARY KEY或带唯一索引,避免重复键 - 补
type字段(如'string'/'int'/'bool'),应用层可据此做类型校验和自动转换 - 高频查询的配置前缀(如
app.,cache.)可建前缀索引:INDEX idx_key_prefix (key(16)) - 如果需要版本控制或审计,加
updated_at和updated_by,别等出问题再补
MySQL 8.0+ 用 JSON 字段存复杂配置真香?
当配置项开始嵌套(比如一个 redis 配置含 host、port、pool_size),纯 KV 表就难看了。这时 JSON 类型确实能少建几张表,但得盯紧两个现实限制:
-
JSON字段不能直接建普通索引,要提取路径建GENERATED COLUMN+ 索引,例如:ALTER TABLE config ADD redis_host VARCHAR(64) AS (JSON_UNQUOTE(JSON_EXTRACT(v, '$.redis.host'))) STORED;
再对redis_host加索引 - MySQL 的
JSON_SET()、JSON_REPLACE()不支持原子性更新深层字段(比如只改$.redis.timeout而不动其他字段),必须先读全量、改完再写回,高并发下容易覆盖 - 如果配置本身是数组(如
"whitelist": ["192.168.1.1", "10.0.0.5"]),JSON_CONTAINS()查询尚可,但想按数组元素分页或排序,基本没招
如何安全地批量更新配置而不炸服务
线上改配置最怕“改一半”,尤其涉及多个键联动(如 cache.enabled 和 cache.ttl 必须同批次生效)。单条 UPDATE 不够,得靠事务+校验:
- 所有变更封装在一个事务里,开头加
SELECT ... FOR UPDATE锁住相关 key(哪怕只读也要锁,防止其他事务在你校验后、提交前篡改) - 应用层在提交前做一次最终校验:比如要求
cache.enabled = 'true'时,cache.ttl必须 > 0,不满足就ROLLBACK - 避免用
REPLACE INTO或INSERT ... ON DUPLICATE KEY UPDATE批量写,它们不保证执行顺序,且无法捕获部分失败;改用显式INSERT+UPDATE分两步,并检查ROW_COUNT() - 如果配置量大(>100 条),拆成小批次(如 20 条/批),每批独立事务,降低锁持有时间
配置热加载时 MySQL 连接和缓存怎么配合
应用读配置不是每次都要查 DB——那太慢。常见做法是加一层内存缓存(如 Go 的 sync.Map,Java 的 ConcurrentHashMap),但关键是怎么让缓存和 DB 保持一致:
- 不要依赖定时轮询(比如每 30 秒
SELECT * FROM config),延迟不可控,还白耗连接 - 推荐“写时通知 + 读时兜底”:每次更新配置后,往 MySQL 的
config_version表(单行单列)执行UPDATE version SET v = v + 1,应用监听这个表的v变化(用SELECT v FROM version对比本地缓存值),变则全量重载 - 如果用 Redis 做二级缓存,记得给每个配置 key 加失效时间(如 5 分钟),防止 DB 更新后 Redis 没同步导致脏读
- 特别注意长连接场景:MySQL 连接空闲太久会被中间件或服务端断开,应用得有重连 + 重试逻辑,否则第一次热加载就卡住
配置表看着简单,但一旦跨服务、跨环境、跨版本,key 命名冲突、type 解释不一致、缓存击穿这些点,比 SQL 写错更难 debug。










