1. 为什么需要
DECIMAL
在数据库中,常见的数值类型有:
INT
、BIGINT
→ 整数,存储容量有限。
FLOAT
、DOUBLE
→ 浮点数,存储效率高,但存在精度丢失问题。
DECIMAL(M, D)
→ 定点数,存储精确值。例子:
SELECT 0.1 + 0.2; -- 结果可能是 0.30000000000000004
这是浮点数的经典精度问题。
如果用DECIMAL(10,2)
存储:INSERT INTO test (amount) VALUES (0.1), (0.2); SELECT SUM(amount); -- 结果就是 0.30 (精确)
👉 结论:金融、电商、会计等涉及金额的业务必须使用
DECIMAL
,而不能用FLOAT
/DOUBLE
。
2.
DECIMAL
的存储方式
DECIMAL(M, D)
表示总共 M 位数字,其中 D 位小数。
M
最大 65(总位数)
D
最大 30(小数位数)存储为字符串形式的二进制编码,避免二进制浮点数误差。
计算时精度高,但性能略低于
FLOAT
/DOUBLE
。例子:
DECIMAL(10,2) -- 最大值:99999999.99 DECIMAL(18,6) -- 最大值:999999999999.999999
3. MySQL 中
DECIMAL
与 Java 的对应关系在 Java 中,浮点数(
float
、double
)也有精度问题,典型例子:System.out.println(0.1 + 0.2); // 输出 0.30000000000000004
Java 中对应的精确数值类型是
BigDecimal
。类型映射
MySQL 类型 Java JDBC 映射类型 DECIMAL / NUMERIC java.math.BigDecimal
FLOAT / DOUBLE Double
/Float
INT / BIGINT Integer
/Long
4. Java
BigDecimal
使用注意事项(1) 创建方式
BigDecimal a = new BigDecimal("0.1"); // 推荐,精确 BigDecimal b = new BigDecimal("0.2"); System.out.println(a.add(b)); // 0.3 // 不推荐 BigDecimal c = new BigDecimal(0.1); // 会有精度问题 System.out.println(c); // 0.10000000000000000555...
(2) 常见操作
BigDecimal x = new BigDecimal("10.25"); BigDecimal y = new BigDecimal("2.5"); System.out.println(x.add(y)); // 加法 System.out.println(x.subtract(y)); // 减法 System.out.println(x.multiply(y)); // 乘法 System.out.println(x.divide(y, 2, RoundingMode.HALF_UP)); // 除法,保留2位四舍五入
(3) 比较大小
不能用
equals
,需要用compareTo
BigDecimal a = new BigDecimal("1.0"); BigDecimal b = new BigDecimal("1.00"); System.out.println(a.equals(b)); // false(因为精度不同) System.out.println(a.compareTo(b)); // 0(数值相等)
5. 典型应用场景
金额字段
price DECIMAL(10,2) -- 最大 99999999.99
Java 中用
BigDecimal
接收,避免丢失精度。财务统计
统计总金额 → 必须保证无误差
结算、报表 → 精确小数位
电商优惠计算
折扣、积分兑换、满减 → 都需要
BigDecimal
来精确计算。
6. 总结
FLOAT
/DOUBLE
→ 高性能但有精度问题,适合科学计算、近似值场景。
DECIMAL
→ 精确存储,适合金额和财务场景,性能稍低但可以接受。在 Java 中:
金额类 → 使用
BigDecimal
存入数据库 → 使用
DECIMAL(M, D)
避免直接用
double
运算金额。