How to use IN OUT parameter in Oracle stored procedure with spring-jdbc?

Thiagarajan Ramanathan :

In my stored procedure, I have four parameters. One of the parameters has both IN and OUT. I am facing issues while accessing parameter with IN and Out.

In normal approach (using CallableStatement) I am able to fetch the results. I am facing this issue when using CallableStatementCreatorFactory (using this to avoid Sonarqube issue). I am looking for a solution using CallableStatementCreatorFactory. I cannot make any change in the stored procedure.

Procedure

PROCEDURE SOMENAME (
applicationname           IN     VARCHAR2,
username                  IN OUT VARCHAR2,
sessionid                 IN     VARCHAR2 DEFAULT NULL,
usertype                  OUT    VARCHAR2,

Spring boot Code

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);

When I add an additional '? 'in the query, I get the following exception:

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

When I uncomment the following line I get the following issue (removed additional question mark):

callableStatementCreatorFactory.addParameter(new SqlOutParameter("USERNAME", OracleTypes.VARCHAR)); 

Exception

org.springframework.jdbc.InvalidResultSetAccessException: CallableStatementCallback; invalid ResultSet access for SQL [{call TEST.PKG.SOMENAME(?,?,?,?)}]; nested exception is java.sql.SQLException: Invalid column index

When I uncomment the following line I get the following error:

userModel.setUserName(callableStatement.getString(TWO));  (after commenting previous line and removing one addtional ?)

Exception

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
Luke Woodward :

Your parameter is an IN OUT parameter so you should use a SqlInOutParameter for it.

Replace the line

    callableStatementCreatorFactory.addParameter(new SqlParameter("USERNAME", OracleTypes.VARCHAR));

with

    callableStatementCreatorFactory.addParameter(new SqlInOutParameter("USERNAME", OracleTypes.VARCHAR));

Don't add the extra ?, there are four parameters to the stored procedure.

Delete the commented-out line that tries to create a SqlOutParameter for USERNAME. However, you should be able to uncomment the line

    //userModel.setUserName(callableStatement.getString(2));  - throwing issue

and use this line to read the username that you get back from the database.

I made these modifications to your code and was able to use it to call a procedure with the same signature as yours and read data back from the procedure.

Incidentally, don't close the statement within the CallableStatementCallback: I found that this causes an exception because Spring will do other stuff with the statement after you've finished with it, but it can't do this if you've closed the statement. Spring will close the statement when it has finished with it. One of the benefits of using Spring to do JDBC is that it handles a lot of the tedious boilerplate stuff like this.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=134824&siteId=1