如何在spring-jdbc的Oracle存储过程中使用IN OUT参数?
How to use IN OUT parameter in Oracle stored procedure with spring-jdbc?
在我的存储过程中,我有四个参数。其中一个参数同时具有 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
您的参数是 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 的好处之一是它可以处理很多像这样的乏味样板文件。
在我的存储过程中,我有四个参数。其中一个参数同时具有 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
您的参数是 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 的好处之一是它可以处理很多像这样的乏味样板文件。