诗剑书生的专栏

我在灌江口上住,花开花落,不知流年度.雁过空遗秋色暮,抚琴细听梧桐雨. 轻舞残虹漫展书,云卷云舒,思愫万千缕.安得婵娟与共处,长作识字耕田夫.                   诗剑书生 于灌江口.听潮居

用户操作
[即时聊天] [发私信] [加为好友]
诗剑书生ID:axman
108824次访问,排名817好友0人,关注者16
一个男人. 一个写程序男人. 一个写程序并从程序中寻找快乐的男人. 一个写程序并从程序中寻找快乐又把快乐传递给大家的男人.
一个书生. 一个寂寞的书生. 一个寂寞的梅香竹影下敲声写韵的书生. 一个寂寞的梅香竹影下敲声写韵晨钟暮鼓中逸气扬剑的书生.
那个男人是位书生。没有人知道他的姓名,居无定所,行无定踪,亦耕亦读,或渔或樵。
axman的文章
原创 87 篇
翻译 0 篇
转载 0 篇
评论 161 篇
axman的公告
最近评论
ZangXT:醍醐灌顶
matay:能不能把这个打包mms的工程源代码共享一下?万分感谢!
mataym@gmail.com
axman:不用说明什么,一切都如我预料的那样.
在整个奥运开幕式期间,我一边看电视,一边访问
http://www.cctvolympics.com/main.php?type=vod这个地址,其间访问一百多次,没有一次成功.大多数时候是前端缓存的squid在报refuse(111).有时以过几分钟的等待,能出来页面,但Flash缓冲的进度条到了99%就一直停止在那儿.
……
myvicc:写得不错,等写下文
chinagavin:我是先读三位正向输出,然后再读三位反向输出来最终达到想要的结果。
文章分类
收藏
    相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Spring 调用ORACLE存储过程的结果收藏

    新一篇: 常见的几个数据库insert into操作的主键返回值 | 旧一篇: DataSource高级应用

    Spring 调用ORACLE存储过程的结果

    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();

    4.处理结果集.具体请参见前面的文章

    以上是对于通用的存储过程返回的结果集的处理,而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);//输出参数

    这样在存储过程执行后,获取输出数造型为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[i] = 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[i],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);
        sp.setOutParameter("cur_result_out",oracle.jdbc.OracleTypes.CURSOR);
        sp.compile();
        
        //传入输入参数值
        Map in = new HashMap();
        in.put("vTarget_in","一个内容");
        sp.SetInParam(in);
        
        //执行存储过程
        sp.execute();

        Map m = sp.set.get(0);//ReultSet的第一条记录
                  //set定义为SpringStoredProcedure的属性用于接收回调时的数据
                  //如果有多个输出参数,应该在每个输出参数的回调方法中生成该输出
                  //参数对应的ArrayList,然后加到一个成员变量的数据结构中.
        Iterator i = m.keySet().iterator();
        while(i.hasNext()){
          String key = i.next().toString();
          System.out.println(key + "=>" + m.get(key));
        }

      总之,上面的方法虽然解决了Spring中对Oracle存储过程的调用,但我极力不推荐这程复杂的处理
     

    发表于 @ 2006年07月07日 08:26:00|评论(loading...)|编辑

    新一篇: 常见的几个数据库insert into操作的主键返回值 | 旧一篇: DataSource高级应用

    评论

    #args 发表于2006-08-05 20:27:00  IP: 211.94.130.*
    请问
    HashMap<String,String> row = new HashMap(count+7);
    +7是啥意思呢? 谢谢
    #axman 发表于2006-08-07 11:07:00  IP: 61.186.85.*
    new HashMap(count+7);
    HashMap你可以不加初始大小,它会自动扩展.但这里每行的column是固定的,相对固定可以节省自动扩展时运算的时间.

    +7是一般根据column大小来做的装填因数,只是一个相对估计而已.
    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © axman