我正在编写一个挖掘货币兑换数据的 Java 程序。数据可以有多个十进制数字,例如“0.973047”。经过一番研究,我发现 BigDecimal 是 Java 的正确数据类型,但我应该为 PostgreSQL 使用哪种数据类型?
3 回答
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 包括方便人们从其他数据库系统移植数据。NUMERIC
MONEY
MONEY
移动小数点
一些人采用的另一种选择是移动小数点,并且只存储在大整数数据类型中。
例如,如果将美元存储为一美分,则将任何给定的小数乘以 100,转换为整数类型,然后继续。例如,$123.45 变成整数 12,345。
这种方法的好处是更快的执行时间。对整数执行诸如此类的操作sum
非常快。整数的另一个好处是更少的内存使用。
我觉得这种方法很烦人、令人困惑且有风险。烦人,因为计算机应该为我们工作,而不是反对我们。有风险,因为某些程序员或用户可能会忽略乘法/除法以转换回小数,从而给出不正确的结果。如果在没有对精确小数的良好支持的系统中工作,这种方法可能是一种可接受的解决方法。
当我们在 SQL 和Java中使用DECIMAL
/时,我认为移动小数点没有任何优势。NUMERIC
BigDecimal
四舍五入&NaN
在你的应用程序的编程中,以及在 Postgres 服务器端进行的任何计算中,要非常小心并注意小数部分的舍入和截断。并测试无意中弹出的NaN 。
在双方,app 和 Postgres 中,总是避免使用浮点数据类型来赚钱。浮点是为提高性能速度而设计的,但以牺牲精度为代价。计算可能会导致小数部分出现看似疯狂的额外数字。不适合财务/金钱或其他需要准确性的目的。
BigDecimal
是的,在 Java 中,您希望BigDecimal
作为任意精度类型。BigDecimal
速度较慢并使用更多内存,但会准确存储您的金额。SQL NUMERIC
/DECIMAL
应该映射到这里和StackOverflowBigDecimal
上的讨论。
BigDecimal
是关于 Java 的最好的事情之一。我不知道有任何其他平台具有类似的类别,尤其是一个实施良好且经过多年改进和修复的平台。
使用BigDecimal
肯定比使用Java 的浮点类型, float
&慢double
。但在现实世界的应用程序中,我怀疑你的金钱计算会成为任何瓶颈。此外,您或您的客户想要哪一个:最快的金钱计算,还是准确的金钱计算?
我一直认为它是BigDecimal
Java 中最大的沉睡特性,与许多其他缺乏对小数的复杂支持的平台相比,使用 Java 平台的最重要优势。
类似问题:货币的最佳数据类型
为了获得尽可能好的(和精确的)精度,您可以使用NUMERIC
(或其别名DECIMAL
),它具有高精度并允许您决定所需的精度;
数字
用户指定精度,精确到小数点前131072位;小数点后最多 16383 位
一般来说,钱不应该存储为浮点数。最好的方法通常是将金额存储为最小允许大小的整数(例如,一美分),并将其格式化以供输入和显示。这本质上是DECIMAL
SQL 中固定精度列所做的事情,但是如果将其传输回 Java,您仍然冒着丢失精度的风险(例如,如果您正好拆分最后一个允许数字的一半会发生什么情况)?