【问题标题】:How to use IN OUT parameter in Oracle stored procedure with spring-jdbc?如何在带有 spring-jdbc 的 Oracle 存储过程中使用 IN OUT 参数?
【发布时间】:2019-04-26 08:19:07
【问题描述】:

在我的存储过程中,我有四个参数。其中一个参数同时具有 IN 和 OUT。我在使用 IN 和 Out 访问参数时遇到问题。

在正常方法中(使用 CallableStatement)我能够获取结果。我在使用 CallableStatementCreatorFactory 时遇到了这个问题(使用它来避免 Sonarqube 问题)。我正在寻找使用 CallableStatementCreatorFactory 的解决方案。我无法对存储过程进行任何更改。

程序

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

Spring 启动代码

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

当我添加一个额外的 '? '在查询中,我得到以下异常:

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

当我取消注释以下行时,我收到以下问题(删除了额外的问号):

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

例外

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

当我取消注释以下行时,我收到以下错误:

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

例外

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

【问题讨论】:

    标签: java spring oracle jdbc spring-jdbc


    【解决方案1】:

    您的参数是IN OUT 参数,因此您应该使用SqlInOutParameter

    换行

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

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

    不要添加额外的?,存储过程有四个参数。

    删除试图为USERNAME 创建SqlOutParameter 的注释行。但是,您应该可以取消注释该行

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

    并使用此行读取您从数据库中返回的用户名。

    我对您的代码进行了这些修改,并且能够使用它来调用与您具有相同签名的过程并从该过程中读回数据。

    顺便说一句,不要关闭CallableStatementCallback中的语句:我发现这会导致异常,因为Spring会在你完成后对语句做其他事情,但如果你这样做,它就不能这样做'已经关闭了声明。 Spring 将在它完成后关闭该语句。使用 Spring 执行 JDBC 的好处之一是它可以处理很多像这样乏味的样板文件。

    【讨论】:

    • 谢谢@Luke Woodward。您提供的解决方案效果很好。你拯救了我的一天。再次感谢您。
    猜你喜欢
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    • 2012-04-18
    • 2020-09-22
    • 2015-01-07
    • 1970-01-01
    • 2011-07-29
    • 2013-04-24
    相关资源
    最近更新 更多