一、数据库层:精准存储,奠定基础
总体原则,不要出现和使用浮点数,确定整型用Int或者BigInt(比如ID号之类),不确定金额统一用Decimal类型。使用DECIMAL(p, s)类型,DECIMAL是十进制高精度数值类型,专门用于存储需要精确计算的小数,不会像FLOAT/DOUBLE那样存在二进制浮点误差。
参数含义:p表示「总有效位数」(整数位 + 小数位),s表示「小数位数」。例如:表示普通金额DECIMAL(18, 2)
一些注意细节:
金额:一般保留2位(JPY币种特殊,保留0位小数),小数位可以补0,例如:"1.00"
汇率:前端展示保留5位小数,数据库存储保留9位小数,看业务要求。
二、后端层:高精度计算,业务闭环
接收前端参数时,优先接收「字符串格式」的金额,避免传输过程中的精度丢失;
计算时使用专门的高精度数值类型,杜绝普通浮点数(double/float);
与数据库交互时,直接映射DECIMAL类型到后端高精度类型,无需额外转换;
所有金融计算完成后,统一格式化保留指定小数位(通常2位),避免多余小数位流转。
三、 前后端交互:原样传输,避免失真
前端传参数给后端,核心方案是JSON中金额字段统一用字符串。
后端返回给前端
后端将高精度类型(BigDecimal/Decimal)转换为「字符串」后,放入 JSON 响应体返回。
一些注意细节:
不要直接返回BigDecimal对象(部分 JSON 序列化框架会将其转为double,导致精度丢失),需主动转为字符串。
四、前端层:精准展示,安全操作
前端负责金额的输入、展示和简单处理(不负责核心计算,核心计算必须放在后端),需要保证用户操作和页面展示的精度准确,这里以JavaScript/TypeScript为例提供方案。
- 不使用
Number类型处理金额,避免精度丢失; - 核心计算(如金额拆分、手续费计算)不放在前端,前端仅做「格式校验、展示、传递」;
- 引入第三方高精度库处理前端必要的简单金额操作(如金额格式化、相加展示)。
统一使用decimal.js库,查看源代码,核心几个细节:
- 该库的rounding mode 默认 ROUND_HALF_UP,既四舍五入。和后端是一致的。结合业务
Decimal(a).add(b).toFixed(2)
- 如果特殊业务需求,需要向上取整或者向下取整,使用ROUND_UP或者ROUND_DOWN,即
Decimal(a).add(b).toFixed(2, Decimal.ROUND_UP)
Decimal(a).add(b).toFixed(2, Decimal.ROUND_DOWN)
-
使用该库计算不区分字符串和数字,库里面有内部处理。
-
使用该库,推荐使用链式调用,清晰优雅
-
使用该库,原型方法对照如下,推荐使用缩写,简洁优雅
/*
* absoluteValue abs
* ceil
* clampedTo clamp
* comparedTo cmp
* cosine cos
* cubeRoot cbrt
* decimalPlaces dp
* dividedBy div
* dividedToIntegerBy divToInt
* equals eq
* floor
* greaterThan gt
* greaterThanOrEqualTo gte
* hyperbolicCosine cosh
* hyperbolicSine sinh
* hyperbolicTangent tanh
* inverseCosine acos
* inverseHyperbolicCosine acosh
* inverseHyperbolicSine asinh
* inverseHyperbolicTangent atanh
* inverseSine asin
* inverseTangent atan
* isFinite
* isInteger isInt
* isNaN
* isNegative isNeg
* isPositive isPos
* isZero
* lessThan lt
* lessThanOrEqualTo lte
* logarithm log
* [maximum] [max]
* [minimum] [min]
* minus sub
* modulo mod
* naturalExponential exp
* naturalLogarithm ln
* negated neg
* plus add
* precision sd
* round
* sine sin
* squareRoot sqrt
* tangent tan
* times mul
* toBinary
* toDecimalPlaces toDP
* toExponential
* toFixed
* toFraction
* toHexadecimal toHex
* toNearest
* toNumber
* toOctal
* toPower pow
* toPrecision
* toSignificantDigits toSD
* toString
* truncated trunc
* valueOf toJSON
*/