【问题标题】:What's the correct approach for monetary operations with JPA + MySQL?使用 JPA + MySQL 进行货币操作的正确方法是什么?
【发布时间】:2021-05-18 15:03:51
【问题描述】:

在这种情况下,我需要在执行货币操作减法的字段中执行更新。该列被创建为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);

我注意到,当我选择值以及在 BigDecimal 中调用 .floatValue() 时,1927369.70 变成了 1927369.80

将所有内容都用作 BigDecimal 的正确方法是什么,甚至是 nativeQuery 的参数?

【问题讨论】:

    标签: jpa spring-data-jpa spring-data bigdecimal


    【解决方案1】:

    我建议:

    1. 对参数和实体属性使用 BigDecimal(如果您决定使用 BigDecimal)。
    2. 重新考虑为什么要使用本机查询来更新单个记录。获取实体对象并更改属性值似乎是更简单的方法,并且由于持久性提供程序的内部优化,可能会提供更好的性能。
    3. 重新考虑您在获取记录时设置的悲观锁。这也会阻止对该记录(以及同一页面上可能的其他记录)的所有读取操作,直到事务结束。乐观锁通常提供更好的可扩展性。

    建议 2 和 3 是一般的最佳做法。我们需要更广泛地审视整个用例和应用程序的其他部分,以做出明智的决定

    【讨论】:

      猜你喜欢
      • 2014-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-23
      • 2012-10-15
      • 2023-03-15
      • 1970-01-01
      相关资源
      最近更新 更多