生产环境RDBMS已做API层校验时是否需配置表级CHECK约束
结论
生产环境在表上额外加CHECK约束不是过度冗余,是非常值得推广的生产级防御设计,API层的参数校验永远替代不了数据库层的原生约束。
为什么API层校验兜不住所有问题?
别信什么“我在接口层把所有参数都校验过了,库层再加约束是多此一举”的说法,生产环境里脏数据的写入路径比你想的多得多:
- 后续运维排查问题直接手动执行SQL改数据、临时跑批处理脚本漏加校验逻辑、老版本服务没升级最新的校验规则、其他业务线的服务因为需求直连库写数据,这些场景太常见了,没有库层约束,离谱的脏数据分分钟落库。
- 应用层的校验逻辑是跟着业务迭代随时改的,你今天写了星期值只能在1-7之间,下个月改需求的同事没复用公共校验组件、或者写代码漏了判断,非法值直接就写进库里了,等你发现故障的时候,可能已经攒了几万条脏数据,修复成本极高。
CHECK约束的性能损耗几乎可以忽略:写入时做个范围、枚举判断是纳秒级的开销,比起脏数据导致的线上故障、数据修复的人力成本,这点代价完全可以忽略不计。
两层校验的定位本来就不冲突:API层校验是为了给前端/调用方返回友好的错误提示,优化使用体验;库层约束是最后一道兜底防线,绝对不允许非法数据进入存储层,二者谁也替代不了谁。
对你给出的建表示例的补充说明
你的建表语句里的CHECK约束思路是对的,只有一个细节可以按需调整:
CREATE TABLE IF NOT EXISTS myTable ( the_date date NOT NULL DEFAULT now(), sentence character varying(10) COLLATE pg_catalog."default", dayNumber integer NOT NULL CHECK (dayNumber BETWEEN 1 AND 7), dayNumberInMonth integer NOT NULL CHECK (dayNumberInMonth BETWEEN 1 AND 32), monthNumber integer CHECK (monthNumber BETWEEN 1 AND 12), CONSTRAINT pk_myTable PRIMARY KEY (the_date) );
其中dayNumberInMonth BETWEEN 1 AND 32是粗粒度的拦截,能挡住0、33、-1这种明显的错误值,但没法拦住2月写30、4月写31这类逻辑错误。如果你的业务场景对日期准确性要求高,可以搭配触发器或者生成列做更细粒度的校验,要是只是为了挡明显的非法值,当前这个约束也完全够用。
什么情况下才叫真的冗余?
只有一种场景不需要加这类约束:你能100%保证表的所有写入路径完全受控,且有强制的流程、工具保障所有写入逻辑的校验规则和库层规则强一致——但现实里99%的生产团队都做不到这个程度,没必要为了省几行建表SQL冒脏数据的风险。
内容的提问来源于stack exchange,提问作者juztcode
相关产品推荐
相关产品推荐

