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

如何通过SimpleJdbcCall调用返回TABLE_NAME%rowtype的Oracle函数

解决SimpleJdbcCall调用返回TABLE_NAME%ROWTYPE的Oracle函数问题

问题场景

要通过Spring的SimpleJdbcCall调用Oracle包中返回TABLE_NAME%ROWTYPE类型的函数,函数定义如下:

function getOneRowFromTbale( applicationId in integer )
return table_name%rowtype;

首次尝试与报错

调用代码:

public VerificationRequest getLastVerificationRequest(Integer applicationId) {
    simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)
            .withCatalogName("pkg_NAME")
            .withFunctionName("getOneRowFromTable");
    return simpleJdbcCall.executeFunction(VerificationRequest.class, new MapSqlParameterSource()
            .addValue("applicationId", applicationId));
}

触发错误:

org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{? = call pkg_NAME.getOneRowFromTable(?)}]; SQL state [99999]; error code [17004]; Invalid column type: 1111; nested exception is java.sql.SQLException: Invalid column type: 1111

二次调整与报错

修改后的代码:

public VerificationRequest getLastVerificationRequest(Integer applicationId) {
    simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)
            .withCatalogName("pkg_NAME")
            .withFunctionName("getOneRowFromTable")
            .declareParameters(
                    new SqlParameter(
                            "applicationId",
                            OracleTypes.NUMBER
                    ),
                    new SqlInOutParameter(
                            "result",
                            OracleTypes.STRUCT
                    )
            );
    Map<String, Object> out =  simpleJdbcCall.execute(new MapSqlParameterSource()
            .addValue("applicationId", applicationId));
    return (VerificationRequest) out.get("result");
}

仍报错:

org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{? = call pkg_NAME.getOneRowFromTable(?)}]; SQL state [99999]; error code [17068]; Invalid argument(s) in call; nested exception is java.sql.SQLException: Invalid argument(s) in call

解决方案

核心原因

Oracle的TABLE_NAME%ROWTYPE属于匿名STRUCT类型,Spring无法自动识别并完成映射,必须手动指定STRUCT的具体类型名称,同时配置对应的类型处理器。

步骤1:确认STRUCT类型名称

TABLE_NAME%ROWTYPE对应数据库内的系统生成类型名,可通过以下SQL查询获取:

SELECT type_name FROM user_types WHERE type_code = 'OBJECT';

通常这类名称为TABLE_NAME_ROWTYPE,也可直接查看表相关元数据确认。

步骤2:修改SimpleJdbcCall配置

这里提供两种可行的配置写法:

写法一:使用SqlOutParameter指定类型与映射器

public VerificationRequest getLastVerificationRequest(Integer applicationId) {
    // 替换为你查询到的实际STRUCT类型名
    String rowTypeName = "TABLE_NAME_ROWTYPE";

    SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)
            .withCatalogName("pkg_NAME")
            .withFunctionName("getOneRowFromTable")
            .declareParameters(
                    new SqlParameter("applicationId", OracleTypes.NUMBER),
                    // 指定STRUCT类型名,并用BeanPropertyRowMapper自动映射字段
                    new SqlOutParameter("result", OracleTypes.STRUCT, rowTypeName,
                            new BeanPropertyRowMapper<>(VerificationRequest.class))
            );

    Map<String, Object> resultMap = simpleJdbcCall.execute(
            new MapSqlParameterSource().addValue("applicationId", applicationId)
    );

    return (VerificationRequest) resultMap.get("result");
}

写法二:使用SqlReturnStruct手动处理映射

public VerificationRequest getLastVerificationRequest(Integer applicationId) {
    String rowTypeName = "TABLE_NAME_ROWTYPE";

    SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate)
            .withCatalogName("pkg_NAME")
            .withFunctionName("getOneRowFromTable")
            .declareParameters(new SqlParameter("applicationId", OracleTypes.NUMBER))
            // 注册返回值的STRUCT类型与实体类
            .declareParameters(new SqlReturnStruct(rowTypeName, VerificationRequest.class))
            .withReturnValue();

    Map<String, Object> resultMap = simpleJdbcCall.execute(
            new MapSqlParameterSource().addValue("applicationId", applicationId)
    );

    return (VerificationRequest) resultMap.get("result");
}

注意:如果数据库字段名和实体属性名不匹配,建议手动实现RowMapper完成字段映射,避免自动映射失败。

步骤3:可选优化——改用自定义OBJECT类型

如果觉得上述配置繁琐,可以修改Oracle函数,返回自定义OBJECT类型而非%ROWTYPE:

-- 先创建自定义对象类型
CREATE OR REPLACE TYPE verification_request_obj AS OBJECT (
    ID INTEGER,
    APPLICATION_ID INTEGER,
    -- 按表结构添加其他字段
);

-- 修改函数返回类型
function getOneRowFromTbale( applicationId in integer )
return verification_request_obj;

这种情况下,Spring的类型映射会更简单,直接将上述代码中的rowTypeName替换为verification_request_obj即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 16:55:27