1. 程式人生 > >Java中呼叫Oracle儲存過程及儲存函式

Java中呼叫Oracle儲存過程及儲存函式

一. 編寫測試所用儲存函式或函式

--1.建立一個帶引數的儲存過程,沒有返回值
--給指定的員工漲100元的工資,並且列印漲錢和漲後的工資
create or replace procedure raisesalary(eno in number)
as
    --定義一個變數儲存漲前的薪水
   psal emp.sal%type;
begin
   --得到員工漲前的薪水
   select sal into psal from emp where empno=eno;

   --給該員工漲100工資
   update emp set sal = sal+100 where empno=eno;
--需不需要commit? --一般不在儲存過程中或儲存函式中提交 --列印 dbms_output.put_line('漲前薪水:' || psal ||'漲後薪水:'||(psal+100)); end; /* 如何呼叫: begin raisesalary(7839); raisesalary(7566); commit; end; */
--2.儲存函式,通過return關鍵字返回員工年薪
--查詢某個員工的年收入
create or replace function getYearMoney (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*12+nvl(pcomm,0); end;
--3.儲存過程,通過in和out引數控制輸入和輸出
--查詢某個員工的姓名,工資和工作
create or replace procedure getEmpInfo(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; /* 呼叫 declare eno number; pename varchar2(200); psal number; pjob varchar2(200); begin eno:=7369; getEmpInfo(eno,pename,psal,pjob); dbms_output.put_line('姓名:'|| pename); dbms_output.put_line('工資:'|| psal); dbms_output.put_line('職位:'|| pjob); end; */
--4.定義包頭和包體
    該包裡面是定義儲存函式和儲存過程,只是未實現,要在包體中實現,有點類似java中抽象類。
--包頭
CREATE OR REPLACE Package mypackage as
    type empcursor is ref cursor;--定義儲存過程返回的資料型別,該過程返回遊標,類似集合
    procedure queryEmpList(dno in number,empList out empcursor);
end mypackage;

--包體,即包頭中定義的儲存過程或函式的實現
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;

二. 測試前準備工作
- 準備jdbc驅動 本測試使用 ojdbc14-10.2.0.4.0.jar
- 準備連線資料庫等相關工具類

package demo.Utils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

//工具類
public class JDBCUtils {
    private static String driver = "oracle.jdbc.OracleDriver";
    private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
    private static String user = "scott";
    private static String password = "tiger";

    //註冊資料庫驅動
    static {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    //獲取資料庫連線
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //釋放資料庫的資源
    public static void release (Connection conn,Statement st,ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                rs = null;
            }
        }

        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                st = null;
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                conn = null;
            }
        }
    }
}

三. 編寫java類呼叫儲存過程或函式
主要是通過CallableStatement介面進行呼叫

//呼叫儲存過程,getEmpInfo
package demo.oracle;
import java.sql.CallableStatement;
import java.sql.Connection;
import org.junit.Test;
import demo.Utils.JDBCUtils;
import oracle.jdbc.driver.OracleTypes;
public class TestProcedure {
    @Test
    public void testProcedure() {
        String sql = "{call getEmpInfo(?,?,?,?)}";
        Connection conn = null;
        CallableStatement call = null;
        try {
            //得到一個連結
            conn = JDBCUtils.getConnection();
            //通過連結創建出statement
            call = conn.prepareCall(sql); 

            //對於in引數,賦值
            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.out.println(name+"\t"+sal+"\t"+job);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            JDBCUtils.release(conn, call, null);
        }
    }
}

//呼叫儲存函式,getYearMoney
package demo.oracle;
import java.sql.CallableStatement;
import java.sql.Connection;
import org.junit.Test;
import demo.Utils.JDBCUtils;
import oracle.jdbc.driver.OracleTypes;
public class TestFunction {
    @Test
    public void testFunction () {
        String sql = "{?=call getYearMoney(?)}";
        Connection conn = null;
        CallableStatement call = null;
        try {
            //得到一個連結
            conn = JDBCUtils.getConnection();
            //通過連結創建出statement
            call = conn.prepareCall(sql); 

            //對於輸出引數,宣告
            call.registerOutParameter(1, OracleTypes.NUMBER);
            //對於輸入引數,賦值
            call.setInt(2, 7839);

            //執行呼叫
            call.execute();
            //取出結果
            double sals = call.getDouble(1);
            System.out.println("年薪為:"+sals);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            JDBCUtils.release(conn, call, null);
        }
    }
}
//呼叫包中定義的儲存過程,與普通儲存過程區別在於,包中定義儲存過程或儲存函式可以返回遊標,並在java中進行解析,這樣比在java中拿到結果集執行效率略高些。
package demo.oracle;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
import demo.Utils.JDBCUtils;
import oracle.jdbc.driver.OracleCallableStatement;
import oracle.jdbc.internal.OracleTypes;
public class TestCursor {
    @Test
    public void testCursor(){
        String sql = "{call mypackage.queryEmpList(?,?)}";
        Connection conn = null;
        CallableStatement call = null;
        ResultSet rs = null;
        try {
            //得到一個連結
            conn = JDBCUtils.getConnection();
            //通過連結創建出statement
            call = conn.prepareCall(sql); 

            //對於in引數,賦值
            call.setInt(1, 20);
            //對於out引數,宣告
            call.registerOutParameter(2, OracleTypes.CURSOR);
            //執行呼叫
            call.execute();
            //取出該部門中所有員工的資訊
            rs = ((OracleCallableStatement)call).getCursor(2);
            while (rs.next()) {
                //取出該員工的員工號,姓名,薪水和職位
                int empno = rs.getInt("empno");
                String name = rs.getString("ename");
                double salary = rs.getDouble("sal");
                String job = rs.getString("job");
                System.out.println(empno+"\t"+name+"\t"+salary+"\t"+job);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.release(conn, call, rs);
        }
    }
}