`
fengpeng
  • 浏览: 99330 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用Spring jdbc template调用Sybase带有返回结果集的储存过程-要点

阅读更多
关键字: Spring   spring    

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

先看看程序吧:
Sybase 存储过程

代码
  1. IF OBJECT_ID('dbo.sp_xx') IS NOT NULL   
  2. BEGIN   
  3.     DROP PROCEDURE dbo.sp_xx   
  4.     IF OBJECT_ID('dbo.sp_xx') IS NOT NULL   
  5.         PRINT '<<< FAILED DROPPING PROCEDURE dbo.sp_xx >>>'   
  6.     ELSE   
  7.         PRINT '<<< DROPPED PROCEDURE dbo.sp_xx >>>'   
  8. END   
  9. go   
  10. create proc sp_xx ( @userid int)    
  11. as   
  12. begin   
  13.     select personid, personname from person where personid = @userid  
  14.        
  15.     select teamid, teamname from team   
  16. end   
  17.   
  18. EXEC sp_procxmode 'dbo.sp_xx','unchained'   
  19. go   
<script>render_code();</script>
正确的java调用程序如下
代码
  1. private class ProcWithResultSet extends StoredProcedure   
  2. {   
  3.     public ProcWithResultSet(DataSource dataSource)   
  4.     {   
  5.         setDataSource(dataSource);   
  6.         setSql("sp_xx");   
  7.                
  8.         //declareParameter(new SqlParameter("userid", java.sql.Types.INTEGER));              //(1)   
  9.         //declare the first out param in the sp, the name rsPerson is the key of result map   
  10.         declareParameter(new SqlReturnResultSet("rsPerson"new PersonRowMapper()));   
  11.         //declare the second out param in the sp, the name rsTeam is the key of result map   
  12.         declareParameter(new SqlReturnResultSet("rsTeam"new TeamRowMapper()));   
  13.     //declare input params, the name userid is the IN params of the param   
  14.         declareParameter(new SqlParameter("userid", java.sql.Types.INTEGER));                //(2)   
  15.            
  16.         compile();   
  17.     }   
  18.        
  19.     public Map getRsFromSP(int userID)   
  20.     {   
  21.            
  22.         Map map = new HashMap();   
  23.         map.put("userid"new Integer(userID));   
  24.         return execute(map);   
  25.     }   
  26. }   
  27.   
  28. private class PersonRowMapper implements RowMapper    
  29. {   
  30. public Object mapRow(ResultSet rs, int rowNum) throws SQLException   
  31. {   
  32.     UserInfo u = new UserInfo();   
  33.     u.setPersonID(rs.getInt(1));   
  34.     u.setUserName(rs.getString(2));   
  35.     return u;   
  36. }   
  37. }   
  38. private class TeamRowMapper implements RowMapper    
  39. {   
  40. public Object mapRow(ResultSet rs, int rowNum) throws SQLException   
  41. {   
  42.     return new PropertyValue(rs.getInt(1)+"", rs.getString(2));   
  43. }      
  44. }   
<script>render_code();</script>
Spring中对于jdbc 调用带有返回结果集的存储过程是用的这个方法。
代码
  1.  /**  
  2.  * Extract returned ResultSets from the completed stored procedure.  
  3.  * @param cs JDBC wrapper for the stored procedure  
  4.  * @param parameters Parameter list for the stored procedure  
  5.  * @return Map that contains returned results  
  6.  */  
  7. protected Map extractReturnedResultSets(CallableStatement cs, List parameters, int updateCount)   
  8.         throws SQLException {   
  9.   
  10.     Map returnedResults = new HashMap();   
  11.     int rsIndex = 0;             
  12.     boolean moreResults;   
  13.     do {   
  14.         if (updateCount == -1) {                 //(3)   
  15.             Object param = null;   
  16.             if (parameters != null && parameters.size() > rsIndex) {   
  17.                 param = parameters.get(rsIndex);     //(4)   
  18.             }   
  19.             if (param instanceof SqlReturnResultSet) {   
  20.                 SqlReturnResultSet rsParam = (SqlReturnResultSet) param;   
  21.                 returnedResults.putAll(processResultSet(cs.getResultSet(), rsParam)); //(5)   
  22.             }   
  23.             else {   
  24.                 logger.warn("Results returned from stored procedure but a corresponding " +   
  25.                         "SqlOutParameter/SqlReturnResultSet parameter was not declared");   
  26.             }   
  27.             rsIndex++;   
  28.         }   
  29.         moreResults = cs.getMoreResults();           //(6)   
  30.         updateCount = cs.getUpdateCount();   
  31.         if (logger.isDebugEnabled()) {   
  32.             logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);   
  33.         }   
  34.     }   
  35.     while (moreResults || updateCount != -1);   
  36.     return returnedResults;   
  37. }   
<script>render_code();</script>

 


原因分析:
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调用时注意一下了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics