`
haiyupeter
  • 浏览: 427402 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

JDBC与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();    
   
对于一个存诸过程,如果返回的结果是我们预先知道的,那么可以根据存储过程定义的顺序来进行处理(事实上一般不会这样),但对于复杂的多结果集的处理,如何定义一个通用的流

程?    
   
我们先看一下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时,说明没有返回结果了, 这时再获取输

出参数.    
   
看明白了吗?    
   
那我们就根据上面的规则来写一个通用的流程吧:    
   
首先,我们要确定什么时候没说结果集了:

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));    
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);//输出参数    
   
这样在存储过程执行后,获取输出数造型为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 set = new ArrayList();    
//声明一个用于接收结果集的数据结构,其中的元素为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    
     header[i] = rs.getMetaData().getColumnName(i+1);    
     while(rs.next()){    
     HashMap row = new HashMap(count+7);    
     for(int i=0;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));    
   }   

分享到:
评论
1 楼 high_java 2010-08-26  
请教一下,如果我用存储过程返回的是一个resultset,然而我想把它封装成为一个Beanlist返回给调用者。没有用spring等框架

相关推荐

    jdbc连接oracle,执行存储过程,带数据库存储过程

    执行Oracle存储过程主要涉及以下几个关键点: 1. 创建CallableStatement对象:使用Connection对象的`prepareCall()`方法创建CallableStatement实例,例如`CallableStatement cs = conn.prepareCall("{call procedure...

    用JDBC操作Oracle的存储过程返回值

    总的来说,使用JDBC操作Oracle的存储过程返回值涉及了JDBC的基本操作,包括加载驱动、建立连接、创建CallableStatement、设置参数、执行存储过程、获取返回值以及释放资源。理解这些步骤对于开发与Oracle数据库交互...

    oracle存储过程学习经典入门

    用 Java 调用 Oracle 存储过程时,需要使用 JDBC 驱动程序来连接 Oracle 数据库,然后使用 CallableStatement 对象来调用存储过程。 在存储过程中做简单动态查询 在存储过程中,做简单动态查询需要使用 EXECUTE ...

    Spring JdbcTemplate调用Oracle存储过程实现CRUD

    使用 Spring JdbcTemplate 调用 Oracle 存储过程实现 CRUD 在本文中,我们将讨论如何使用 Spring JdbcTemplate 调用 Oracle 存储过程来实现 CRUD(Create、Read、Update、Delete)操作。我们将首先编写 Oracle 存储...

    JDBC调用oracle存储过程.docx

    首先,我们需要了解如何创建Oracle存储过程。在示例中,我们看到了三种不同类型的存储过程: 1. **无返回值的存储过程**: 创建了一个名为`test_a`的存储过程,接受两个输入参数`param1`和`param2`,并将它们插入...

    oracle 存储过程 函数 dblink

    ### Oracle存储过程、函数与DBLink详解 #### 一、Oracle存储过程简介 在Oracle数据库中,存储过程是一种预编译好的SQL代码集合,它可以接受输入参数、返回单个值或多个值,并能够执行复杂的数据库操作。存储过程...

    springboot整合mybatis调用oracle存储过程

    本文将深入探讨如何在Spring Boot项目中整合MyBatis,实现调用Oracle存储过程并处理游标返回的数据。 首先,我们需要在Spring Boot项目中引入相关的依赖。在`pom.xml`文件中添加Oracle JDBC驱动(ojdbc66-oracle...

    Oracle存储过程返回结果集

    在Oracle存储过程中,`IN`参数用于传递数据到过程,`OUT`参数则允许过程向调用者返回数据。而`SYS_REFCURSOR`是Oracle提供的一种特殊类型,它允许存储过程动态地打开一个游标(即结果集)并将其作为`OUT`参数返回。 ...

    groovy将JDBC中oracle存储过程游标转换为多层json

    ### Groovy将JDBC中Oracle存储过程游标转换为多层JSON 在本文档中,我们将探讨如何使用Groovy脚本结合JDBC技术从Oracle存储过程中获取数据,并将其转换为多层JSON格式。该方法特别适用于需要从XML输入中提取数据并...

    java 与 oracle 存储过程

    Java与Oracle存储过程是数据库应用开发中的重要技术结合,它们在企业级系统中广泛使用,尤其是在数据处理和业务逻辑复杂的场景下。Oracle存储过程是一种在数据库服务器端编写的程序,可以包含一系列SQL语句和控制流...

    润乾报表调用oracle存储过程案例说明

    在实际的业务场景中,有时我们需要调用数据库中的存储过程来获取或处理数据,本篇将详细介绍如何在润乾报表中调用Oracle存储过程。 首先,我们要在Oracle数据库中创建存储过程。以下是一个简单的存储过程示例,名为...

    java调用oracle存储过程返回结果集,Record,cursor参照.pdf

    3. Java调用Oracle存储过程:Java程序可以通过JDBC来调用Oracle存储过程,获取结果集。 4. Type类型:Type类型是Oracle中的一种数据类型,用于定义复杂数据结构。 5. PACKAGE和PROCEDURE:PACKAGE和PROCEDURE是...

    Java链接Oracle 存储过程 jdbc BLOG

    总的来说,Java通过JDBC API调用Oracle存储过程涉及以下几个关键步骤:建立连接、定义存储过程调用字符串、设置参数、执行存储过程和处理结果。通过熟练掌握这些步骤,你可以轻松地在Java应用中集成和利用Oracle...

    oracle存储过程教程

    在Java开发中,Oracle存储过程常被用于后端数据库操作,与Java应用程序进行交互,实现业务逻辑。 首先,理解存储过程的概念是必要的。存储过程是一组预先编译的SQL语句,它们以函数的形式存储在数据库中,可以接受...

    Oracle存储过程、触发器

    Oracle存储过程和触发器是数据库管理系统中的重要组成部分,它们在数据处理和业务逻辑实现中扮演着关键角色。本文将深入探讨这两个概念以及它们在实际应用中的使用。 **Oracle存储过程** Oracle存储过程是一组预...

    java调用Oracle存储过程的代码

    在Java编程中,与Oracle数据库进行交互是常见的需求,尤其是当需要执行复杂的业务逻辑时,我们通常会使用Oracle存储过程。存储过程是预编译的SQL语句集合,它可以提高性能,封装复杂逻辑,并减少网络通信量。本教程...

    oracle存储过程(语法实例).pdf

    Java可以通过JDBC调用Oracle存储过程,包括`CallableStatement`对象来执行过程并处理输入/输出参数。 9. **更新与权限保留** 使用`CREATE OR REPLACE PROCEDURE`语句更新存储过程时,原有执行权限不会丢失。 10....

    oracle存储过程返回多行多列的结构化数组,java调用并解析

    总结来说,本示例展示了如何在Oracle存储过程中定义和使用结构化数组,以及如何在Java中调用这些存储过程并解析返回的多行多列数据。通过这种方式,你可以高效地处理复杂的数据结构,同时利用Java的灵活性来处理这些...

Global site tag (gtag.js) - Google Analytics