En mi procedimiento almacenado, tengo cuatro parámetros. Uno de los parámetros tiene tanto dentro como fuera. Estoy frente a los problemas mientras se accede a los parámetros de entrada y salida.
En el enfoque normal (usando CallableStatement) Soy capaz de obtener los resultados. Estoy frente a este problema cuando se utiliza CallableStatementCreatorFactory (utilizando este tema para evitar sonarqube). Busco a una solución utilizando CallableStatementCreatorFactory. No puedo hacer ningún cambio en el procedimiento almacenado.
Procedimiento
PROCEDURE SOMENAME (
applicationname IN VARCHAR2,
username IN OUT VARCHAR2,
sessionid IN VARCHAR2 DEFAULT NULL,
usertype OUT VARCHAR2,
Código de inicio de primavera
public static final String STORED_PROCEDURE_SOME_NAME = "{call TEST.PKG.SOMENAME(?,?,?,?)}";
CallableStatementCreatorFactory callableStatementCreatorFactory = new CallableStatementCreatorFactory(STORED_PROCEDURE_SOME_NAME);
callableStatementCreatorFactory.addParameter(new SqlParameter("APPLICATIONNAME", OracleTypes.VARCHAR));
callableStatementCreatorFactory.addParameter(new SqlParameter("USERNAME", OracleTypes.VARCHAR));
callableStatementCreatorFactory.addParameter(new SqlParameter("sessionid", OracleTypes.VARCHAR));
//callableStatementCreatorFactory.addParameter(new SqlOutParameter("USERNAME", OracleTypes.VARCHAR)); - throwing issue
callableStatementCreatorFactory.addParameter(new SqlOutParameter("usertype", OracleTypes.VARCHAR));
final Map<String, Object> param = new HashMap<>();
param.put("APPLICATIONNAME", applicationName);
param.put("USERNAME", userName);
param.put("sessionid", sessionGuid);
CallableStatementCallback<User> callableStatementCallback = new CallableStatementCallback<User>()
{
@Override
public User doInCallableStatement(CallableStatement callableStatement) throws SQLException
{
try
{
callableStatement.execute();
User userModel = new User();
//userModel.setUserName(callableStatement.getString(2)); - throwing issue
userModel.setUserType(callableStatement.getString(4));
return populateUser(callableStatement);
}
finally
{
try
{
callableStatement.close();
}
catch (SQLException e)
{
LOGGER.error(MESSAGE_ERROR_CALLABLESTATEMENT_CLOSE, e);
}
}
}
};
CallableStatementCreator callableStatementCreator = callableStatementCreatorFactory.newCallableStatementCreator(param);
userModel = jdbcTemplate.execute(callableStatementCreator, callableStatementCallback);
Al agregar un adicional '? 'En la consulta, me sale el siguiente excepción:
org.springframework.jdbc.BadSqlGrammarException: CallableStatementCallback; bad SQL grammar [{call TEST.PKG.SOMENAME(?,?,?,?,?)}]; nested exception is java.sql.SQLException: ORA-06550: line 1, column 7:
PLS-00306: wrong number or types of arguments in call to 'SOMENAME'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
Cuando elimine la línea siguiente me sale el siguiente tema (eliminado signo de interrogación adicional):
callableStatementCreatorFactory.addParameter(new SqlOutParameter("USERNAME", OracleTypes.VARCHAR));
Excepción
org.springframework.jdbc.InvalidResultSetAccessException: CallableStatementCallback; invalid ResultSet access for SQL [{call TEST.PKG.SOMENAME(?,?,?,?)}]; nested exception is java.sql.SQLException: Invalid column index
Cuando habilite la línea siguiente me sale el siguiente error:
userModel.setUserName(callableStatement.getString(TWO)); (after commenting previous line and removing one addtional ?)
Excepción
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback; uncategorized SQLException for SQL [{call TEST.PKG.SOMENAME(?,?,?,?)}]; SQL state [99999]; error code [17021]; Missing defines; nested exception is java.sql.SQLException: Missing defines
Su parámetro es un IN OUT
parámetro de lo que debe utilizar una SqlInOutParameter
para él.
Vuelva a colocar la línea
callableStatementCreatorFactory.addParameter(new SqlParameter("USERNAME", OracleTypes.VARCHAR));
con
callableStatementCreatorFactory.addParameter(new SqlInOutParameter("USERNAME", OracleTypes.VARCHAR));
No añadir el extra ?
, hay cuatro parámetros al procedimiento almacenado.
Eliminar la línea comentada, que intenta crear una SqlOutParameter
para USERNAME
. Sin embargo, usted debe ser capaz de comentar la línea
//userModel.setUserName(callableStatement.getString(2)); - throwing issue
y utilizar esta línea para leer el nombre de usuario que vuelva de la base de datos.
Hice estas modificaciones a su código y era capaz de utilizarlo para llamar a un procedimiento con la misma firma que la suya y vuelve a leer los datos del procedimiento.
Por cierto, no cierre la declaración dentro del CallableStatementCallback
: He encontrado que esto provoca una excepción porque la primavera va a hacer otras cosas con la declaración después de que haya terminado con él, pero no puedo hacer esto si ha cerrado el comunicado. Primavera cerrará la declaración cuando haya terminado con él. Uno de los beneficios del uso de la primavera a hacer JDBC es que maneja una gran cantidad de las cosas repetitivo tedioso como este.