基於oracle數據庫存儲過程的創建及調用
1、PLSQL編程
1.1概念和目的
PL/SQL(Procedure Language/SQL)
PLSQL是Oracle對sql語言的過程化擴展
指在SQL命令語言中增加了過程處理語句(如分支、循環),使SQL語言具有過程處理能力
1.2程序結構
通過PLsqlDeveloper工具的Test Windows創建程序模版或者通過語句在SQLWindows編寫
提示:PLSQL語言的大小是不區分的
PL/SQL可以分為三個部分:聲明部分、可執行部分、異常處理部分
[declare] --聲明變量,遊標(無變量聲明可以省略)
begin
--執行部分(方法)處理業務異常
end;
set serveroutput on --sqlplus 命令窗口
begin
DBMS_output.put_line(“Hello world”);
end;
/ ---需要在程序最後添加一個/標識程序的結束
1.3變量
聲明變量的方式
變量名 變量類型(變量長度) --v_name varchar2(20)
1.3.1普通變量(char varchar2 date number boolean long)
(1)直接賦值語句:= --v_name=’zhangsan’
(2)語句賦值,使用select…into…賦值(語法select值into變量)
【示例】打印人員個人信息,包括:姓名、薪水、地址
declare v_name varchar2(20):=’zhangsan’; v_sal number; v_addr varchar2(200); begin v_sal:=1580; select ‘ad’ into v_addr from dual; DBMS_output.put_line(‘姓名:’|| v_name|| ’薪水:’ || v_sal ||‘地址:’||v_addr); end;
【示例】查詢 emp表中7839號員工的個人信息,打印姓名和薪水
declare v_name vachar2(20); v_sal number; begin select ename,sal into v_name,v_sal from emp where empno=7839; DBMS_output.put_line(‘姓名:’|| v_name || ‘,薪水:’|| v_sal); end;
1.3.2特殊變量類型(引用型變量、記錄型變量)
(1)引用型變量
【示例】查詢 emp表中7839號員工的個人信息,打印姓名和薪水
declare v_name emp.ename%TYPE; v_sal emp.sal%TYPE; begin select ename,sal into v_name,v_sal from emp where empno=7839; DBMS_output.put_line(‘姓名:’|| v_name || ‘,薪水:’|| v_sal); end;
使用普通變量定義方式,需要知道表中列的類型,而是用引用類型,不需要考慮列的類型,使用%TYPE是非常好的編程風格,因為它使得PL/SQL更加靈活,更加適應於對數據庫定義的更新。
(2)記錄型變量
接受表中的一行記錄,相當於Java中的一個對象
語法:變量名稱 表名%ROWTYPE
【示例】查詢 emp表中7839號員工的個人信息,打印姓名和薪水…..
declare v_emp emp%ROWTYPE; begin select * into v_emp from emp where empno=7839; DBMS_output.put_line(‘姓名:’|| v_emp.ename || ‘,薪水:’|| v_emp.sal); end;
如果有一個表,有100個字段,如果要使用這100字段名,如果使用引用型變量一個個聲明,會特別麻煩,記錄型變量可以方便的解決這個問題。
錯誤的使用:
1.記錄型變量只能存儲一個完整的行數據。
2.返回的行太多了,記錄型變量也接受不了。
1.4流程控制
1.4.1條件分支
begin if 條件1 then 執行1 elsif 條件2 then 執行2 else 執行3 end if; end;
【示例】判斷emp表中記錄是否超過20條,10-20之間,或者10條以下
declare --聲明變量接受emp中的數量 v_count number; begin select count(1) into v_count from emp; if v_count>20 then DBMS_output.put_line(‘emp表中的記錄數超過了20條為:’|| v_count); elsif v_count>=10 then DBMS_output.put_line(‘emp表中的記錄數在10-20條為:’|| v_count); else DBMS_output.put_line(‘emp表中的記錄數10條以下為:’|| v_count); end if; end;
1.4.2循環
在oracle中有三種循環方式,loop循環
語法:
begin loop exit when 退出循環條件 end loop; end;
【示例】打印數字1-10
declare v_num number:=1; begin loop exit when v_num>10; dbms_output.put_line(v_num); v_num+=v_num+1; end loop; end;
2、遊標
2.1什麽是遊標
用於臨時存儲一個查詢返回的多行數據(結構集,類似於Java的jdbc連接返回的ResultSet集合),通過遍歷遊標,可以逐行訪問處理該結果集的數據。
遊標的使用方式:聲明--à打開à讀取à關閉
2.2語法
遊標聲明:
cursor 遊標名[(參數列表)] is 查詢語句;
遊標的打開:
open 遊標名;
遊標的取值:
fetch 遊標名 into 變量列表;
遊標的關閉:
close 遊標名;
2.3遊標的屬性
遊標的屬性 |
返回值類型 |
說明 |
%ROWCOUNT |
整型 |
獲得fetch語句返回的數據行數 |
%FOUND |
布爾型 |
最近的fetch語句返回一行數據則為真,否則為假 |
%NOTFOUNT |
布爾型 |
與%FOUND屬性返回值相反 |
%ISOPEN |
布爾型 |
遊標已經打開時值為真,否則為假 |
其中%NOTFOUND是在遊標中找不到元素的時候返回TRUE,通常用來判斷退出循環
2.4創建和使用
無參遊標
【示例】使用遊標查詢emp表中所有員工的姓名和工資,並將其依次打印出來。
declare --聲明遊標 cursor c_emp is select ename,sal from emp; --聲明變量用來接受遊標中的元素 v_ename emp.ename%type; v_sal emp.sal%type; begin --打開遊標 open c_emp; 遍歷遊標 loop --獲取遊標中的數據 fetch c_emp into v_ename,v_sal; --退出循壞條件 exit when c_emp%notfound; dbms_output.put_line(‘姓名:’||v_name||’,薪水:’||v_sal); end loop; --關閉遊標 close c_emp; end;
帶參遊標
【示例】使用遊標查詢並打印某部門的員工的姓名和薪資,部門編號為運行時手動輸入。
declare --聲明遊標 cursor c_emp(v_deptno emp.deptno%type) is select ename,sal from emp where deptno=v_deptno; --聲明變量用來接受遊標中的元素 v_ename emp.ename%type; v_sal emp.sal%type; begin --打開遊標 open c_emp; 遍歷遊標 loop --獲取遊標中的數據 fetch c_emp into v_ename,v_sal; --退出循壞條件 exit when c_emp%notfound; dbms_output.put_line(v_name || v_sal); end loop; --關閉遊標 close c_emp; end;
3、存儲過程
3.1概念作用
之前我們編寫的PLSQL語句程序可以進行表的操作,判斷,循環邏輯處理的工作,但無法重復調用。可以理解之前的代碼全部編寫在了main方法中,是匿名程序。Java可以通過封裝對象和方法來解決復用問題,PLSQL是將一個個PLSQL的業務處理過程存儲起來進行復用,這些被存儲起來的PLSQL程序稱之為存儲過程。
存儲過程作用:
- 在開發過程中,為了一個特定的業務功能,會向數據庫進行多次連接關閉(連接和關閉是很耗費資源),需要對數據庫進行多次I/O讀寫,性能比較低。如果把這些業務放到PLSQL中,在應用程序中只需要調用PPLSQL就可以做到連接關閉一次數據庫就可以實現我們的業務,可以大大提高效率。
- ORACLE官方給的建議:能夠讓數據庫操作的不要放在程序中。在數據庫中實現基本上不會出現錯誤,在程序中操作可能會存在錯誤。(如果在數據庫中操作數據,可以有一定的日誌恢復等功能)
3.2語法
create or replace procedure 過程名稱[(參數列表)] is begin end [過程名稱];
根據參數的類型,我們將其分為3類講解:
不帶參數的
帶輸入參數的
帶輸入輸出參數(返回值)的
3.3無參存儲
3.3.1創建存儲
3.3.2調用存儲
create or replace procedure p_hello as begin dbms_output.put_line(‘hello word’); end p_hello; begin p_hello; end;
exec p_hello; -----sqlplus
註:is和as是可以會用的,用哪個都沒有關系;過程中沒有declare關鍵字,declare用在語句塊中
3.4帶輸入參數的存儲過程
【示例】查詢並打印某個員工(如7839號員工)的姓名和薪水—存儲過程:要求:調用的時候傳入員工編號,自動控制臺打印。
create or replace procedure p_querynameandsal(v_empno in emp.empno%type) is --聲明變量接受查詢結果 v_name emp.ename%type; v_sal emp.sal%type; begin --查詢emp表中某個員工的姓名和薪水並賦值給變量 select ename,sal into v_name,v_sal from emp where empno=v_empno; dbms_output.put_line(v_name || v_sal); end;
declare i integer; begin p_querynameandsal(7839); end exec p_querynameandsal(7839);
3.5帶輸出參數的存儲過程
【示例】輸入員工號查詢某個員工(7839號員工)信息,要求,將薪水作為返回值輸出,給調用的程序使用。
create or replace procedure p_querysal_out(v_empno in emp.empno%type,o_sal out emp.sal%type) as begin select sal into o_sal from emp where empno=v_empno; end;
declare v_sal emp.sal%type; begin p_querysal_out(7839,v_sal); dbms_output.put_line(v_sal); end
3.6JAVA程序調用存儲過程
需求:如果一條語句無法實現結構集,比如需要多表查詢,或者需要復雜邏輯查詢,我們可以選擇調用存儲出你的結果。
結論:通過 Connection對象的prepareCall方法傳遞一個轉義SQL語句可以實現調用存儲過程。輸入參數直接調用set方法傳遞,輸出參數需要註冊後,執行存儲過程,通過get方法獲取,參數列表的下標是從1開始的。
public interface CallableStatement
- extends PreparedStatement
用於執行SQL存儲過程的界面。 JDBC API提供了存儲過程SQL轉義語法,允許以標準方式為所有RDBMS調用存儲過程。 此轉義語法包含一個結果參數和不包含結果參數的表單。 如果使用,結果參數必須註冊為OUT參數。 其他參數可用於輸入,輸出或兩者。 參數按順序依次引用,第一個參數為1。
{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
{call <procedure-name>[(<arg1>,<arg2>, ...)]}
IN參數值使用從PreparedStatement繼承的set方法設置。 所有OUT參數的類型必須在執行存儲過程之前進行註冊; 它們的值通過這裏提供的get方法在執行get 。
import oracle.jdbc.OracleTypes; import java.sql.CallableStatement; import java.sql.DriverManager; import java.sql.Connection; public class JdbcTest{ public static void main(String[] args){ //1.加載驅動 Class.forName(“oracle.jdbc.driver.PracleDriver”); //2.獲取連接 String url=”jdbc:oracle:thin:@localhost:1521:xe”; String name=”scott”; String password=”tigger”; Connection conn=DriverManager.getConnection(url,name,password); //3.獲取語句對象 String sql=”{call p_querysal_out(?,?)}”; CallableStatement call=conn.prepareCall(sql); //4.設置輸出參數 call.setInt(1,7839); //5.註冊輸出參數 call.registerOutParameter(2,OracleTypes.DOUBLE); //6.執行存儲過程 call.execute(); //7.獲取輸出參數 double sal=call.getDouble(2); System.out.println(“薪水:”+sal); //8.釋放資源 call.close(); conn.close(); } }
視頻整理:https://www.bilibili.com/video/av46777605
基於oracle數據庫存儲過程的創建及調用