Hibernate HQL转PostgreSQL SQL时类型转换异常及精度问题咨询
HQL转SQL类型转换问题解答(Hibernate 5.6.15.Final + PostgreSQL JDBC 42.7.4)
问题场景
用户执行如下HQL语句:
SELECT CAST(a * 100000000 as big_integer) FROM Amount WHERE id = :id
生成的SQL却带有两位小数:
prepareStatement( "select cast(amount0_.\"a\"*100000000 as numeric(19, 2)) from \"AMOUNT\" where amount0_.\"id\"=?");
同时存在另外两个疑问:
- HQL中CAST为Long类型,生成SQL为int8(用户认为Long范围大于int8)
- HQL中CAST为Double类型,生成SQL为float8(用户认为Double精度高于float8)
核心疑问:为何生成带两位小数的numeric(19,2)?
根源在于原始字段a的类型配置:如果实体类中a字段是BigDecimal且指定了scale=2(对应数据库的numeric(19,2)),Hibernate在处理乘法运算时会保留原始类型的精度,运算结果仍为numeric(19,2)。后续CAST为big_integer时,Hibernate 5.6版本的PostgreSQL Jakarta方言会优先匹配与源类型精度一致的SQL类型,而非直接映射为PostgreSQL的BIGINT。
解决办法:
- 改用
java.lang.Long作为HQL的CAST目标类型:CAST(a * 100000000 as java.lang.Long),强制Hibernate生成BIGINT类型 - 自定义PostgreSQL方言,覆盖
BigIntegerType的SQL类型映射为BIGINT
问题1:CAST为Long生成int8是正常行为
PostgreSQL的int8就是64位大整数(官方别名BIGINT),其取值范围(-9223372036854775808 ~ 9223372036854775807)与Java的Long完全一致。Hibernate只是使用了PostgreSQL的原生类型别名,不存在范围不足的问题。
问题2:CAST为Double生成float8是正确映射
PostgreSQL的float8是64位双精度浮点数(别名DOUBLE PRECISION),对应Java的Double类型;而float4才是32位单精度浮点数(对应Java的Float)。Hibernate生成float8完全匹配Double的精度要求,不存在精度损失问题。
内容的提问来源于stack exchange,提问作者Grim
相关产品推荐
相关产品推荐

