设为首页 收藏本站
查看: 695|回复: 0

[经验分享] Spring调用Oracle存储过程结果小集

[复制链接]
YunVN网友  发表于 2016-8-14 07:12:32 |阅读模式
oracle 对于高级特性总是和众不同(我极力讨厌这一点,如果使用他的产品就要对这种产品进行特定的编程,这也是我从不看好weblogic之类的平台的原因),大对象存取一要定用他自己的LOB对象,所幸我还能通过LONG RAW来代替。以便能使程式不必特定的编码。但对于存储过程(我是说返回结果集的存储过程),我还没有什么方法能用一个通用的程式来处理ORACLE.太多的教材或文章在讲存储过程的调用只是不负责任地简单执行一些涵数或无结果返回的存储过程,使大多数读者根本不知道到底怎么调用存储过程的结果集。而在Spring中,根本就没有真正完全地介绍对存储过程的结果集的处理,更别说象oracle这种"特别"的存储过程的结果集处理。
  
  
  先来简单看一下我们怎么在JDBC中处理存储过程的结果集的通用流程:
  
  1.获取CallableStatement语句:
  
  CallableStatement cs = conn.prepareCall("{call spName(?,?,?)}");
  
  2.传入输入参数和注册输出参数
  
  cs.setXXX(index,value);//输入参数
  
  cs.registerOutParameter(index,type);//输出参数
  
  3.执行存储过程:
  
  cs.execute();
  
  对于一个存诸过程,如果返回的结果是我们预先知道的,那么能根据存储过程定义的顺序来进行处理(事实上一般不会这样),但对于复杂的多结果集的处理,怎么定义一个通用的流程?
中国网管论坛


  
  我们先看一下JDBC本身能为我们提供什么?
  
  一个存储过程执行后返回的是boolean型:
  
  boolean flag = callableStatement.execute();
  
  如果flag为true,那么说明返回了一个结果集(ResultSet)类型,你能用getResultSet()得到当前行所在的结果,而如果返回为flase,说明什么呢?
  
  如果你不进行处理,什么也不能说明,只能说明当前指针不是ResultSet,有可能是更新计数(updateCount)也可能什么也没有反因。
  
  那么如果当前指针为flase时怎么处理?我们应该先getUpdateCount();如果返回-1,既不是结果集,又不是更新计数了。说明没的返回了。而如果getUpdateCount()返回0或大于0,则说明当前指针是更新计数(0的时候有可能是DDL指令)。无论是返回结果集或是更新计数,那么则可能还继续有其他返回。只有在当前指指针getResultSet()==null && getUpdateCount() == -1才说明没有再多的返回。
  
  存储过程的返回和ResultSet类似,每次处理的返回结果相当于是ResultSet的Row,只不过存储过程的Row最先在第一行而不是象ResultSet要先next才到第一行,存储过程向下移动一行用getMoreResults(),相当于ResultSet的next()。同样他返回boolean和上面的flag相同,只是说明当前行是不是ResultSet,如果是flase,你还是要判断是不是updateCount,在每一行,都要先同时判断是否为ResultSet还是UpdateCount,如果是其中一种则要继续getMoreResults(),当不是ResultSet也不是updateCount时,说明没有返回结果了,这时再获取输出参数。
www.bitsCN.com


  
  看明白了吗?
  
  那我们就根据上面的规则来写一个通用的流程吧:
  
  首先,我们要确定什么时候没说结果集了:
  
  if(cs.getResultSet() == null && cs.getUpdateCount() == -1)
  
  目前我们做一个循环:
  
  ResultSet rs = null;
  
  int updateCount = -1;
  
  flag = cs.execute();
  
  do{
  
  updateCount = cs.getUpdateCount();
  
  if(updateCount != -1){//说明当前行是个更新计数
  
  //处理.
  
  cs.getMoreResults();
  
  continue;//已是更新计数了,处理完成后应该移动到下一行
  
  //不再判断是否是ResultSet
  
  }
  
  rs = cs.getResultSet();
  
  if(rs != null){//如果到了这里,说明updateCount == -1
  
  //处理rs
  
  cs.getMoreResults();
  
  continue;
  
  //是结果集,处理完成后应该移动到下一行
  
  }
  
  //如果到了这里,说明updateCount == -1 && rs == null,什么也没的了
  
  }while(!(updateCount == -1 && rs == null)); bbs.bitsCN.com
  
  cs.getXXX(int);//获取输出参数
  
  以上是对于通用的存储过程返回的结果集的处理,而oracle,他不能返回结果集,只能在输出参数中返回一个cursor,所以通用的流程中你获取不到所有结果:
  
  package PK_AREA_PUBLIC is
  
  TYPE serarch_result IS REF CURSOR;
  
  PROCEDURE area_search(vTarget_in IN VARCHAR2 ,cur_result_out OUT serarch_result) ;
  
  end PK_AREA_PUBLIC;
  
  package body PK_AREA_PUBLIC is
  
  PROCEDURE area_search(vTarget_in IN VARCHAR2 ,cur_result_out OUT serarch_result)
  
  IS
  
  sqlstr VARCHAR2(1000);
  
  BEGIN
  
  sqlstr:=’select .................................’;
  
  OPEN cur_result_out FOR sqlstr USING vTarget_in;
  
  END area_search;
  
  end PK_AREA_PUBLIC;
  
  对于上面的例子,存储过程有一个输入参数,一个输出参数,我们要接受输出参数作为结果集处理.所以注册的时候应该注册为:
  
  cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);//输出参数 bitsCN.nET中国网管博客
  
  这样在存储过程执行后,获取输出数造型为ResultSet就能处理:
  
  ResultSet rs = (ResultSet)cs.getObject(2);
  
  如果有多个结果集就用多个输出参数.
  
  明白了ORACLE的特别性,我们再看看在spring中如果处理他的存储过程的结果集:
  
  spring在处理复杂对象的时候,大都采用回调的方法,需求程式员自己实现接口方法。也就是他提供了程式运行时的参数,需求你自己对这些参数进行处理。对于JdbcTemplate,他在非常多地方提供了ResultSet参数供程式员处理。在Spring文件中提供了对于通用流程,也就是从存储过程执行结果中获取结果集的
  
  例程:
  
  Map out = execute(new HashMap());
  
  其实他是默认实现了上面JDBC通用流程中对ResuleSet到Map的封装.而对于Oracle,我们就必须自己手实现对输出参数中ResultSet的回调:
  
  public class SpringStoredProcedure
  
  extends StoredProcedure {
  
  public ArrayList<HashMap> set = new ArrayList<HashMap>();
  
  //声明一个用于接收结果集的数据结构,其中的元素为row,用map存放private Map inParam;//输入参数 中国网管联盟
  
  private RowMapper rm = new RowMapper(){
  
  public Object mapRow(ResultSet rs,int rowNum) throws SQLException{
  
  return null;//不用从存储过程本身获取结果
  
  }
  
  };
  
  private RowMapperResultReader callback = new RowMapperResultReader(rm ){
  
  public void processRow(ResultSet rs) //回调处理
  
  throws SQLException{
  
  int count = rs.getMetaData().getColumnCount();
  
  String[] header = new String[count];
  
  for(int i=0;i<count;i++)
  
  header = rs.getMetaData().getColumnName(i+1);
  
  while(rs.next()){
  
  HashMap<String,String> row = new HashMap(count+7);
  
  for(int i=0;i<count;i++)
  
  row.put(header,rs.getString(i+1));
  
  set.add(row);
  
  }
  
  }
  
  }; //RowMapperResultReader作为输出参数的回调句柄
  
  public SpringStoredProcedure(DataSource ds, String SQL) { 中国网管联盟
  
  setDataSource(ds);
  
  setSql(SQL);
  
  }
  
  public void setOutParameter(String column,int type){
  
  declareParameter(new SqlOutParameter(column, type,callback));
  
  //利用回调句柄注册输出参数
  
  }
  
  public void setParameter(String column,int type){
  
  declareParameter(new SqlParameter(column, type));
  
  }
  
  public void SetInParam(Map inParam){
  
  this.inParam = inParam;
  
  }
  
  public Map execute() {
  
  compile();
  
  return execute(this.inParam);
  
  }
  
  }
  
  下面我们看一下调用过程:
  
  DriverManagerDataSource ds = .......;
  
  SpringStoredProcedure sp = new SpringStoredProcedure(ds,"PK_AREA_PUBLIC.area_search");
  
  //注册参数类型,输入参数和输出参数同时注册,否则不能正确编译存储过程
  
  sp.setParameter("vTarget_in",java.sql.Types.VARCHAR); www_bitscn_com
  
  sp.setOutParameter("cur_result_out",oracle.jdbc.OracleTypes.CURSOR);
  
  sp.compile();
  
  //传入输入参数值
  
  Map in = new HashMap();
  
  in.put("vTarget_in","一个内容");
  
  sp

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-257451-1-1.html 上篇帖子: 查询oracle表的信息(表,字段,约束,索引) 下篇帖子: Oracle数据库单个或多字段排序
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表