应使用 DECIMAL 类型存储金额,因 float 用二进制存储导致 0.1 等十进制小数精度丢失,引发对账不平、审计风险;DECIMAL 按十进制精确存储与计算,各数据库及 ORM 均支持,是金融场景唯一可靠选择。

因为 float 是近似数值类型,会引入精度误差,导致金额计算不准、对账不平、审计出问题。
浮点数天生存不准小数
float(以及 double)底层用二进制科学计数法存储,而很多十进制小数(比如 0.1、0.2、19.99)无法被精确表示为有限位二进制小数。就像十进制里 1/3 = 0.333… 无限循环一样,0.1 在二进制中也是无限循环小数,只能截断存储——这就产生了微小但确定的误差。
例如:
- 0.1 + 0.2 在 float 中可能算出 0.30000000000000004,而不是 0.3
- 数据库里存 19.99,实际可能存成 19.989999999999998
金额场景容不得“几乎正确”
金融和财务系统要求绝对精确:加总必须等于明细之和,扣款必须分毫不差,报表必须可追溯可审计。哪怕每笔只差 0.000001 元,百万级交易后误差可能达几百元;跨系统对账时一个微小差异就会触发人工核查,拖慢结算流程。
更麻烦的是,这种误差是“隐藏”的——SELECT 看起来正常(数据库常做四舍五入显示),但参与计算或导出到程序里就暴露了。
应该用 decimal / numeric
这是 SQL 标准中的**精确数值类型**,按指定精度(总位数)和标度(小数位数)存储,例如 DECIMAL(10,2) 表示最多 10 位数字、其中 2 位小数,能准确表示 -9999999.99 到 9999999.99 之间的任意值。
- 所有加减乘除运算都保持精度(除法需注意标度截断规则)
- 不同数据库(MySQL、PostgreSQL、SQL Server、Oracle)都支持且行为一致
- ORM 和应用层也能安全映射为 BigDecimal(Java)、Decimal(Python/C#)等精确类型
别被“看起来没问题”骗了
有人测试过 “19.99 + 0.01 = 20.00”,发现 float 也对,就认为“够用”。但这是巧合——只是当前计算路径恰好没暴露误差。真实业务涉及多轮累加、分摊、汇率换算、四舍五入、跨表关联,误差会累积、放大、交叉传染。一次线上资损事故,往往就始于一个 float 金额字段。
规范做法:只要字段含义是“钱”,无论大小、是否带小数,一律用 DECIMAL。这是成本最低、效果最稳的风控手段。










