Esta es el arreglo más exacta que te podemos aportar, pero primero mírala pausadamente y analiza si es compatible a tu trabajo.
Solución:
Después de renunciar a esta pregunta y simplemente pasar todos los parámetros, incluidos los opcionales, me encontré con su incapacidad para pasar argumentos booleanos, porque booleano no es un tipo de datos SQL, solo PL/SQL.
Entonces, mi solución actual es que JDBC no es adecuado para ejecutar procedimientos almacenados y así es como lo soluciono:
jdbcTemplate.execute(
new CallableStatementCreator()
public CallableStatement createCallableStatement(Connection con) throws SQLException
CallableStatement cs = con.prepareCall("call sys.dbms_stats.gather_table_stats(ownname=>user, tabname=>'" + cachedMetadataTableName + "', estimate_percent=>20, method_opt=>'FOR ALL COLUMNS SIZE 1', degree=>0, granularity=>'AUTO', cascade=>TRUE, no_invalidate=>FALSE, force=>FALSE) ");
return cs;
,
new CallableStatementCallback()
public Object doInCallableStatement(CallableStatement cs) throws SQLException
cs.execute();
return null; // Whatever is returned here is returned from the jdbcTemplate.execute method
);
Se me ocurrió una solución decente para esto hoy, que hace frente a los no-null por defecto, y no utiliza técnicas de reflexión afrutada. Funciona al crear el contexto de metadatos para la función externamente para recuperar todos los tipos de parámetros, etc., y luego construir el SimpleJdbcCall manualmente a partir de eso.
Primero, crea un CallMetaDataContext para la función:
CallMetaDataContext context = new CallMetaDataContext();
context.setFunction(true);
context.setSchemaName(schemaName);
context.setProcedureName(functionName);
context.initializeMetaData(jdbcTemplate.getDataSource());
context.processParameters(Collections.emptyList());
A continuación, cree SimpleJdbcCall, pero oblíguelo a que no realice su propia búsqueda de metadatos:
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate);
// This forces the call object to skip metadata lookup, which is the part that forces all parameters
simpleJdbcCall.setAccessCallParameterMetaData(false);
// Now go back to our previously created context and pull the parameters we need from it
simpleJdbcCall.addDeclaredParameter(context.getCallParameters().get(0));
for (int i = 0; i < params.length; ++i)
simpleJdbcCall.addDeclaredParameter(context.getCallParameters().get(i));
// Call the function and retrieve the result
Map resultsMap = simpleJdbcCall
.withSchemaName(schemaName)
.withFunctionName(functionName)
.execute(params);
Object returnValue = resultsMap.get(context.getScalarOutParameterName());
Encontré una solución para mi caso con SimpleJdbcCall y Spring 5.2.1, Java 8, Oracle 12.
Necesitas:
- Utilizar .sinProcedimientoColumnaMetaDataAccess()
- Utilizar .withNamedBinding()
- Declare los parámetros que conoce en .declareParameters() llamada. El procedimiento se llamará solo con parámetros, declarados en este método. Los parámetros predeterminados, que no desea configurar, no están escribiendo aquí.
La llamada de ejemplo está abajo
final String dataParamName = "P_DATA";
final String ageParamName = "P_AGE";
final String genderParamName = "P_GENDER";
final String acceptedParamName = "P_ACCEPTED";
SimpleJdbcCall simpleJdbcCall = new SimpleJdbcCall(getJdbcTemplate())
.withCatalogName("PKG_USER")
.withProcedureName("USER_CHECK")
.withoutProcedureColumnMetaDataAccess()
.withNamedBinding()
.declareParameters(
new SqlParameter(dataParamName, OracleTypes.VARCHAR),
new SqlParameter(ageParamName, OracleTypes.NUMBER),
new SqlParameter(genderParamName, OracleTypes.VARCHAR),
new SqlOutParameter(acceptedParamName, OracleTypes.NUMBER)
);
SqlParameterSource parameterSource = new MapSqlParameterSource()
.addValue(dataParamName, data)
.addValue(ageParamName, age)
.addValue(genderParamName, gender);
Map out = simpleJdbcCall.execute(parameterSource);
Reseñas y puntuaciones del artículo
No se te olvide dar visibilidad a este enunciado si te ayudó.