You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate 6.x.x Oracle原生查询SUM计算字段丢失小数问题求助

解决方案

方案1:修改Oracle JDBC连接参数

在JDBC URL中添加oracle.jdbc.mapNumericToInt=false,禁用驱动自动将可转换为整数的数值类型映射为Java Integer类型。这是最便捷的方案,无需修改代码或SQL:

spring.datasource.url=jdbc:oracle:thin:@//your-oracle-host:1521/your-service?oracle.jdbc.mapNumericToInt=false

原理:Oracle JDBC驱动默认会把诸如39.74这类可被截断为整数的数值自动转成Integer,导致小数部分丢失。关闭该参数后,驱动会保留原始数值精度,返回BigDecimal类型。

方案2:自定义Hibernate类型贡献者

创建自定义类型处理SUM函数的返回值,强制映射为高精度数值类型:

  1. 编写类型贡献者类:
package com.yourpackage;

import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.descriptor.sql.DecimalTypeDescriptor;

public class OracleSumTypeContributor implements TypeContributor {
    @Override
    public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        // 注册针对SUM结果的自定义类型映射,强制使用NUMERIC类型
        typeContributions.contributeSqlTypeDescriptorOverride(
            new DecimalTypeDescriptor() {
                @Override
                public int getSqlType() {
                    return java.sql.Types.NUMERIC;
                }
            }
        );
    }
}
  1. 在Spring Boot配置中指定类型贡献者:
spring.jpa.properties.hibernate.type_contributors=com.yourpackage.OracleSumTypeContributor

原理:通过自定义SQL类型描述符,让Hibernate将SUM函数的结果识别为高精度的NUMERIC类型,避免被截断为整数。

方案3:使用TupleTransformer手动转换结果

在执行原生查询时,通过TupleTransformer手动转换返回值类型,修复被截断的数值:

import org.hibernate.query.TupleTransformer;
import jakarta.persistence.EntityManager;
import java.math.BigDecimal;
import java.math.RoundingMode;

// 业务代码中执行查询
EntityManager entityManager = ...; // 注入或获取EntityManager
BigDecimal result = (BigDecimal) entityManager.createNativeQuery("SELECT SUM(39.74) AS total FROM dual")
    .setTupleTransformer(new TupleTransformer<Object>() {
        @Override
        public Object transformTuple(Object[] tuple, String[] aliases) {
            if (tuple[0] instanceof Integer) {
                // 将截断的整数转换为带两位小数的BigDecimal
                return BigDecimal.valueOf((Integer) tuple[0]).divide(BigDecimal.ONE, 2, RoundingMode.HALF_UP);
            }
            return tuple[0];
        }
    })
    .getSingleResult();

原理:Hibernate 6推荐使用TupleTransformer替代旧的ResultTransformer,通过手动检查结果类型并转换,恢复丢失的小数部分。


内容的提问来源于stack exchange,提问作者Isaachjk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 04:28:21