google半天,没找到有人写者方面的,我就开个头吧。有不对的地方还请大侠们拍砖。
要点其实很简单,就是把在declareParameter时要先声明返回结果集参数,再声明input参数。
先看看程序吧:
Sybase 存储过程
[code]
IF OBJECT_ID('dbo.sp_xx') IS NOT NULL
BEGIN
DROP PROCEDURE dbo.sp_xx
IF OBJECT_ID('dbo.sp_xx') IS NOT NULL
PRINT '<<< FAILED DROPPING PROCEDURE dbo.sp_xx >>>'
ELSE
PRINT '<<< DROPPED PROCEDURE dbo.sp_xx >>>'
END
go
create proc sp_xx ( @userid int)
as
begin
select personid, personname from person where personid = @userid
select teamid, teamname from team
end
EXEC sp_procxmode 'dbo.sp_xx','unchained'
go
[/code]
正确的java调用程序如下
[code]
private class ProcWithResultSet extends StoredProcedure
{
public ProcWithResultSet(DataSource dataSource)
{
setDataSource(dataSource);
setSql("sp_xx");
//declareParameter(new SqlParameter("userid", java.sql.Types.INTEGER)); //(1)
//declare the first out param in the sp, the name rsPerson is the key of result map
declareParameter(new SqlReturnResultSet("rsPerson", new PersonRowMapper()));
//declare the second out param in the sp, the name rsTeam is the key of result map
declareParameter(new SqlReturnResultSet("rsTeam", new TeamRowMapper()));
//declare input params, the name userid is the IN params of the param
declareParameter(new SqlParameter("userid", java.sql.Types.INTEGER)); //(2)
compile();
}
public Map getRsFromSP(int userID)
{
Map map = new HashMap();
map.put("userid", new Integer(userID));
return execute(map);
}
}
private class PersonRowMapper implements RowMapper
{
public Object mapRow(ResultSet rs, int rowNum) throws SQLException
{
UserInfo u = new UserInfo();
u.setPersonID(rs.getInt(1));
u.setUserName(rs.getString(2));
return u;
}
}
private class TeamRowMapper implements RowMapper
{
public Object mapRow(ResultSet rs, int rowNum) throws SQLException
{
return new PropertyValue(rs.getInt(1)+"", rs.getString(2));
}
}
[/code]
Spring中对于jdbc 调用带有返回结果集的存储过程是用的这个方法。
[code]
/**
* Extract returned ResultSets from the completed stored procedure.
* @param cs JDBC wrapper for the stored procedure
* @param parameters Parameter list for the stored procedure
* @return Map that contains returned results
*/
protected Map extractReturnedResultSets(CallableStatement cs, List parameters, int updateCount)
throws SQLException {
Map returnedResults = new HashMap();
int rsIndex = 0;
boolean moreResults;
do {
if (updateCount == -1) { //(3)
Object param = null;
if (parameters != null && parameters.size() > rsIndex) {
param = parameters.get(rsIndex); //(4)
}
if (param instanceof SqlReturnResultSet) {
SqlReturnResultSet rsParam = (SqlReturnResultSet) param;
returnedResults.putAll(processResultSet(cs.getResultSet(), rsParam)); //(5)
}
else {
logger.warn("Results returned from stored procedure but a corresponding " +
"SqlOutParameter/SqlReturnResultSet parameter was not declared");
}
rsIndex++;
}
moreResults = cs.getMoreResults(); //(6)
updateCount = cs.getUpdateCount();
if (logger.isDebugEnabled()) {
logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
}
}
while (moreResults || updateCount != -1);
return returnedResults;
}
[/code]
[color=blue]
原因分析:
1:Sybase不支持Out 参数返回结果集。只能再Sp当中最后select column from some table
2:Sybase的JDBC Driver对于jdbc的实现比较令人费解,如果一个Sp返回多个结果集,如果不调用第一个结果集即statement.getResultSet()
那么接下来statementcs.getMoreResults()会返回False,即使有有第二个返回结果集,它一样返回false,那么Spring就会把返回结果认为是一个update的
结果,就不会对其它结果集进行处理。
3:Spring中如果jdbc返回结果集,那么程序会执行到(3)处,这里rsIndex = 0,如果输入参数声明在先,那么这里得到的将会是输入参数,
(5)处的cs.getResultSet()将不会被执行,第一个ResultSet不会被处理,同时,因为(5)处没有被执行,那么(6)处会返回false,也就是解下来
的结果集不会被正确的认出来,Spring也不会去处理后续的结果集,这样就一个结果集也得不到了。
4:这里主要还是Sybase jdbcDriver在实现jdbc时有bug,但是我们只能顺着人家来,在用Spring Jdbctemplate调用时注意一下了。
[/color]
要点其实很简单,就是把在declareParameter时要先声明返回结果集参数,再声明input参数。
先看看程序吧:
Sybase 存储过程
[code]
IF OBJECT_ID('dbo.sp_xx') IS NOT NULL
BEGIN
DROP PROCEDURE dbo.sp_xx
IF OBJECT_ID('dbo.sp_xx') IS NOT NULL
PRINT '<<< FAILED DROPPING PROCEDURE dbo.sp_xx >>>'
ELSE
PRINT '<<< DROPPED PROCEDURE dbo.sp_xx >>>'
END
go
create proc sp_xx ( @userid int)
as
begin
select personid, personname from person where personid = @userid
select teamid, teamname from team
end
EXEC sp_procxmode 'dbo.sp_xx','unchained'
go
[/code]
正确的java调用程序如下
[code]
private class ProcWithResultSet extends StoredProcedure
{
public ProcWithResultSet(DataSource dataSource)
{
setDataSource(dataSource);
setSql("sp_xx");
//declareParameter(new SqlParameter("userid", java.sql.Types.INTEGER)); //(1)
//declare the first out param in the sp, the name rsPerson is the key of result map
declareParameter(new SqlReturnResultSet("rsPerson", new PersonRowMapper()));
//declare the second out param in the sp, the name rsTeam is the key of result map
declareParameter(new SqlReturnResultSet("rsTeam", new TeamRowMapper()));
//declare input params, the name userid is the IN params of the param
declareParameter(new SqlParameter("userid", java.sql.Types.INTEGER)); //(2)
compile();
}
public Map getRsFromSP(int userID)
{
Map map = new HashMap();
map.put("userid", new Integer(userID));
return execute(map);
}
}
private class PersonRowMapper implements RowMapper
{
public Object mapRow(ResultSet rs, int rowNum) throws SQLException
{
UserInfo u = new UserInfo();
u.setPersonID(rs.getInt(1));
u.setUserName(rs.getString(2));
return u;
}
}
private class TeamRowMapper implements RowMapper
{
public Object mapRow(ResultSet rs, int rowNum) throws SQLException
{
return new PropertyValue(rs.getInt(1)+"", rs.getString(2));
}
}
[/code]
Spring中对于jdbc 调用带有返回结果集的存储过程是用的这个方法。
[code]
/**
* Extract returned ResultSets from the completed stored procedure.
* @param cs JDBC wrapper for the stored procedure
* @param parameters Parameter list for the stored procedure
* @return Map that contains returned results
*/
protected Map extractReturnedResultSets(CallableStatement cs, List parameters, int updateCount)
throws SQLException {
Map returnedResults = new HashMap();
int rsIndex = 0;
boolean moreResults;
do {
if (updateCount == -1) { //(3)
Object param = null;
if (parameters != null && parameters.size() > rsIndex) {
param = parameters.get(rsIndex); //(4)
}
if (param instanceof SqlReturnResultSet) {
SqlReturnResultSet rsParam = (SqlReturnResultSet) param;
returnedResults.putAll(processResultSet(cs.getResultSet(), rsParam)); //(5)
}
else {
logger.warn("Results returned from stored procedure but a corresponding " +
"SqlOutParameter/SqlReturnResultSet parameter was not declared");
}
rsIndex++;
}
moreResults = cs.getMoreResults(); //(6)
updateCount = cs.getUpdateCount();
if (logger.isDebugEnabled()) {
logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
}
}
while (moreResults || updateCount != -1);
return returnedResults;
}
[/code]
[color=blue]
原因分析:
1:Sybase不支持Out 参数返回结果集。只能再Sp当中最后select column from some table
2:Sybase的JDBC Driver对于jdbc的实现比较令人费解,如果一个Sp返回多个结果集,如果不调用第一个结果集即statement.getResultSet()
那么接下来statementcs.getMoreResults()会返回False,即使有有第二个返回结果集,它一样返回false,那么Spring就会把返回结果认为是一个update的
结果,就不会对其它结果集进行处理。
3:Spring中如果jdbc返回结果集,那么程序会执行到(3)处,这里rsIndex = 0,如果输入参数声明在先,那么这里得到的将会是输入参数,
(5)处的cs.getResultSet()将不会被执行,第一个ResultSet不会被处理,同时,因为(5)处没有被执行,那么(6)处会返回false,也就是解下来
的结果集不会被正确的认出来,Spring也不会去处理后续的结果集,这样就一个结果集也得不到了。
4:这里主要还是Sybase jdbcDriver在实现jdbc时有bug,但是我们只能顺着人家来,在用Spring Jdbctemplate调用时注意一下了。
[/color]