Java代碼調用存儲過程和存儲函數要使用CallableStatement接口
查看API文檔:
上代碼:
java代碼調用如下的存儲過程和函數:
查詢某個員工的姓名 月薪 職位
1 create or replace procedure queryEmpinfo(eno in number, 2 pename out varchar2, 3 psal out number, 4 pjob out varchar2) 5 as 6 begin 7 select ename,sal,empjob into pename,psal,pjob from emp where empno=eno; 8 end;
1 --查詢某個員工的年收入 2 create or replace function queryEmpIncome(eno in number) 3 return number 4 as 5 psal emp.sal%type; 6 pcomm emp.comm%type; 7 begin 8 select sal,comm into psal,pcomm from emp where empno=eno; 9 10 --返回年收入 11 return psal*12+nvl(pcomm,0); 12 13 end;
1 --在out參數中使用光標 2 查詢某個部門中所有員工的所有信息 3 4 5 包頭 6 CREATE OR REPLACE PACKAGE MYPACKAGE AS 7 8 type empcursor is ref cursor; 9 procedure queryEmpList(dno in number,empList out empcursor); 10 11 END MYPACKAGE; 12 13 14 包體 15 CREATE OR REPLACE 16 PACKAGE BODY MYPACKAGE AS 17 18 procedure queryEmpList(dno in number,empList out empcursor) AS 19 BEGIN 20 open empList for select * from emp where deptno=dno; 21 END queryEmpList; 22 23 END MYPACKAGE;
1 import java.sql.CallableStatement; 2 import java.sql.Connection; 3 import java.sql.ResultSet; 4 import java.sql.SQLException; 5 6 import oracle.jdbc.driver.OracleCallableStatement; 7 import oracle.jdbc.driver.OracleTypes; 8 9 import org.junit.Test; 10 11 public class TestOracle { 12 13 /* 14 * CallableStatement 接口 15 * 調用存儲函數,等號左邊有一個返回值 16 * {?= call <procedure-name>[(<arg1>,<arg2>, ...)]} 17 * 調用存儲過程. 沒有返回值 18 {call <procedure-name>[(<arg1>,<arg2>, ...)]} 19 20 * 21 */ 22 23 /*存儲過程 查詢某個員工的姓名 月薪 職位 24 * create or replace procedure queryEmpinfo(eno in number, 25 pename out varchar2, 26 psal out number, 27 pjob out varchar2) 28 */ 29 30 @Test 31 public void testProcedure(){ 32 //{call <procedure-name>[(<arg1>,<arg2>,...)]} 33 String sql = "{call queryEmpinfo(?,?,?,?)}";//4個問號中,第一個是輸入參數,其余是輸出參數 34 Connection conn = null; 35 //要用CallableStatement這個接口,用於執行 SQL 存儲過程的接口 36 CallableStatement call = null; 37 38 try { 39 conn = JDBCUtils.getConnection(); 40 call = conn.prepareCall(sql); 41 //對於in參數,需要賦值 42 call.setInt(1,7839); 43 //對於out參數,需要聲明 44 call.registerOutParameter(2, OracleTypes.VARCHAR);//第二個是字符串 45 call.registerOutParameter(3, OracleTypes.NUMBER);//第三個是數字 46 call.registerOutParameter(4, OracleTypes.VARCHAR);//第四個是字符串 47 48 call.execute(); 49 //取出結果 50 String name = call.getString(2); 51 double sal = call.getDouble(3); 52 String job = call.getString(4); 53 System.out.println(name+"\t"+sal+"\t"+job+"\t"); 54 } catch (SQLException e) { 55 e.printStackTrace(); 56 }finally{ 57 JDBCUtils.release(conn, call, null);//沒有最后一個參數就傳入null 58 } 59 } 60 61 /*存儲函數 查詢某個員工的姓名,月薪和職位 62 * create or replace function queryEmpIncome(eno in number) 63 return number 64 */ 65 @Test 66 public void testFunction(){ 67 //{?= call <procedure-name>[(<arg1>,<arg2>, ...)]} 68 //第一個問號是函數的返回值,第二個問號是輸入參數. 返回值的作用和輸出參數是一樣的. 69 String sql = "{?=call QUERYEMPINCOME(?)}";//這個call后面的存儲過程名或者是存儲函數名大寫或者是小寫是沒有要求的. 70 Connection conn = null; 71 //要用CallableStatement這個接口,用於執行 SQL 存儲過程的接口 72 CallableStatement call = null; 73 74 try { 75 conn = JDBCUtils.getConnection(); 76 call = conn.prepareCall(sql); 77 78 //對於in參數,賦值 79 call.setInt(2,7839); 80 81 //對於out參數,申明 82 call.registerOutParameter(1, OracleTypes.NUMBER); 83 call.execute(); 84 //取出結果 85 //取出結果 86 double income = call.getDouble(1); 87 System.out.println(income); 88 } catch (SQLException e) { 89 e.printStackTrace(); 90 }finally{ 91 JDBCUtils.release(conn, call, null);//沒有最后一個參數就傳入null 92 } 93 94 95 } 96 97 /* 98 查詢某個部門中所有員工的所有信息 99 包頭 100 CREATE OR REPLACE PACKAGE MYPACKAGE AS 101 102 type empcursor is ref cursor; 103 procedure queryEmpList(dno in number,empList out empcursor); 104 105 END MYPACKAGE; 106 107 108 包體 109 CREATE OR REPLACE 110 PACKAGE BODY MYPACKAGE AS 111 112 procedure queryEmpList(dno in number,empList out empcursor) AS 113 BEGIN 114 open empList for select * from emp where deptno=dno; 115 END queryEmpList; 116 117 END MYPACKAGE; 118 */ 119 @Test 120 public void testCursor(){ 121 //{call <procedure-name>[(<arg1>,<arg2>, ...)]} 122 String sql = "{call MYPACKAGE.queryEmpList(?,?)}"; 123 124 Connection conn = null; 125 CallableStatement call = null; 126 //有游標,就有結果集 127 ResultSet rest = null; 128 try { 129 conn = JDBCUtils.getConnection(); 130 call = conn.prepareCall(sql); 131 132 //對於in參數,賦值 133 call.setInt(1, 20); 134 135 //對於out參數,申明 136 call.registerOutParameter(2, OracleTypes.CURSOR); 137 call.execute(); 138 //取出集合 139 //這個地方要強轉!!!OracleCallableStatement是抽象類,繼承了CallableStatement 140 //不強轉沒有getCursor()方法... 141 rest = ((OracleCallableStatement)call).getCursor(2); 142 while(rest.next()){ 143 String name = rest.getString("ename"); 144 double sal = rest.getDouble("sal"); 145 System.out.println(name+"\t"+sal); 146 } 147 }catch (Exception e) { 148 e.printStackTrace(); 149 }finally{ 150 JDBCUtils.release(conn, call, rest);//上面打開了光標,再這個地方關閉結果集rest,也就關閉了光標 151 } 152 } 153 }
關於Oracle中的包對象:
之前的存儲函數中查詢的是某一個員工的信息:
1 create or replace procedure queryEmpinfo(eno in number, 2 pename out varchar2, 3 psal out number, 4 pjob out varchar2) 5 as 6 begin 7 select ename,sal,empjob into pename,psal,pjob from emp where empno=eno; 8 end;
但是①如果要查詢一個員工的所有信息,而這個員工的信息對應的有幾百列
在存儲函數中括號的函數要把這幾百列都聲明出來?
②如果要查詢某個部門中所有員工的所有信息...這個信息對應的是一個集合.
第二個問題解決了第一個問題也就解決了.
怎么在存儲過程或者存儲函數中返回一個集合.
學到現在有多少種方式可以代表一個集合?
第一個是表,第二個是select語句也可以.第三個是光標.
在out參數中使用光標.但是有一個要求,必須要聲明一個包,包分為包頭和包體.也是數據庫的對象.跟表,視圖,等是一樣的是數據庫的對象.
包頭只負責聲明,包體只負責實現.
1 --在out參數中使用光標 2 查詢某個部門中所有員工的所有信息 3 4 5 包頭 6 CREATE OR REPLACE PACKAGE MYPACKAGE AS 7 8 type empcursor is ref cursor; 9 procedure queryEmpList(dno in number,empList out empcursor); 10 11 END MYPACKAGE; 12 13 14 包體 15 CREATE OR REPLACE 16 PACKAGE BODY MYPACKAGE AS 17 18 procedure queryEmpList(dno in number,empList out empcursor) AS 19 BEGIN 20 open empList for select * from emp where deptno=dno; 21 END queryEmpList; 22 23 END MYPACKAGE;
分析圖:
參看包:
包無法在plsqldeveloper和sqldeveloper等工具中右鍵運行....必須通過java代碼應用程序來調用執行(代碼在上面)