调用返回BOOLEAN的PL/SQL函数报SQL错误[17004]求助
解决Spring JDBC调用Oracle PL/SQL BOOLEAN函数的17004错误
你遇到的Type de colonne non valide: 1111(无效列类型1111)错误,核心原因是JDBC规范本身不支持Oracle PL/SQL的BOOLEAN类型,Oracle JDBC驱动无法直接映射这个类型到Java的Boolean,再加上你的Java代码获取返回值的方式完全错误,导致了这个异常。
问题拆解
- PL/SQL BOOLEAN的JDBC兼容性问题:JDBC没有将BOOLEAN定义为标准SQL类型,Oracle的PL/SQL BOOLEAN属于数据库内部专属类型,JDBC驱动无法直接识别处理。
- Java代码的逻辑错误:你尝试通过
cs.getResultSet().toString()获取返回值,但这个函数返回的是单个BOOLEAN值,不是结果集,这种获取方式完全不符合函数调用的逻辑。
解决方案
这里提供两种可靠的解决方式,你可以根据实际场景选择:
方案一:修改PL/SQL函数,返回JDBC兼容类型(推荐)
把PL/SQL函数的返回类型从BOOLEAN改为NUMBER,用1代表TRUE,0代表FALSE,这样JDBC可以直接处理该类型:
FUNCTION F_IsDemandeDeLitFromHosp(i_NoMvtHosp IN MVTHOSP.NOMVTHOSP%TYPE )RETURN NUMBER IS v_Found NUMBER := 0; BEGIN BEGIN SELECT COUNT(1) INTO v_Found FROM ICSF.T_DEMANDE_LIT D, MVTUS U, MVTHOSP H WHERE H.NOMVTHOSP = i_NoMvtHosp AND H.NOMVTHOSP = U.NOMVTHOSP AND U.NOMVTUS = D.NOMVTUS AND U.RANG <> '0000000000' AND H.RANG = '0000100000' AND NVL (D.ETAT, ' ') <> 'X' AND NVL (U.ETAT, ' ') <> 'X' AND NVL (H.ETAT, ' ') <> 'X' AND ROWNUM = 1; EXCEPTION WHEN OTHERS THEN RETURN 0; END; RETURN CASE WHEN v_Found > 0 THEN 1 ELSE 0 END; END F_IsDemandeDeLitFromHosp;
同步修改Java代码,获取返回的数值并转为Boolean:
@Override public DemandeDeLitFromHospit isDemandeDelitFromHosp(String noMvtHosp) { final ProcedureRequest request = new ProcedureRequest( PK.GET_IS_DEMANDE_DE_LIT_FROM_HOSP.getPackageName(), PK.GET_IS_DEMANDE_DE_LIT_FROM_HOSP.getMethodeName() ); request.addInParam("i_NoMvtHosp", noMvtHosp); // 注册输出参数为JDBC支持的NUMERIC类型 request.addOutParam("return", Types.NUMERIC); DemandeDeLitFromHospit demande = new DemandeDeLitFromHospit(); Integer result = (Integer) callFunction(request, new CallableStatementCallback<Integer>() { public Integer doInCallableStatement(CallableStatement cs) throws SQLException { cs.execute(); // 函数返回值对应第一个输出参数 return cs.getInt(1); } }); demande.setIsDemandeDeLitFromHosp(result != null && result == 1); return demande; }
方案二:不修改PL/SQL,使用Oracle特定API处理
如果你无法修改PL/SQL函数,可以使用Oracle官方JDBC驱动提供的OracleCallableStatement来处理BOOLEAN类型:
@Override public DemandeDeLitFromHospit isDemandeDelitFromHosp(String noMvtHosp) { final ProcedureRequest request = new ProcedureRequest( PK.GET_IS_DEMANDE_DE_LIT_FROM_HOSP.getPackageName(), PK.GET_IS_DEMANDE_DE_LIT_FROM_HOSP.getMethodeName() ); request.addInParam("i_NoMvtHosp", noMvtHosp); DemandeDeLitFromHospit demande = new DemandeDeLitFromHospit(); Boolean result = callFunction(request, new CallableStatementCallback<Boolean>() { public Boolean doInCallableStatement(CallableStatement cs) throws SQLException { // 转换为Oracle专属的CallableStatement OracleCallableStatement ocs = (OracleCallableStatement) cs; // 注册输出参数为Oracle的BOOLEAN类型 ocs.registerOutParameter(1, OracleTypes.BOOLEAN); ocs.execute(); // 获取布尔返回值 return ocs.getBoolean(1); } }); demande.setIsDemandeDeLitFromHosp(result != null && result); return demande; }
关键注意事项
- PL/SQL函数的返回值是通过输出参数传递的,不要尝试从
getResultSet()获取,这是针对查询语句的方法。 - JDBC不支持PL/SQL BOOLEAN是核心矛盾,要么修改PL/SQL兼容JDBC,要么使用Oracle专属API绕开限制。
内容的提问来源于stack exchange,提问作者guicontat
相关产品推荐
相关产品推荐

