天天看点

Oracle 存储过程的使用

本文主要是总结 如何实现 JDBC调用Oracle的存储过程,从以下情况分别介绍:

[1]、只有输入IN参数,没有输出OUT参数

[2]、既有输入IN参数,也有输出OUT参数,输出是简单值(非列表)

[3]、既有输入IN参数,也有输出OUT参数,输出是列表

[4]、输入输出参数是同一个(IN OUT)

[5]、存储过程中 使用 truncate 截断表中的数据

【准备工作】

  创建一个测试表TMP_MICHAEL ,并插入数据,SQL如下:

create table TMP_MICHAEL  
(  
  USER_ID    VARCHAR2(20),  
  USER_NAME  VARCHAR2(10),  
  SALARY     NUMBER(8,2),  
  OTHER_INFO VARCHAR2(100)  
)  
  
insert into TMP_MICHAEL (USER_ID, USER_NAME, SALARY, OTHER_INFO)  
values ('michael', 'Michael', 5000, 'http://sjsky.iteye.com');  
insert into TMP_MICHAEL (USER_ID, USER_NAME, SALARY, OTHER_INFO)  
values ('zhangsan', '张三', 10000, null);  
insert into TMP_MICHAEL (USER_ID, USER_NAME, SALARY, OTHER_INFO)  
values ('aoi_sola', '苍井空', 99999.99, 'twitter account');  
insert into TMP_MICHAEL (USER_ID, USER_NAME, SALARY, OTHER_INFO)  
values ('李四', '李四', 2500, null); 
 
           

Oracle jdbc 常量:

private final static String DB_DRIVER = "oracle.jdbc.driver.OracleDriver";  
private final static String DB_CONNECTION = "jdbc:oracle:thin:@127.0.0.1:1521:Ora11g";  
private final static String DB_NAME = "mytest";  
private final static String DB_PWd = "111111"; 
           

[一]、只有输入IN参数,没有输出OUT参数

CREATE OR REPLACE PROCEDURE TEST_MICHAEL_NOOUT(P_USERID    IN VARCHAR2,  
                                               P_USERNAME  IN VARCHAR2,  
                                               P_SALARY    IN NUMBER,  
                                               P_OTHERINFO IN VARCHAR2) IS  
BEGIN  
  
  INSERT INTO TMP_MICHAEL  
    (USER_ID, USER_NAME, SALARY, OTHER_INFO)  
  VALUES  
    (P_USERID, P_USERNAME, P_SALARY, P_OTHERINFO);  
  
END TEST_MICHAEL_NOOUT;  
           

调用代码如下:

/** 
    * 测试调用存储过程:无返回值 
    * @blog http://sjsky.iteye.com 
    * @author Michael 
    * @throws Exception 
    */  
   public static void testProcNoOut() throws Exception {  
       System.out.println("-------  start 测试调用存储过程:无返回值");  
       Connection conn = null;  
       CallableStatement callStmt = null;  
       try {  
           Class.forName(DB_DRIVER);  
           conn = DriverManager.getConnection(DB_CONNECTION, DB_NAME, DB_PWd);  
           // 存储过程 TEST_MICHAEL_NOOUT 其实是向数据库插入一条数据  
           callStmt = conn.prepareCall("{call TEST_MICHAEL_NOOUT(?,?,?,?)}");  
  
           // 参数index从1开始,依次 1,2,3...  
           callStmt.setString(1, "jdbc");  
           callStmt.setString(2, "JDBC");  
           callStmt.setDouble(3, 8000.00);  
           callStmt.setString(4, "http://sjsky.iteye.com");  
           callStmt.execute();  
           System.out.println("-------  Test End.");  
       } catch (Exception e) {  
           e.printStackTrace(System.out);  
       } finally {  
           if (null != callStmt) {  
               callStmt.close();  
           }  
           if (null != conn) {  
               conn.close();  
           }  
       }  
   }  
           

[二]、既有输入IN参数,也有输出OUT参数,输出是简单值(非列表)

CREATE OR REPLACE PROCEDURE TEST_MICHAEL(P_USERID IN VARCHAR2,  
                                         P_SALARY IN NUMBER,  
                                         P_COUNT  OUT NUMBER) IS  
  V_SALARY NUMBER := P_SALARY;  
BEGIN  
  IF V_SALARY IS NULL THEN  
    V_SALARY := 0;  
  END IF;  
  IF P_USERID IS NULL THEN  
    SELECT COUNT(*)  
      INTO P_COUNT  
      FROM TMP_MICHAEL T  
     WHERE T.SALARY >= V_SALARY;  
  ELSE  
    SELECT COUNT(*)  
      INTO P_COUNT  
      FROM TMP_MICHAEL T  
     WHERE T.SALARY >= V_SALARY  
       AND T.USER_ID LIKE '%' || P_USERID || '%';  
  END IF;  
  DBMS_OUTPUT.PUT_LINE('v_count=:' || P_COUNT);  
END TEST_MICHAEL;  

           

调用程序如下

/** 
    * 测试调用存储过程:返回值是简单值非列表 
    * @blog http://sjsky.iteye.com 
    * @author Michael 
    * @throws Exception 
    */  
   public static void testProcOutSimple() throws Exception {  
       System.out.println("-------  start 测试调用存储过程:返回值是简单值非列表");  
       Connection conn = null;  
       CallableStatement stmt = null;  
       try {  
           Class.forName(DB_DRIVER);  
           conn = DriverManager.getConnection(DB_CONNECTION, DB_NAME, DB_PWd);  
  
           stmt = conn.prepareCall("{call TEST_MICHAEL(?,?,?)}");  
  
           stmt.setString(1, "");  
           stmt.setDouble(2, 3000);  
  
           // out 注册的index 和取值时要对应  
           stmt.registerOutParameter(3, Types.INTEGER);  
           stmt.execute();  
  
           // getXxx(index)中的index 需要和上面registerOutParameter的index对应  
           int i = stmt.getInt(3);  
           System.out.println("符号条件的查询结果 count := " + i);  
           System.out.println("-------  Test End.");  
       } catch (Exception e) {  
           e.printStackTrace(System.out);  
       } finally {  
           if (null != stmt) {  
               stmt.close();  
           }  
           if (null != conn) {  
               conn.close();  
           }  
       }  
   }  

           

测试程序就是查询薪水3000以上人员的数量 ,运行结果如下:

------- start 测试调用存储过程:返回值是简单值非列表

符号条件的查询结果 count := 4

------- Test End.

[三]、既有输入IN参数,也有输出OUT参数,输出是列表

  首先需要创建PACKAGE TEST_PKG_CURSOR 的SQL如下:

首先需要创建PACKAGE TEST_PKG_CURSOR 的SQL如下:
Sql代码     
CREATE OR REPLACE PACKAGE TEST_PKG_CURSOR IS  
  
  -- Author  : MICHAEL  http://sjsky.iteye.com  
  TYPE TEST_CURSOR IS REF CURSOR;  
  
END TEST_PKG_CURSOR;  
再创建存储过程 TEST_P_OUTRS 的SQL如下:
Sql代码     
CREATE OR REPLACE PROCEDURE TEST_P_OUTRS(P_SALARY IN NUMBER,  
                                         P_OUTRS  OUT TEST_PKG_CURSOR.TEST_CURSOR) IS  
  V_SALARY NUMBER := P_SALARY;  
BEGIN  
  IF P_SALARY IS NULL THEN  
    V_SALARY := 0;  
  END IF;  
  OPEN P_OUTRS FOR  
    SELECT * FROM TMP_MICHAEL T WHERE T.SALARY > V_SALARY;  
END TEST_P_OUTRS;  
           

调用存储过程的代码如下:

/** 
    * 测试调用存储过程:有返回值且返回值为列表的 
    * @blog http://sjsky.iteye.com 
    * @author Michael 
    * @throws Exception 
    */  
   public static void testProcOutRs() throws Exception {  
       System.out.println("-------  start 测试调用存储过程:有返回值且返回值为列表的");  
       Connection conn = null;  
       CallableStatement stmt = null;  
       ResultSet rs = null;  
       try {  
           Class.forName(DB_DRIVER);  
           conn = DriverManager.getConnection(DB_CONNECTION, DB_NAME, DB_PWd);  
  
           stmt = conn.prepareCall("{call TEST_P_OUTRS(?,?)}");  
  
           stmt.setDouble(1, 3000);  
           stmt.registerOutParameter(2, OracleTypes.CURSOR);  
           stmt.execute();  
  
           // getXxx(index)中的index 需要和上面registerOutParameter的index对应  
           rs = (ResultSet) stmt.getObject(2);  
           // 获取列名及类型  
           int colunmCount = rs.getMetaData().getColumnCount();  
           String[] colNameArr = new String[colunmCount];  
           String[] colTypeArr = new String[colunmCount];  
           for (int i = 0; i < colunmCount; i++) {  
               colNameArr[i] = rs.getMetaData().getColumnName(i + 1);  
               colTypeArr[i] = rs.getMetaData().getColumnTypeName(i + 1);  
               System.out.print(colNameArr[i] + "(" + colTypeArr[i] + ")"  
                       + " | ");  
           }  
           System.out.println();  
           while (rs.next()) {  
               StringBuffer sb = new StringBuffer();  
               for (int i = 0; i < colunmCount; i++) {  
                   sb.append(rs.getString(i + 1) + " | ");  
               }  
               System.out.println(sb);  
           }  
           System.out.println("------- Test Proc Out is ResultSet end. ");  
  
       } catch (Exception e) {  
           e.printStackTrace(System.out);  
       } finally {  
           if (null != rs) {  
               rs.close();  
           }  
           if (null != stmt) {  
               stmt.close();  
           }  
           if (null != conn) {  
               conn.close();  
           }  
       }  
   }  
 运行结果如下:
------- start 测试调用存储过程:有返回值且返回值为列表的 
USER_ID(VARCHAR2) | USER_NAME(VARCHAR2) | SALARY(NUMBER) | OTHER_INFO(VARCHAR2) |  
michael | Michael | 5000 | null |  
zhangsan | 张三 | 10000 | null |  
aoi_sola | 苍井空 | 99999.99 | null |  
jdbc | JDBC | 8000 | http://sjsky.iteye.com |  
------- Test Proc Out is ResultSet end.
           

[四]、输入输出参数是同一个(IN OUT)

CREATE OR REPLACE PROCEDURE TEST_P_INOUT(P_USERID IN VARCHAR2,  
                                         P_NUM    IN OUT NUMBER) IS  
  V_COUNT  NUMBER;  
  V_SALARY NUMBER := P_NUM;  
BEGIN  
  IF V_SALARY IS NULL THEN  
    V_SALARY := 0;  
  END IF;  
  
  SELECT COUNT(*)  
    INTO V_COUNT  
    FROM TMP_MICHAEL  
   WHERE USER_ID LIKE '%' || P_USERID || '%'  
     AND SALARY >= V_SALARY;  
  P_NUM := V_COUNT;  
END TEST_P_INOUT;  
           

调用存储过程的代码:

/** 
     * 测试调用存储过程: INOUT同一个参数: 
     * @blog http://sjsky.iteye.com 
     * @author Michael 
     * @throws Exception 
     */  
    public static void testProcInOut() throws Exception {  
        System.out.println("-------  start 测试调用存储过程:INOUT同一个参数");  
        Connection conn = null;  
        CallableStatement stmt = null;  
        try {  
            Class.forName(DB_DRIVER);  
            conn = DriverManager.getConnection(DB_CONNECTION, DB_NAME, DB_PWd);  
  
            stmt = conn.prepareCall("{call TEST_P_INOUT(?,?)}");  
  
            stmt.setString(1, "michael");  
            stmt.setDouble(2, 3000);  
  
            // 注意此次注册out 的index 和上面的in 参数index 相同  
            stmt.registerOutParameter(2, Types.INTEGER);  
            stmt.execute();  
  
            // getXxx(index)中的index 需要和上面registerOutParameter的index对应  
            int count = stmt.getInt(2);  
            System.out.println("符号条件的查询结果 count := " + count);  
            System.out.println("-------  Test End.");  
        } catch (Exception e) {  
            e.printStackTrace(System.out);  
        } finally {  
            if (null != stmt) {  
                stmt.close();  
            }  
            if (null != conn) {  
                conn.close();  
            }  
        }  
    }  
 运行结果如下:
------- start 测试调用存储过程:INOUT同一个参数 
符号条件的查询结果 count := 1 
------- Test End.
           

[五] 存储过程中使用 truncate  清空表中的数据

create or replace procedure PROC_INSERT_BLDAREN(rownums in number) is
begin
  EXECUTE IMMEDIATE 'TRUNCATE TABLE BI_BAOLIAO_DAREN';
  insert into BI_BAOLIAO_DAREN (ID,USERID,USERNAME,BAOLIAONUM,CREDITS) select bi_baoliao_sequence.nextval,bl.* from (select b.userid,b.username,count(b.id),sum(b.credits) credits from bi_baoliao b  group by b.userid,b.username order by credits desc) bl where rownum <=rownums;
end PROC_INSERT_BLDAREN;
           

java 调用

/**
* 使用 truncate 先清空表中的数据
* 然后 插入数据
*/
public static boolean updateData1(int rownum){
		boolean result=true;
		Connection conn=null;
		CallableStatement  cs=null;
		try {
			Date stime=new Date();
			conn=DBConnection.getConnection();
			cs=conn.prepareCall("{call PROC_INSERT_BLDAREN(?)}");
			cs.setInt(1, rownum);
			result=cs.execute();
			Date etime=new Date();
			System.out.println(etime.getTime()-stime.getTime());
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			DBConnection.cleanUp(null, null, cs, null);
		}
		return result;
	}