【问题标题】:PreparedStatement, float values and postgresqlPreparedStatement、浮点值和 postgresql
【发布时间】:2020-09-24 02:57:42
【问题描述】:

为什么使用 setFloat 的 PreparedStatement 会给出与直接 INSERT 不同的结果(精度较低)?

下面的代码显示了这个问题:

    Connection conn = createConnection();

/* here works as expected */
    String sql = "INSERT INTO teste values (1, -50.505050)";
    PreparedStatement ps = conn.prepareStatement(sql);
    ps.executeUpdate();

/* below, all values were saved with less precision */
    sql = "INSERT INTO teste values (?, ?)";
    ps = conn.prepareStatement(sql);

    ps.setInt(1, 2);
    ps.setFloat(2, -50.505050f);
    ps.executeUpdate();

    ps.setInt(1, 3);
    ps.setFloat(2, (float) -50.505050);
    ps.executeUpdate();

    ps.setInt(1, 4);
    ps.setFloat(2, Float.valueOf(-50.505050f));
    ps.executeUpdate();

    ps.setInt(1, 5);
    ps.setFloat(2, Float.valueOf("-50.505050"));
    ps.executeUpdate();

// with double works ok, but how? //
    ps.setInt(1, 6);
    ps.setDouble(2, -50.505050);
    ps.executeUpdate();

    ps.close();
    conn.close();

数据库是 PostgreSQL,有两列,id (bigint) 和 valor (numeric (9,6))。

这是来自 pgadmin4 的输出。

pom.xml 中唯一相关的依赖如下:

    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.2.8</version>
    </dependency>

我用于创建表的脚本。

CREATE TABLE public.teste
(
    id bigint NOT NULL,
    valor numeric(9,6),
    CONSTRAINT teste_pkey PRIMARY KEY (id)
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE public.teste
    OWNER to postgres;

我正在使用 Java 11。

【问题讨论】:

  • 感谢您的建议,我刚刚加入了。
  • 为什么要尝试使用浮点数据类型将值插入精确的数字列?使用BigDecimal会更合适,如果真的需要使用浮点类型,使用double,而不是float
  • 我不知道浮点类型 (java) 的小精度。 BigDecimal 对我来说也是新的。感谢您的提示!

标签: java database postgresql jdbc prepared-statement


【解决方案1】:

floatfrom 6 to 9 significant decimal digits precision
doublefrom 15 to 17 significant decimal digits precision
-50.505050 是 8 位数字,这超出了 float 可以处理的限制。

如果你打印出来,你可以自己看看。

System.out.printf("%.6f%n", -50.505050f);
System.out.println(new BigDecimal(-50.505050f));
System.out.println(new BigDecimal(-50.505050d));

输出

-50.505051
-50.5050506591796875
-50.5050499999999971123543218709528446197509765625

数据库类型numeric(9,6) 应该在Java 中存储为BigDecimal。或者,可以使用 double,但 float 没有存储此类值所需的有效十进制数字精度。

除非您严重受到 Java 内存的限制(非常罕见),否则永远不要使用 float。仅保证 6 位精度,根本没有用/不可靠,所以不要使用它。

【讨论】:

  • 谢谢。从现在开始我将使用双倍。我不明白:如果 float 可以处理 6 位精度,为什么 -50.505050 不起作用?
  • @LucianoBrum 因为它是一个 8 位数字。请注意,6-9 有效小数位精度是总位数,而不仅仅是小数点右侧的小数位。
猜你喜欢
  • 2017-04-04
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多