尝试从MySQL数据库的BigDecimal读取创建Joda-Money Money
对象会引发错误。
此代码:
PreparedStatement p_stmt = ...;
ResultSet results = ...;
Money amount = Money.of(CurrencyUnit.USD, results.getBigDecimal("amount"));
抛出这个:
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)
我实际上通过添加舍入来解决错误:
Money amount = Money.of(CurrencyUnit.USD, results.getBigDecimal("amount"), RoundingMode.HALF_UP);
但是,我对这个解决方案持怀疑态度。这是最好的吗?。
我正在使用DECIMAL(19,4)
按照this SO answer将资金值存储在数据库中。老实说,有点让我感到困惑的是,为什么那里的回答者要求DB上有4位小数精度,但我倾向于相信高价值的答案,我认为他们知道他们在谈论什么,我会后悔不遵循他们的咨询。然而,Joda-Money不喜欢美国货币的4位小数精度。也许DECIMAL(19,4)
是一个国际标准,他们需要4位小数精度?不确定..
使问题简明扼要:
RoundingMode.HALF_UP
是解决此错误的理想解决方案吗?DECIMAL(19,4)
更改为DECIMAL(19,2)
吗?答案 0 :(得分:0)
是的,不是一个好的解决方案。你代表的是金钱,因此你无法向上/向下舍入并且几分钱:)。
问题是CurrencyUnit.USD的位数为2,例如:1.45,来自DB的内容可能是1.45343,可能导致比例不同。试着用BigMoney而不是Money代表钱。
BigMoney amount = BigMoney .of(CurrencyUnit.USD, results.getBigDecimal("amount"));
答案 1 :(得分:0)
有同样的问题并通过添加舍入模式解决它:不必要:
@Test(dataProvider = "moneyValueProvider")
public void testMoneyFromFloat(String currency, Float value) {
CurrencyUnit cu = CurrencyUnit.of(currency);
//Double dVal = Double.valueOf(value.toString());
BigDecimal bigDecimal = new BigDecimal(value.toString());
Money money = Money.of(cu, bigDecimal, RoundingMode.UNNECESSARY);
Assert.assertNotNull(money);
Assert.assertEquals(bigDecimal.doubleValue(), money.getAmount().doubleValue());
}
@DataProvider
public static Object[][] moneyValueProvider() {
return new Object[][] {
{"GBP", 22.5f},
{"GBP", 57.8f},
{"JPY", 15000.0f}
};
答案 2 :(得分:0)
Joda Money和BigDecimal为每种货币类型定义了一个“比例”。
规模为否。货币使用的小数位数。
因此,美元的小数位数为2(小数点后两位小数)。
如果您尝试从具有两个以上小数位的来源实例化一个USD货币的Money实例,那么您将得到缩放错误。 例如
20.99 is fine
20.991 throws an error.
其他货币允许使用不同的小数位数。
根据文档RoundMode.UNNECESSARY
,如果实际上需要舍入,则实际上将引发异常。
例如:假设USD的小数位数为2,则小数位数应为2。
使用:
Money money = Money.of(CurrencyUnit.USD, value, RoundingMode.UNNECESSARY);
值:
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
周围的环境和金钱总是一个问题。 我的方法是在db中存储正确的比例
例如:如果美元是DECIMAL(19,2)
使用RoundingMode.HALF_UP
。
进行乘法和除法操作时要小心。 在除法之前进行乘法运算将减少舍入问题。 如果您在进行四舍五入时进行算术运算,那应该没问题。