java調用存儲過程、存儲函數


需要用到的接口

接口 CallableStatement

JDK文檔對改接口的說明:

public interface CallableStatement
      extends 
      PreparedStatement

用於執行 SQL 存儲過程的接口。JDBC API 提供了一個存儲過程 SQL 轉義語法,該語法允許對所有 RDBMS 使用標准方式調用存儲過程。此轉義語法有一個包含結果參數的形式和一個不包含結果參數的形式。如果使用結果參數,則必須將其注冊為 OUT 參數。其他參數可用於輸入、輸出或同時用於二者。參數是根據編號按順序引用的,第一個參數的編號是 1。

   {?= call <procedure-name>[(<arg1>,<arg2>, ...)]}  -------存儲函數的sql,第一個?代表返回類型
   {call <procedure-name>[(<arg1>,<arg2>, ...)]}     -------存儲過程的sql

IN 參數值是使用繼承自 PreparedStatement 的 set 方法設置的。在執行存儲過程之前,必須注冊所有 OUT 參數的類型;它們的值是在執行后通過此類提供的 get 方法獲取的。

CallableStatement 可以返回一個 ResultSet 對象或多個 ResultSet 對象。多個 ResultSet 對象是使用繼承自 Statement 的操作處理的。

為了獲得最大的可移植性,某一調用的 ResultSet 對象和更新計數應該在獲得輸出參數的值之前處理。

例子程序

對oracle的scott/tiger用戶的emp表操作

存儲過程,查詢員工信息

create or replace procedure queryEmpInfo(eno in number,
                               pename out varchar2,
                               psal out number,
                               pjob out varchar2)
as
begin
  select ename,sal,job into pename,psal,pjob from emp where empno=eno;
end;

存儲函數:

create or replace function queryEmpImcome(eno in number)
return number
as

  --變量
  psal emp.sal%type;
  pcomm emp.comm%type;
begin
  select sal,comm into psal,pcomm from emp where empno=eno;
  return (psal+nvl(pcomm,0))*12;

end;

jdbc工具類

 

package com.lhy.util;
import java.sql.*;

/**
 * JDBC工具類 ,一般工具類final。
 * 工具類一般不需要new,不需要構造實例。(把構造方法私有)別人就new不了了。
 * 此時使用類的方法:
 * 1是單例模式(復雜點)
 * 2是提供靜態的public方法。(簡單)
 * 本例子是簡單的提供public方法實現的。需要靜態方法
 * 
 * @author hy
 * 
 */
public final class JdbcUtils {
    private static String  url ="jdbc:oracle:thin:@127.0.0.1:1521:ORCL";
    private static String user ="scott";
    private static  String passWord = "tiger"; 

    //構造方法私有,別人不能構造,不會有實例出來.
    private JdbcUtils(){
        
    }
    
    /**
     * 靜態代碼塊,類加載到虛擬機是只執行一次。
     */
    static {
        try {
            Class.forName("oracle.jdbc.driver.OracleDriver");
        } catch (ClassNotFoundException e) {
            
            e.printStackTrace();
        }

    }

    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn =  DriverManager.getConnection(url,user,passWord);
        } catch (SQLException e) {
            
            e.printStackTrace();
        }
        return conn;
        
             
        
    }
    
    //釋放資源,重載方法。
    public static void close(Connection conn) {
        try {
            if(conn != null){
                conn.close();
                conn = null;
            }
        }catch(SQLException e){
            e.printStackTrace();
        } 
    }
    public static void close(Statement stmt){
        try{
            if(stmt != null){
                stmt.close();
                stmt = null;
            }
        }catch(SQLException e){
            e.printStackTrace();
        }
    }
    public static void close(ResultSet  rs){
        try{
            if(rs != null){
                rs.close();
                rs = null;
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

測試程序:

public class OracleTest {

    /**
     * 測試存儲過程
     * create or replace procedure queryEmpInfo(eno in number,
                               pename out varchar2,
                               psal out number,
                               pjob out varchar2)
    as

    begin
      select ename,sal,job into pename,psal,pjob from emp where empno=eno;
    end;
     */
    @Test
    public void testProcedure(){
        //格式 {call <procedure-name>[(<arg1>,<arg2>, ...)]}
        String sql = "{call queryEmpInfo(?,?,?,?)}";
        Connection conn = null;
        CallableStatement call = null;
        
        try {
            conn = JdbcUtils.getConnection();
            call = conn.prepareCall(sql);
            //賦值
            call.setInt(1, 7839);
            //對於out參數,聲明
            call.registerOutParameter(2, OracleTypes.VARCHAR);
            call.registerOutParameter(3, OracleTypes.NUMBER);
            call.registerOutParameter(4, OracleTypes.VARCHAR);
            
            //調用
            call.execute();
            
            //取值
            String name = call.getString(2);
            double sal = call.getDouble(3);
            String job = call.getString(4);
            System.err.println(name);
            System.err.println(sal);
            System.err.println(job);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            JdbcUtils.close(call);
            JdbcUtils.close(conn);
        }
    }
    
    /**
     * 測試 存儲函數
     * create or replace function queryEmpImcome(eno in number)
        return number
        as
        
          --變量
          psal emp.sal%type;
          pcomm emp.comm%type;
        begin
          select sal,comm into psal,pcomm from emp where empno=eno;
          return (psal+nvl(pcomm,0))*12;
        
        end;
     */
    @Test
    public void testFunction(){
        //{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
        //第一個?--> 輸出參數,返回值,    第二個 ?-->輸入參數
        String sql = "{?= call queryEmpImcome(?)}";
        Connection conn = null;
        CallableStatement call = null;
        
        try {
            conn = JdbcUtils.getConnection();
            call = conn.prepareCall(sql);
            
            //注冊輸出參數
            call.registerOutParameter(1, OracleTypes.NUMBER);
            //輸入參數
            call.setInt(2, 7839);
            
            //執行
            call.execute();
            //取出年收入,注意是get 1
            double income = call.getDouble(1);
            System.err.println("年收入:"+income);
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.close(call);
            JdbcUtils.close(conn);
        }
    }
}

運行結果:

性能
Statement < preparedStatement < CallableStatement

在Out參數中使用游標

package:程序包

上邊的例子的存儲過程,輸出參數只有三個,如果輸出參數有很多,或者輸出結果是一個結果集(如查詢一個部門中所有員工的信息),此時就需要在out參數中使用游標 

例子:查詢某個部門所有員工的所有信息

使用PLSQL建包

1,新建包

create or replace package MYPACKAGE as

   type empcursor is ref cursor;
  
  procedure queryEmpList(dno in number,empList out empcursor);
 
end MYPACKAGE;

2,新建包體

CREATE OR REPLACE PACKAGE BODY MYPACKAGE AS

  procedure queryEmpList(dno in number,empList out empcursor) AS
  BEGIN
      
      open empList for select * from emp where deptno=dno;
    
  END queryEmpList;

END MYPACKAGE;

使用java程序測試:

@Test
    public void testCursor(){
        String sql = "{call MYPACKAGE.queryEmpList(?,?)}";
        Connection conn = null;
        CallableStatement call = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils.getConnection();
            call = conn.prepareCall(sql);
            
            call.setInt(1, 10);
            call.registerOutParameter(2, OracleTypes.CURSOR);
            
            //執行
            call.execute();
            //取出集合,轉換為OracleCallableStatement,去除游標
            rs = ((OracleCallableStatement)call).getCursor(2);
            while(rs.next()){
                String name = rs.getString("ename");
                String job = rs.getString("job");
                double salary = rs.getDouble("sal");
                
                System.err.println("姓名:"+name+",職位:"+job+",薪水:"+salary);
                
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.close(rs);
            JdbcUtils.close(call);
            JdbcUtils.close(conn);
        }
    }

 

光標當ResultSet關閉的時候就關閉了

 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM