ZhangLiHai.Com Blog


ORACLE存储过程返回多结果集的解决方案

张利海 于 2005年04月29日 14:56 发表
关键词 : ORACLE 存储过程 PL/SQL

 我们知道,ORACLE存储过程(以下简称SP)本身连单结果集都不能返回,只能通过输出参数返回cursor引用.对于一次查询多个结果集,则要注册多个输出参数.


但是很多时候我们并不知道一次查询要返回多少个结果集.而ORACLE的SP又不支持变长参数,如果一次从十多个表中查询结果集,则客户端要和服务端交互十几次,这是一个极大的浪费.我在一个新项目的有需要根据一个ID去十多个表中取相应数据的需求.于是采用了职下方案:

用java写SP,这一点,并不是我看不起PL/SQL,JAVA的运算能力绝对比PL/SQL强N倍,比竟它是一门非常完善的编程语言,用它写SP可以做你想做的任何事.而且用JAVA写SP调试非常方便:

public class SPClass{
   public static String test(){return "hello!";}//必须是静态方法
}

这样一个java文件或类或多个jar文件可以非常方便地用loadjava命令加载到oracle数据库中,然后只要

create or replace function [procedure] test return varchar2 as language java name 'SPClass.test() return java.lang.String'; 就可以加载这个过程或函数.
关键是你create一个function[procedure]后,如果你想修改它你只要修改源文件并重新用 loadjava命令回载到数据库中,而不需要再在SQLPLUS环境下重新create or replace function [procedure] ,非常的方便.

基于上面的应用,我在JAVA方法中根据输入的参数,用ORACLE内置的连结获取数据后封装在 OracleCachedRowSet中,然后多个OracleCachedRowSet以参数传入的表名为key,放在一个HashMap中,将这个 HashMap序列化后base64编码,返回成String.
这样客户端获取base64字符串后decode成byte[] 返序列化成HashMap,然后根据传入的表名获取相应的OracleCachedRowSet,一次交互可以获取到多个结果集:

import oracle.jdbc.driver.*;
import oracle.jdbc.rowset.*;
import java.sql.*;
import java.util.*;
import java.io.*;

/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: </p>
 *
 * @author not attributable
 * @version 1.0
 */
public class MultiResultSet {
  public static String getMultiResultSet(String args,String multiType,int page)
      throws SQLException {
    try{
      String[] params = split(args,",");
      HashMap rt = new HashMap();
      for(int i=0;i<params.length;i++){
        OracleCachedRowSet rowset = new OracleCachedRowSet();
        rowset.setUrl("jdbc:default:connection");
//      rowset.setUsername("");
//      rowset.setPassword("");
        String sql = "select * from " + params[i] ;
        rowset.setCommand(sql);
        rowset.execute();
        rt.put(params[i],rowset.createCopy());
      }
      ByteArrayOutputStream ba = new ByteArrayOutputStream();
      ObjectOutputStream out = new ObjectOutputStream(ba);
      out.writeObject(rt);
      byte[] buf = ba.toByteArray();
      out.flush();
      out.close();
      return new sun.misc.BASE64Encoder().encode(buf);
    }
    catch(Exception e){
      return e.getMessage();
    }
  }
  public static String[] split(String strOb, String mark) {
    if (strOb == null) {
      return null;
    }
    StringTokenizer st = new StringTokenizer(strOb, mark);
    ArrayList tmp = new ArrayList();
    while (st.hasMoreTokens()) {
      tmp.add(st.nextToken());
    }
    String[] strArr = new String[tmp.size()];
    for (int i = 0; i < tmp.size(); i++) {
      strArr[i] = (String) tmp.get(i);
    }
    return strArr;
  }
}


客户机器测试:


import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.Types;
import java.util.HashMap;
import java.util.Iterator;

import sun.misc.BASE64Decoder;

/**
 * <P>Title:</P>
 *  <P>Description:</P>
 * @author : cheung
 * @version : 1.0
 * @date : 2005-4-28
 * @homepage : <a href="http://www.zhanglihai.com" target="_blank">ZhangLiHai.Com </a>
 * @email : <a href="mailto:zhanglihai.com@gmail.com">zhanglihai.com@gmail.com </a>
 */
public class ResultSetTest {

    /**
     *
     */
    public ResultSetTest() {
        super();
    }

    public void test() {
        long startTime = System.currentTimeMillis();
        Connection con = null;
        try {
            con = getConnection();
            CallableStatement cs = con.prepareCall("{? = call GetTest(?,?,?)}");
            cs.registerOutParameter(1, Types.VARCHAR);
            cs.setString(2, "copyright,filetype");
            cs.setString(3, "test");
            cs.setInt(4, 1);
            cs.execute();

            String temps = cs.getString(1);
            // System.out.println(temps);
            byte[] buf = new BASE64Decoder().decodeBuffer(temps);

            ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(buf));
            HashMap map = (HashMap) input.readObject();
            Iterator keys = map.keySet().iterator();
            Object key = null;
            oracle.jdbc.rowset.OracleCachedRowSet value = null;
            while (keys.hasNext()) {
                key = keys.next();
                System.out.println("key : " + key + " value : " + map.get(key));
            }
            System.out.println("usedTime : " + (System.currentTimeMillis() - startTime) + " ms.");

        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        } finally {
            try {
                con.close();
            } catch (Exception ex) {
            }
        }
    }

    public Connection getConnection() throws Exception {
        
       //构造你的Connection,或者用DataSource来实现
        return con;

    }

    public static void main(String[] args) {
        ResultSetTest test = new ResultSetTest();
        test.test();

    }
}


以上方案在台式机上测试,取两个表,记录都在五百多条左右.时间在60-120ms之间.这种方案适用于根据某一ID获取不同表中数据,但数据量不大,如果数据量很大,上万条记录最好不要用CachedRowSet.

转载:http://www.cnjbb.org/thread.jsp?boardid=23&threadid=44518&pageno=last#lastpost



新版本Blog中有更多内容
Copyright (C)2002-2005 All Rights Reserved Powered By:ZhangLiHai.Com