将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。也有同样的结果。
有人知道为什么通过驱动程序进行舍入工作会有所不同吗?是否有任何设置使其像控制台一样?
答案 0 :(得分:4)
这是因为二进制浮点的性质,这就是你在double
中使用的(在Java中)。
最接近36.7875的double
的完全值
36.7867499999999978399500832892954349517822265625
这将被舍入到36.7867。而最接近36.78750001的double
的精确值
36.786750000099999624580959789454936981201171875
这将被四舍五入到36.7878。这就是你得到这种行为的原因。控制台可能将输入视为十进制数而不是转换为二进制浮点数。
如果确切的十进制数字对您很重要,您可能不应该使用二进制浮点类型 - 请改用BigDecimal
。
你应该考虑你的价值代表什么。如果它是一个物理连续值,如身高,长度或重量,那么使用double
可能是合适的 - 但你不应该对这样的情况感到困惑。如果它是具有离散(基于十进制)值的人工构造,例如货币值,那么您绝对应该使用BigDecimal
,或者只是缩放整数。