使用Java的PostgreSQL上的Money数据

我正在编写一个挖掘货币兑换数据的Java程序。 数据可以有多个十进制数字,例如“0.973047”。 经过一些研究后,我发现BigDecimal是Java的正确数据类型,但我应该将哪种数据类型用于PostgreSQL?

NUMERIC / DECIMAL

正如Joachim Isaksson所说 ,你想使用NUMERIC / DECIMAL类型作为任意精度类型。

关于NUMERIC / DECIMAL两个要点:

  • 仔细阅读文档 ,了解您应该指定比例以避免默认比例为0,这意味着小数部分被删除的整数值。 虽然这是Postgres偏离标准SQL的地方之一(给你任何扩展到实现限制)。 因此,未能指定比例是一个糟糕的选择。
  • 根据SQL标准,SQL类型NUMERICDECIMAL接近但不相同的 。 在SQL:92中 ,您遵守NUMERIC的指定精度,而对于DECIMAL ,允许数据库服务器添加超出您指定的精度。 在这里,Postgres再次偏离标准,将NUMERICDECIMAL 记录为等效。

条款:

  • 精度是数字中的总位数。
  • 比例是小数点右边的位数(小数部分)。
  • (精度 – 比例)=小数点左边的位数(整数部分)。

明确您的项目的精度和规模的规格:


  • 精度必须足够大才能处理将来可能需要的更大数量。 意思是……今天您的应用程序可能会以数千美元的价格运行,但未来必须执行最终数以百万计的汇总报告。

  • 出于某些会计目的,您可能需要存储最小货币金额的一小部分。 含义…超过3或4个小数位,而不是美元一分钱所需的2位数。

避免使用MONEY类型

Postgres也提供MONEY类型。 这可能听起来不错,但对大多数用途来说可能不是最好的。 一个缺点是,使用MONEY比例由基于区域 设置的数据库范围配置设置来设置 。 因此,当您切换服务器或进行其他更改时,设置可能会发生危险的变化。 此外,您无法控制特定列的设置,而您可以在NUMERIC类型的每列上设置比例。 最后, MONEY不是标准SQL,如此标准SQL数据类型列表中所示。 Postgres包含MONEY ,以方便人们从其他数据库系统移植数据。

移动小数点

某些人采用的另一种方法是移动小数点,只存储大整数数据类型。

例如,如果将美元存入便士,将任意给定的小数乘以100,则转换为整数类型,然后继续。 例如,$ 123.45成为整数12,345。

这种方法的好处是更快的执行时间。 当对整数执行时,诸如sum类的操作非常快。 整数的另一个好处是减少了内存使用量。

我发现这种方法很烦人,令人困惑,而且风险很大。 烦人,因为计算机应该我们工作,而不是反对我们。 风险,因为一些程序员或用户可能忽略乘法/除法转换回小数,给出不正确的结果。 如果在没有良好支持准确小数的系统中工作,这种方法可能是一种可接受的解决方法。

当我们在SQL中使用DECIMAL / NUMERIC而在Java中使用BigDecimal ,我认为移动小数点没有任何优势。

舍入和NaN

在您的应用程序编程中,以及在Postgres服务器端进行的任何计算, 都要非常小心并注意小数部分中的舍入和截断 。 并测试无意中的NaN弹出。

在app和Postgres这两方面,总是避免浮点数据类型的钱工作。 浮点设计用于提高性能 ,但代价是精确度 计算可能会导致小数部分看似疯狂的额外数字。 对于财务/金钱或准确性很重要的其他目的不利。

BigDecimal

是的,在Java中,您希望将BigDecimal作为任意精度类型。 BigDecimal较慢并且使用更多内存,但会准确存储您的金额。 SQL NUMERIC / DECIMAL应映射到BigDecimal ,如此处和StackOverflow所述 。

BigDecimal是关于Java的最好的东西之一。 我不知道任何其他类似课程的平台,特别是那些经过精心实施和精心打造的平台,多年来取得了重大改进和修复。

使用BigDecimal肯定比使用Java的浮点类型 floatdouble慢。 但在现实世界的应用程序中,我怀疑你的资金计算会成为任何瓶颈。 此外,您或您的客户想要哪些: 最快的金钱计算,还是准确的金钱计算? 😉

我一直认为BigDecimal是Java中最大的睡眠function,在许多其他平台上使用Java平台的最重要优势是缺乏对分数的精确支持。

类似的问题: 货币的最佳数据类型

为了获得尽可能好(和精确)的精度,您可以使用NUMERIC (或其别名DECIMAL ),它具有高精度并允许您决定所需的精度;

数字

用户指定的精度,精确到小数点前的131072位; 小数点后最多16383位

通常,钱不应存储为浮点数。 最好的方法通常是将金额存储为最小允许大小的整数(例如,1美分),并将其格式化为输入和显示。 这实际上是固定精度DECIMAL列在SQL中的作用,但如果将其转换回Java,您仍然存在丢失精度的风险(例如,如果您将最后一个允许数字的一半分开,会发生什么)?