日期:2014-05-16  浏览次数:20506 次

使用Spring jdbc template调用Sybase带有返回结果集的储存过程-要点
google半天,没找到有人写者方面的,我就开个头吧。有不对的地方还请大侠们拍砖。
要点其实很简单,就是把在declareParameter时要先声明返回结果集参数,再声明input参数。

先看看程序吧:
Sybase 存储过程
  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

正确的java调用程序如下
    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));
  		}	
    }

Spring中对于jdbc 调用带有返回结果集的存储过程是用的这个方法。
  /**
	 * 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;
	}



原因分析:
1:Sybase不支持Out 参数返回结果集。只能再Sp当中最后select column from some table
2:Sybase的JDBC Driver对于jdbc的实现比较令人费解,如果一个Sp返回多个结果集,如果不调用第一个结果集即statement.getResultSet()
那么接下来statementcs.getMoreResults()会返回F