【问题标题】:How to store BigDecimal like 13.50 in DB using JPA (EclipseLink)?如何使用 JPA(EclipseLink)将 BigDecimal(如 13.50)存储在 DB 中?
【发布时间】:2020-07-16 14:56:58
【问题描述】:

我想使用 JPA (EclipseLink) 在数据库中存储一笔钱,比如说 13.50。

我将该字段声明为

private BigDecimal amout;

没有进一步的注释。此字段在 Sybase DB 中创建为 NUMERIC

当我在数据库中存储BigDecimal.valueOf(13.50D) 时,我只在数据库字段中得到 13,00。缺少 0.50 个。

该列也支持 13.50,我可以手动输入。 我应该怎么做才能将 13.50 写入数据库字段?是否需要调整 BigDecimal 值或 / 是否需要为列设置任何精度注释?

为了让问题更清楚,这里有一些代码sn-ps。

这是 DDL:

CREATE TABLE "DBA"."BUCH" (
    "PNR" INTEGER NOT NULL DEFAULT AUTOINCREMENT,
    "AMOUNT" NUMERIC(38,2) NOT NULL,
    PRIMARY KEY ( "PNR" ASC )
) IN "system";

这是实体

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@Entity
@ToString
@EqualsAndHashCode
@Table(name = "BUCH")
public class Buch {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int pnr;

    @Column(nullable = false, precision = 4, scale = 2))
    private BigDecimal amount;

    public Buch() {
        // JPA
    }
}

这是对它的测试

@Test
public void test()  {

    Buch b = new Buch();
    
    BigDecimal amount = new BigDecimal("13.50");
    b.setAmount(amount);
    assertThat(b.getAmount(), is(new BigDecimal("13.50")));

    EntityManager em = createEntityManager();
    em.getTransaction().begin();
    em.persist(b);
    em.flush();
    em.getTransaction().commit();
    em.close();

    List<Buch> allBuch = BuchDAO.getInstance().findAll();
    assertThat(allBuch.size(), is(1));

    Buch buch = allBuch.get(0);

    assertThat(buch.getAmount(), is(new BigDecimal("13.50")));

}

这是测试结果

java.lang.AssertionError: 
Expected: is <13.50>
     got: <13,00>

【问题讨论】:

  • 原则上您输入的代码似乎没问题,您可以尝试将值初始化为 BigDecimal.valueOf (12.50);只有当它不起作用时,才将这段代码放在初始化实体的位置(或转换它的位置)以及持久化对象的方法。问候
  • 顺便说一句,BigDecimal.valueOf( 12.50D ) 之类的代码是错误的使用BigDecimal 的方式。传递double 意味着您已经引入了inaccuracy of a floating-point type,从而阻碍了使用BigDecimal 的目的。改为传递StringBigDecimal.valueOf( "12.50D" )
  • 列的确切类型是什么,在某些数据库中,只有 NUMERIC 将具有特定于实现的精度和比例 0(尽管对于Sybase),这意味着它只接受整数。要接受 12.50,该列需要是 - 例如 - NUMERIC(9, 2)。在任何情况下,拥有minimal reproducible example 会很有帮助,包括数据库架构和您的 Java 代码。
  • 打开日志记录,检查数据库中的实际内容,以确定输入或值的回读是否存在问题。

标签: java jpa eclipselink


【解决方案1】:

DECIMAL 引用the documentationNUMERIC 与 Sybase 中的DECIMAL 相同)...

一个有符号的十进制数,具有精确的总位数和小数点后的位数。精度可以等于 1 到 126,小数位可以等于 0 到精度值。

因此,0 表示仅有效整数,小数部分为零。

默认值是比例 = 38 和精度 = 126。

默认值对于您的数据示例来说当然足够了。

根据列的实际数据类型计算结果以确保准确性,但您可以使用 MAX_CLIENT_NUMERIC_SCALE 选项设置返回给应用程序的结果的最大比例。

所以你应该在我们的数据库中检查两件事:

  • 为您的列定义设置的精度和小数位数。
  • MAX_CLIENT_NUMERIC_SCALE 选项的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-15
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 2012-04-04
    • 2011-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多