控制台和JDBC中的十进制截断/舍入差异

时间:2013-02-20 07:07:09

标签: java sql-server tsql jdbc rounding-error

将double值插入到具有一些小数精度的数据库表时,我遇到了问题。我使用的是MS SQL Server 10.0.4000版 下面是一个带十进制列的示例表,其中包含4位小数。

create table test (
test decimal (18,4))

当我通过MSSQL控制台插入值“36.78675”时,它将舍入为36.7868,因为该字段仅为4位小数。这可以。

DECLARE @T DECIMAL(18, 5)

SET @T = 36.78675

insert into test values(@T)

select * from test

但是当我通过我的java代码(MS SQL JDBC驱动程序)执行等效插入(使用预处理语句)时,数据存储在表36.7867中。如果我有一个类似36.786750001的值,则控制台和JDBC都将轮到36.7868。 我使用的java对象是double。我用双值调用setDouble()。在这里它会自动选择数据类型。但是还有另一种JDBC方法,它采用对象和数据类型。使用这个,我测试了DECIMAL和FLOAT类型。所有人都给出相同的结果。我甚至将jdbc驱动程序更改为I-net。也有同样的结果。

有人知道为什么通过驱动程序进行舍入工作会有所不同吗?是否有任何设置使其像控制台一样?

1 个答案:

答案 0 :(得分:4)

这是因为二进制浮点的性质,这就是你在double中使用的(在Java中)。

最接近36.7875的double完全

36.7867499999999978399500832892954349517822265625

这将被舍入到36.7867。而最接近36.78750001的double精确

36.786750000099999624580959789454936981201171875

这将被四舍五入到36.7878。这就是你得到这种行为的原因。控制台可能将输入视为十进制数而不是转换为二进制浮点数。

如果确切的十进制数字对您很重要,您可能不应该使用二进制浮点类型 - 请改用BigDecimal

你应该考虑你的价值代表什么。如果它是一个物理连续值,如身高,长度或重量,那么使用double可能是合适的 - 但你不应该对这样的情况感到困惑。如果它是具有离散(基于十进制)值的人工构造,例如货币值,那么您绝对应该使用BigDecimal,或者只是缩放整数。