ResultSet::getBigDecimal 抛出 joda-money 的比例异常

ryv*_*age 5 java mysql jdbc joda-money

尝试从 MySQL 数据库读取的 BigDecimal 创建 Joda-MoneyMoney对象会引发错误。

这段代码:

PreparedStatement p_stmt = ...;
ResultSet results = ...;
Money amount = Money.of(CurrencyUnit.USD, results.getBigDecimal("amount"));
Run Code Online (Sandbox Code Playgroud)

抛出这个:

java.lang.ArithmeticException: Scale of amount 1.0000 is greater than the scale of the currency USD
    at org.joda.money.Money.of(Money.java:74)
    at core.DB.getMoney(DB.java:4821)
Run Code Online (Sandbox Code Playgroud)

我实际上已经通过添加舍入解决了该错误:

Money amount = Money.of(CurrencyUnit.USD, results.getBigDecimal("amount"), RoundingMode.HALF_UP);
Run Code Online (Sandbox Code Playgroud)

但是,我对这个解决方案持怀疑态度。是最好的吗?

我用来按照这个 SO 答案DECIMAL(19,4)将货币值存储在数据库上。老实说,这有点让我困惑,为什么那里的回答者要求数据库上的小数点后 4 位精度,但我倾向于相信高价值的答案,并且我认为他们知道他们在说什么,并且我会后悔没有遵循他们的要求建议。然而 Joda-Money 不喜欢美国货币的小数点后 4 位精度。也许是国际标准要求小数点后 4 位精度?没有把握..DECIMAL(19,4)

为了使问题简洁:

  1. RoundingMode.HALF_UP解决此错误的理想解决方案吗?
  2. 我应该将 MySQL DB 的精度从 更改为DECIMAL(19,4)DECIMAL(19,2)
  3. 有没有办法改变 Joda-Money 的精度?如果是:我应该吗?

Bre*_*ton 3

Joda Money 和 BigDecimal 为每种货币类型定义了一个“规模”。

规模是没有。货币使用的小数位数。

因此美元的小数位数为 2(小数点后两位小数)。

如果您尝试从具有超过两位小数的源实例化美元货币的 Money 实例,那么您将收到比例错误。例如

20.99 is fine
20.991 throws an error.
Run Code Online (Sandbox Code Playgroud)

其他货币允许不同的小数位数。

根据文档,RoundMode.UNNECESSARY如果实际需要舍入,实际上会抛出异常。

例如:假设美元的小数位数为 2,则预计有 2 位小数。

使用:

Money money = Money.of(CurrencyUnit.USD, value, RoundingMode.UNNECESSARY);
Run Code Online (Sandbox Code Playgroud)

价值:

1.20 - works fine
1.200 - works fine as whilst extra digit rounding isn't necessary.
1.201 - throws an exception as rounding is necessary
Run Code Online (Sandbox Code Playgroud)

四舍五入和金钱始终是一个问题。我的方法是将正确的比例存储在数据库中

例如:如果是美元,则 DECIMAL(19,2)

使用RoundingMode.HALF_UP

做乘法和除法时要小心。在除法之前进行乘法将减少舍入问题。如果你在做算术的时候四舍五入,你应该没问题。