直接改库存引擎底层逻辑比加补丁更治本,通过long强制压制、显式精度截断、构造器校验及数据访问层统一处理,根治字符串拼接、浮点干扰、负库存三类规格失真问题。

直接改库存引擎的底层逻辑,比加补丁更治本。老旧系统里多规格库存常混着字符串拼接、隐式类型转换、硬编码阈值,一改就崩。压制机制加高精度截断不是炫技,是给混乱的规格流装上“安全阀”和“校准尺”。
识别三类典型规格失真源头
重构前得知道病根在哪:
- 字符串型规格字段未清洗:数据库存的是"XL-红色-2025夏款"或"XL/红/夏",Java里直接split或substring易越界,取错尺码或颜色维度;
- 浮点数精度干扰整数计数:用double存储“可售件数”(如99.9999999),再做int强转导致截断为99,实际应为100;
- 边界缺失引发负库存透支:SKU组合拆解时(如套装A含2件单品B+1件C),未校验子项库存是否充足,导致B扣减后为-1。
用long强制压制 + 显式精度截断
所有规格库存参与运算前,必须统一转为long并显式截断小数部分,杜绝隐式舍入风险:
- 从请求参数获取库存数时,先用
BigDecimal解析再转long:new BigDecimal("99.999").setScale(0, RoundingMode.DOWN).longValue(),确保向下取整; - 数据库读取numeric字段后,立即调用
Math.max(0L, value.longValue())压制负值,并记录告警; - 多规格聚合计算(如按颜色汇总尺码库存)必须用
Stream.mapToLong(...).sum(),避免中间过程出现double溢出。
在规格对象构造器中嵌入不可绕过压制校验
校验不是写在Service里可被跳过的逻辑,而是封装进SkuStock实体构造器中:
- 创建实例时强制检查:
if (rawQty ; - 规格组合生成后,调用
enforceNonNegative()方法确保各子项≥0,否则拒绝构建并触发熔断; - 多级拆解(如套装→单品→批次)需在每层工厂方法中校验输出值是否在合理区间,例如单件库存必须∈[0, 999999],超限自动归零并上报审计日志。
把压制逻辑下沉到数据访问层
避免业务代码重复写if判断。在MyBatis的TypeHandler或JPA的AttributeConverter中,统一处理入库/出库时的规格转换与压制:
- 出库时:将数据库字段转为
SkuStock对象,自动执行Math.max(0L, ...)与位数校验(如限制最大6位整数); - 入库时:若传入值为null、NaN或超出预设范围,直接拒绝持久化并抛出受检异常;
- 配合数据库
CHECK (stock_qty BETWEEN 0 AND 999999)约束,形成双保险。











