19

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

4

3 回答 3

33

NUMERIC/DECIMAL

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

NUMERIC关于/的两个要点DECIMAL

  • 仔细阅读文档以了解您应该指定比例以避免默认比例 0,这意味着小数部分被截断的整数值。虽然这是 Postgres 偏离标准 SQL 的地方之一(让您可以扩大到实施限制)。因此,未能指定规模是一个糟糕的选择。
  • 根据 SQL 标准,SQL 类型NUMERIC&DECIMAL接近但不相同。在SQL:92中,尊重您指定的精度NUMERIC,而对于DECIMAL数据库服务器,允许添加超出您指定的额外精度。在这里,Postgres 再次偏离标准,两者NUMERIC&DECIMAL 记录为等效。

条款:

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

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


  • 精度必须足够大以处理将来可能需要的更大数字。这意味着......也许您的应用程序今天的工作量为数千美元,但将来必须执行最终以数百万美元计的汇总报告。

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

避免MONEY类型

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

移动小数点

一些人采用的另一种选择是移动小数点,并且只存储在大整数数据类型中。

例如,如果将美元存储为一美分,则将任何给定的小数乘以 100,转换为整数类型,然后继续。例如,$123.45 变成整数 12,345。

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

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

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

四舍五入&NaN

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

在双方,app 和 Postgres 中,总是避免使用浮点数据类型来赚钱。浮点是为提高性能速度而设计的,但以牺牲精度为代价。计算可能会导致小数部分出现看似疯狂的额外数字。不适合财务/金钱或其他需要准确性的目的。

BigDecimal

是的,在 Java 中,您希望BigDecimal作为任意精度类型。BigDecimal速度较慢并使用更多内存,但会准确存储您的金额。SQL NUMERIC/DECIMAL应该映射到这里StackOverflowBigDecimal上的讨论。

BigDecimal是关于 Java 的最好的事情之一。我不知道有任何其他平台具有类似的类别,尤其是一个实施良好且经过多年改进和修复的平台。

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

我一直认为它是BigDecimalJava 中最大的沉睡特性,与许多其他缺乏对小数的复杂支持的平台相比,使用 Java 平台的最重要优势。

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

于 2013-08-11T08:13:01.183 回答
5

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

数字

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

于 2013-08-11T07:14:26.050 回答
2

一般来说,钱不应该存储为浮点数。最好的方法通常是将金额存储为最小允许大小的整数(例如,一美分),并将其格式化以供输入和显示。这本质上是DECIMALSQL 中固定精度列所做的事情,但是如果将其传输回 Java,您仍然冒着丢失精度的风险(例如,如果您正好拆分最后一个允许数字的一半会发生什么情况)?

于 2013-08-11T07:48:10.037 回答