java金额字段用什么数据类型存储?

1,734 阅读2分钟

理论

金额是小数,而且必须精确,所以用BigDecimal。

所以,金融场景一般用BigDecimal。非金融场景,一般用double就够了,因为不要求那么精确,而且可以少占一点空间,计算速度也会快一点。

工作使用

公司ys,金额和手续费都是Double。加减的时候,没有精度问题吗?有,但是底层通过BigDecimal转换了一下精度,本质是四舍五入了,所以就没有精度的问题。

公司zf,全部都是BigDecimal。

double有什么问题?

有精度问题。

测试代码

import java.math.BigDecimal;
import lombok.extern.slf4j.Slf4j;

/**
 * 测试double的精度问题
 *
 * @author gzh
 * @createTime 2021/10/6 10:55 AM
 */
@Slf4j
public class TestDouble {

   public static void main(String[] args) {
//    double d1 = 0.03;
//    double d2 = 0.02;
//    double d3 = d1 -d2;
//    log.info(String.valueOf(d3)); //0.009999999999999998

      //
//    Double d1 = 0.03;
//    Double d2 = 0.02;
//    Double d3 = d1 -d2;
//    log.info(String.valueOf(d3)); //0.009999999999999998
//    log.info(String.valueOf(subtract(d1,d2))); //0.01,因为底层用BigDecimal转换了一下精度,公司ys就是这么玩的。

      BigDecimal d1 = BigDecimal.valueOf(0.03);
      BigDecimal d2 = BigDecimal.valueOf(0.02);
      BigDecimal d3 = d1.subtract(d2);
      log.info(String.valueOf(d3)); //0.01

   }

   /**
    * 减法
    *
    * @author gzh
    * @date 2021/10/6 12:47 PM
    * @param d1
    * @param d2
    * @return java.lang.Double
    */
   public static Double subtract(Double d1, Double d2)
   {
      return new Double(format(d1.doubleValue() - d2.doubleValue()));
   }

   /**
    * 用BigDecimal转换double精度。
    * 为什么BigDecimal精度准确,double不准确?因为BigDecimal四舍五入了。
    *
    * @author gzh
    * @date 2021/10/6 12:47 PM
    * @param value
    * @return double
    */
   public static double format(double value)
   {
      return new BigDecimal(Double.toString(value)).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
   }
}

数据库

数据库oracle、mysql都有decimal类型,所以代码层面和数据库层面都统一用同一个数据类型。

注:如果用的是double,代码层面和数据库层面也要统一用double。

BigDecimal和double的区别?

为什么double就有精度问题?而BigDecimal就没有精度问题?BigDecimal是怎么解决精度的?因为本质是BigDecimal进行四舍五入了。

并且,BigDecimal数据长度可以无限大。

最佳实践

用BigDecimal,因为涉及到金额的问题,肯定数据准确是第一重要的,至于多占了一点点空间,速度慢一点点,都不是最重要的。

参考

《java核心技术》

zazalu.space/2019/09/25/…

juejin.cn/post/684490…