Waterline ORM(Sails.js)如何指定decimal类型长度精度存储货币值
Waterline ORM(Sails + PostgreSQL)货币字段配置方案
一、货币值存储的最佳选型
- 不推荐用
float类型存储货币:浮点数基于二进制实现,天生存在精度截断问题,做金额累加、折扣计算时很容易出现0.1+0.2=0.30000000000000004这类误差,支付、对账场景下会直接造成资损问题。 - 存储层优先选用
decimal(9,2):你当前配置的这个PostgreSQL原生类型本身完全符合货币存储要求,固定保留2位小数,最大支持存储9999999.99的金额,覆盖绝大多数普通法币的业务场景完全够用。 - 你碰到的blueprints查询返回字符串不是功能异常,是sails-postgresql适配器的默认处理逻辑:JavaScript原生
Number类型无法无损承载高精度十进制值,适配器为了避免精度丢失,会把decimal/numeric类型的查询结果默认转成字符串返回。只需要在模型里加简单的转换逻辑,就能正常返回数字类型,不需要修改columnType配置。
转换配置参考:
如果业务涉及超大金额、多币种需要更高精度,也可以直接存分为单位的整数,比如10.00元存1000,用attributes: { price: { type: 'number', columnType: 'decimal(9,2)', columnName: 'PRICE', // 查询结果转数字返回 after: function(val) { return val === null ? null : Number(val); }, // 写入前统一处理为2位小数格式 before: function(val) { if (typeof val !== 'number' || isNaN(val)) return val; return val.toFixed(2); } } }integer类型,完全没有精度问题,计算性能也更好,只需要在业务层做元分转换即可,这也是工业界非常常用的落地方案。
二、float类型映射decimal(9,2)存储的配置方法
- 只要显式指定
columnType: 'decimal(9,2)',不管属性的type设为number还是float,sails-postgresql都会在数据库里创建decimal(9,2)格式的字段,不会自动转成浮点数类型。配置示例:attributes: { price: { type: 'float', columnType: 'decimal(9,2)', columnName: 'PRICE' } } - 注意:如果只写
type: 'float'不指定columnType,适配器会默认创建双精度浮点数(double precision)类型字段,不会自动使用decimal类型,必须手动声明columnType才能固定为decimal(9,2)的存储格式。 - 非必要不推荐该搭配:用float类型映射decimal字段时,JS侧的浮点数精度问题依然存在,就算数据库存的是固定2位小数,转成JS浮点数后做计算还是可能出现精度漂移。
内容的提问来源于stack exchange,提问作者S. Kaushika
相关产品推荐
相关产品推荐

