使用 JPA + MySQL 进行货币操作的正确方法是什么?
What's the correct approach for monetary operations with JPA + MySQL?
在这种情况下,我需要在执行货币操作减法的字段中执行更新。该列创建为 DECIMAL(19,2) UNSIGNED
.
首先我得到值:
static final String LOCK_AMOUNT_FOR_UPDATED = "select amount from Sample where uuid = :uuid for update ";
这是存储库:
@Query(value = LOCK_AMOUNT_FOR_UPDATED, nativeQuery = true)
Float getAmountForUpdate(@Param("uuid") String uuid);
这里是第一题,不是返回Float。 建议返回一个 BigDecimal?
然后我检查值并执行更新:
static final String DECREASE_AMOUNT = "update Sample set amount = amount - :amountToSubtract where uuid = :uuid ";
存储库:
@Modifying
@Query(value = DECREASE_AMOUNT, nativeQuery = true)
void decreaseAmount(@Param("amountToSubtract") Float amountNegotiated, @Param("uuid") String uuid);
当值为:1927369.70
时执行此操作。我得到:
Data truncation: Out of range value for column 'amount' at row 1
方法调用是这样的:
repository.decreaseNetAmount(amountNegotiated.floatValue(), uuid);
我注意到当我 select 值和我在 BigDecimal 中调用 .floatValue()
时 1927369.70
变成了 1927369.80
。
将所有内容都用作 BigDecimal 的正确方法是什么,甚至是 nativeQuery 的参数?
我会推荐给:
- 对参数和实体属性使用 BigDecimal(如果您决定使用 BigDecimal)。
- 重新考虑为什么要使用本机查询来更新单个记录。获取实体对象并更改属性的值似乎是更简单的方法,并且由于持久性提供程序的内部优化可能会提供更好的性能。
- 重新考虑您在获取记录时设置的悲观锁。这也会阻止对该记录(以及同一页上可能的其他记录)的所有读取操作,直到事务结束。乐观锁通常提供更好的可扩展性。
建议 2 和 3 是一般最佳做法。我们需要更广泛地审视整个用例和应用程序的其他部分,以做出明智的决定
在这种情况下,我需要在执行货币操作减法的字段中执行更新。该列创建为 DECIMAL(19,2) UNSIGNED
.
首先我得到值:
static final String LOCK_AMOUNT_FOR_UPDATED = "select amount from Sample where uuid = :uuid for update ";
这是存储库:
@Query(value = LOCK_AMOUNT_FOR_UPDATED, nativeQuery = true)
Float getAmountForUpdate(@Param("uuid") String uuid);
这里是第一题,不是返回Float。 建议返回一个 BigDecimal?
然后我检查值并执行更新:
static final String DECREASE_AMOUNT = "update Sample set amount = amount - :amountToSubtract where uuid = :uuid ";
存储库:
@Modifying
@Query(value = DECREASE_AMOUNT, nativeQuery = true)
void decreaseAmount(@Param("amountToSubtract") Float amountNegotiated, @Param("uuid") String uuid);
当值为:1927369.70
时执行此操作。我得到:
Data truncation: Out of range value for column 'amount' at row 1
方法调用是这样的:
repository.decreaseNetAmount(amountNegotiated.floatValue(), uuid);
我注意到当我 select 值和我在 BigDecimal 中调用 .floatValue()
时 1927369.70
变成了 1927369.80
。
将所有内容都用作 BigDecimal 的正确方法是什么,甚至是 nativeQuery 的参数?
我会推荐给:
- 对参数和实体属性使用 BigDecimal(如果您决定使用 BigDecimal)。
- 重新考虑为什么要使用本机查询来更新单个记录。获取实体对象并更改属性的值似乎是更简单的方法,并且由于持久性提供程序的内部优化可能会提供更好的性能。
- 重新考虑您在获取记录时设置的悲观锁。这也会阻止对该记录(以及同一页上可能的其他记录)的所有读取操作,直到事务结束。乐观锁通常提供更好的可扩展性。
建议 2 和 3 是一般最佳做法。我们需要更广泛地审视整个用例和应用程序的其他部分,以做出明智的决定