【发布时间】:2015-01-09 08:38:59
【问题描述】:
我将 PostgreSql 9.3 与 postgresql-9.3-1101 JDBC 驱动程序一起使用。
PreparedStatements 有一个非常奇怪的行为。
这是一个例子: 首先我创建一个测试表:
CREATE TABLE double_test
(
id numeric(18) NOT NULL
);
之后我运行以下代码:
DecimalFormat df = new DecimalFormat("0");
try {
conn = BeanUtils.getBean("dataSource", DataSource.class).getConnection();
conn.setAutoCommit(false);
conn.createStatement().execute("DELETE from double_test ");
conn.commit();
PreparedStatement stmt = conn.prepareStatement("INSERT INTO double_test (id )VALUES (?)");
double input = 1234567890123456d;
System.out.println("Input:" + df.format(input));
stmt.setDouble(1, input);
stmt.execute();
conn.commit();
ResultSet rs = conn.createStatement().executeQuery("SELECT id FROM double_test ");
rs.next();
System.out.println("Output:" + df.format(rs.getDouble(1)));
rs.close();
} catch (SQLException e1) {
throw new RuntimeException(e1);
} finally {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
代码的输出将是:
Input: 1234567890123456
Output:1234567890123460
这让我很困惑,在 15 位之后,Postgres JDBC 驱动程序开始四舍五入。插入的数据已损坏,恕不另行通知!
我在这里错过了什么吗?我的代码有错误吗?
或者这是驱动程序中的错误?如果是这样,我真的很想知道还没有人注意到这一点。
也许使用BigDecimal 可以防止数据损坏,但这只是一种解决方法。
【问题讨论】:
-
使用
BigDecimal不是一种“解决方法”,它是处理numeric列的正确方法。double是一个近似数据类型:floating-point-gui.de -
@a_horse_with_no_name 但他/她将一个
double放入,并取出另一个。 -
@a_horse_with_no_name 肯定都是浮点值的近似值,但我们不是在讨论小数点的四舍五入。它只是削减 15. 数字之后的值并用零填充它。只需在示例中添加数字,您就会看到。
-
@Orism
1234567890123456只是0.1234567890123456E16的简写,浮点数将在其有效部分四舍五入,而PostgreSQL 的numeric不会对其值进行四舍五入。这就是为什么您应该选择客户端的表示,它不适用四舍五入。 -
事实是,如果您希望它以一致的方式正确执行,您必须使用
BigDecimal,正如@a_horse_with_no_name 已经指出的那样。
标签: java postgresql jdbc