用JDBC操作Oracle的存储过程返回值
Oracle的存储过程可以返回任何类型,包括一个ResultSet,JDBC自带的CallableStatement可以提供操作这些返回值得借口,其中我们可以通过registerOutParameter来注册需要返回的类型。CallableStatement是PrepareStatement的一个子类,但提供了返回和注册Out类型参数的功能。
我们看一下例子,在Oracle里面我们定义了一个包如下:
create or replace package GP_TESTP is
type my_dCursor is ref cursor;
procedure GP_Test(m_cursor2 OUT my_dCursor);
end GP_TESTP;

create or replace package body GP_TESTP is
procedure GP_Test(m_cursor2 OUT my_dCursor) is
begin
open m_cursor2 for select bom.material_no,bom.product_no from gp2_bom bom where bom.year=2006 ;
end GP_Test;
end GP_TESTP;

在JDBC里面我们可以通过如下的接口来得到返回的动态游标的内容
Global.start(); //初始化连接池
ConnectionWrapper wrapper=ConnectionPoolFactory.getPoolInstance().borrowConnection();//从连接池里面返回连接
Connection conn=wrapper.getConnection();
try {
String callSql="{call GP_TESTP.GP_Test(?)}";
CallableStatement cs = null;
ResultSet rs=null;
cs = conn.prepareCall(callSql);
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);
cs.execute();
rs = (ResultSet)cs.getObject(2);
while(rs.next()){
//String s=rs.get("");
String component=rs.getString(2);
String productNo=rs.getString(4);
System.out.println("component="+component+"-------productNo="+productNo);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
注意兰颜色的代码是注册动态游标和返回结果集的关键代码。


=======================================
2008年07月06日 星期日 07:41 P.M.一:无返回值的存储过程

存储过程为:

CREATE OR REPLACE PROCEDURE TESTA(PARA1 IN VARCHAR2,PARA2 IN VARCHAR2) AS

BEGIN

INSERT INTO HYQ.B_ID (I_ID,I_NAME) VALUES (PARA1, PARA2);

END TESTA;

然后呢,在java里调用时就用下面的代码:

package com.hyq.src;


import java.sql.*;

import java.sql.ResultSet;


public class TestProcedureOne {

public TestProcedureOne() {

}

public static void main(String[] args ){

String driver = "oracle.jdbc.driver.OracleDriver";

String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521: hyq ";

Statement stmt = null;

ResultSet rs = null;

Connection conn = null;

CallableStatement cstmt = null;


try {

Class.forName(driver);

conn = DriverManager.getConnection(strUrl, " hyq ", " hyq ");

CallableStatement proc = null;

proc = conn.prepareCall("{ call HYQ.TESTA(?,?) }");

proc.setString(1, "100");

proc.setString(2, "TestOne");

proc.execute();

}

catch (SQLException ex2) {

ex2.printStackTrace();

}

catch (Exception ex2) {

ex2.printStackTrace();

}

finally{

try {

if(rs != null){

rs.close();

if(stmt!=null){

stmt.close();

}

if(conn!=null){

conn.close();

}

}

}

catch (SQLException ex1) {

}

}

}

}

当然了,这就先要求要建张表TESTTB,里面两个字段(I_ID,I_NAME)。

二:有返回值的存储过程(非列表)

存储过程为:

CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2) AS

BEGIN

SELECT INTO PARA2 FROM TESTTB WHERE I_ID= PARA1;

END TESTB;

在java里调用时就用下面的代码:

package com.hyq.src;


public class TestProcedureTWO {
public TestProcedureTWO() {
}
public static void main(String[] args ){
String driver = "oracle.jdbc.driver.OracleDriver";
String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, " hyq ", " hyq ");
CallableStatement proc = null;
proc = conn.prepareCall("{ call HYQ.TESTB(?,?) }");
proc.setString(1, "100");
proc.registerOutParameter(2, Types.VARCHAR);
proc.execute();
String testPrint = proc.getString(2);
System.out.println("=testPrint=is="+testPrint);
}
catch (SQLException ex2) {
ex2.printStackTrace();
}
catch (Exception ex2) {
ex2.printStackTrace();
}
finally{
try {
if(rs != null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch (SQLException ex1) {
}
}
}
}
}

注意,这里的proc.getString(2)中的数值2并非任意的,而是和存储过程中的out列对应的,如果out是在第一个位置,那就是proc.getString(1),如果是第三个位置,就是proc.getString(3),当然也可以同时有多个返回值,那就是再多加几个out参数了。


2008年07月06日 星期日 07:42 P.M.由于oracle存储过程没有返回值,它的所有返回值都是通过out参数来替代的,列表同样也不例外,但由于是集合,所以不能用一般的参数,必须要用pagkage了.所以要分两部分,

1, 建一个程序包。如下:

CREATE OR REPLACE PACKAGE TESTPACKAGE AS

TYPE Test_CURSOR IS REF CURSOR;

end TESTPACKAGE;

2,建立存储过程,存储过程为:

CREATE OR REPLACE PROCEDURE TESTC(p_CURSOR out TESTPACKAGE.Test_CURSOR) IS

BEGIN

OPEN p_CURSOR FOR SELECT * FROM HYQ.TESTTB;

END TESTC;

可以看到,它是把游标(可以理解为一个指针),作为一个out 参数来返回值的。

在java里调用时就用下面的代码:

package com.hyq.src;

import java.sql.*;
import java.io.OutputStream;
import java.io.Writer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import oracle.jdbc.driver.*;

public class TestProcedureTHREE {
public TestProcedureTHREE() {
}
public static void main(String[] args ){
String driver = "oracle.jdbc.driver.OracleDriver";
String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
try {
Class.forName(driver);
conn = DriverManager.getConnection(strUrl, "hyq", "hyq");
CallableStatement proc = null;
proc = conn.prepareCall("{ call hyq.testc(?) }");
proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);
proc.execute();
rs = (ResultSet)proc.getObject(1);
while(rs.next())
{
System.out.println("<tr><td>" + rs.getString(1) + "</td><td>"+rs.getString(2)+"</td></tr>");
}
}
catch (SQLException ex2) {
ex2.printStackTrace();
}
catch (Exception ex2) {
ex2.printStackTrace();
} finally{
try {
if(rs != null){
rs.close();
if(stmt!=null){
stmt.close();
}
if(conn!=null){
conn.close();
}
}
}
catch (SQLException ex1) {
}
}
}


================================

create or replace procedure proc_assess_optr is
date_cycle varchar2(20); --周期
start_date varchar2(10); --开始日期
end_date varchar2(10); --结束日期
region_code varchar2(32); --region code
db_user varchar2(30); --用户名
del_sql varchar2(1000);--删除这个周期的数据

begin
declare
cursor cur_user is
SELECT distinct DB_USER, CODE FROM REGION_CONFIG;
begin
start_date := to_char(last_day(add_months(SYSDATE, -2)) + 1, 'yyyy-MM-dd');--上个月的1号
end_date := to_char(last_day(add_months(SYSDATE, -1)) + 1 , 'yyyy-MM-dd');--这个月1号
date_cycle := to_char(sysdate - interval '1' month, 'yyyyMM');
--遍历所有的用户
begin
dbms_output.enable(1000000);
open cur_user;
loop
fetch cur_user
into db_user, region_code;
exit when cur_user%notfound;
begin
del_sql := 'delete from ' || db_user ||
'.guideline_instance t where t.cycle_id=''' ||
date_cycle || ''' and t.guidline_id in(''1'',''2'',''3'',''4'')';
DBMS_OUTPUT.put_line(del_sql);
execute immediate del_sql; --动态立即执行一个SQL语句
---具体数据分析执行
proc_assess_optr_exeute(db_user,
start_date,
end_date,
date_cycle);
end;
end loop;
close cur_user;
commit;
end;
end;
end proc_assess_optr;
/