MySQL 的 DECIMAL、FLOAT、DOUBLE 有什么区别?金额字段应该怎么选?
下面是一段教学用的模拟面试。
🧑💻 面试官:金额为什么通常不用 FLOAT?
🙋♂️ 我:它精度不够,换 DOUBLE 就准确了。
🧑💻 面试官:DOUBLE 能精确表示所有十进制小数吗?数据库用 DECIMAL,应用先用 Number 算错了再写进去呢?
🙋♂️ 我:数据库不会把之前的误差自动消掉。
🧑💻 面试官:折扣计算后有三位小数,什么时候舍入?所有币种都一定保留两位吗?
金额正确性是一整条计算和传输链路的约定,不是只把数据库字段改成 DECIMAL。
面试速答(60 秒版)
DECIMAL 是按声明精度保存十进制精确值的类型,FLOAT 和 DOUBLE 是近似浮点类型。DOUBLE 通常提供更高精度,但仍不能精确表示所有十进制小数。
金额通常适合使用明确精度和标度的 DECIMAL,或者按约定最小单位保存整数。具体选择要看金额范围、币种、计算方式和舍入规则,不是所有金额都固定两位小数。
应用计算和传输也要保持相同约定。JavaScript 可以采用经过评估的十进制库或整数单位,Python 可以使用从字符串创建的 Decimal。
数据库的精确类型不能修复应用先前引入的误差。还要检查驱动返回类型、JSON 表达、边界范围,以及乘除后在哪一步采用哪种舍入方式。

知识点详解:精度问题从哪里进入系统?
DOUBLE 为什么也不是十进制万能精确值?
常见二进制浮点能精确表示一些数,但许多十进制小数没有有限的二进制表示。增加位数通常减少近似误差,不会改变这一事实。
这类类型适合很多测量与科学计算场景,不是“所有浮点都不能用”。但需要严格十进制记账语义时,应该选择匹配要求的表示方法。
MySQL 把整数和 DECIMAL 归入精确数值类型,把 FLOAT、DOUBLE 归入近似数值类型。MySQL 数值类型文档
DECIMAL(12, 2) 表达的是什么?
12 是总位数,2 是小数点后的位数,整数部分最多十位。不是“整数十二位,再加两位小数”。
输入更多小数位、超出范围或混合其他类型运算时,还要看数据库的转换与 SQL 模式等规则。精确表示也不意味着无限位数,更不意味着不用设计舍入。DECIMAL 文档
如果业务需要四位费率或多币种标度,固定两位可能在存储时就损失信息。
为什么写入之前也要保持精确?
假设应用先按二进制浮点计算,再把结果转成字符串写入 DECIMAL。数据库接到的是计算后的值,无法推断原本想要的精确结果。
应从可信输入开始就采用约定表示。下面只演示两位、非负金额的加法;不包含币种、折扣、负数和通用舍入逻辑。
TypeScript(从字符串直接解析为整数最小单位):
function toMinorUnits(value: string): bigint {
if (!/^\d+(\.\d{1,2})?$/.test(value)) {
throw new Error("只接受非负、最多两位小数");
}
const [whole, fraction = ""] = value.split(".");
return BigInt(whole) * 100n
+ BigInt(fraction.padEnd(2, "0"));
}
const total = toMinorUnits("0.10") + toMinorUnits("0.20");
console.log(total.toString()); // "30",单位按本例约定
Python(直接从十进制字符串创建 Decimal):
from decimal import Decimal
total = Decimal("0.10") + Decimal("0.20")
print(total) # 0.30
不要先构造 float 再传给 Decimal,期望它自动找回原来的十进制输入。BigInt 则需要明确单位,也不能直接当 JSON 数字序列化;跨接口可以按契约用字符串表达。
舍入必须放在明确的业务步骤
假设计算折扣、税费或分摊后产生额外小数位。逐项舍入后相加,和总和计算后再舍入,结果可能不同。
应该规定采用哪种舍入模式、在哪一步舍入、剩余最小单位如何分配,以及记录哪些中间值。不能只写“保留两位”,让前后端各自处理。
本文讨论技术表示,不规定某个具体财务业务的规则;实际规则需要依据币种和业务契约确定。

驱动和接口可能把精度再次丢掉
数据库驱动可能把 DECIMAL 返回为字符串,应用不能为图方便无条件转成 Number。整数金额也要检查 Number 的安全整数范围与数据库字段范围。
验证应覆盖大数、很多项累加、乘除舍入、驱动往返和接口解析。数据库里某个值看起来正确,只证明了链路中的一个位置。
面试官继续追问
所有金额都存整数就够了吗?
不一定。整数需要明确单位和标度,费率、外汇及中间计算可能需要更多精度。它是一种方案,不是免除精度设计。
DECIMAL 可以和 DOUBLE 随便混算吗?
不能这样假设。表达式类型转换可能影响计算,应核对操作数类型和结果规则。
测试金额链路只看最终显示两位吗?
不够。格式化可能遮住误差,应检查计算结果、入库值、读取类型和序列化内容。
面试速记卡
- DECIMAL:明确精度与标度的十进制精确表示。
- FLOAT、DOUBLE:近似类型,DOUBLE 不保证所有小数精确。
- 整数金额:必须约定单位、标度和范围。
- 舍入规则:模式和步骤都要明确。
- 完整链路:输入、计算、驱动、数据库与接口一起验证。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →