存儲過程:
存儲過程是 SQL, PL/SQL, Java 語句的組合, 它使你能將執行商業規則的代碼從你的應用程序中移動到數據庫。這樣的結果就是,代碼存儲一次但是能夠被多個程序使用。是存放在數據庫服務器上的SQL語句塊,其效率高於同等SQL語句6-10倍
下面通過例子讓你了解存儲過程對數據的增刪查改(對Oracle中的emp操作)
一、Oracle存儲過程語法:
Create [or replace] procedure 存儲過程名稱 (輸入參數或輸出參數)]as
變量
Begin
執行主體
End;
二、IN, OUT , IN OUT 用來修飾參數。
IN 表示這個變量必須被調用者賦值然后傳入到 PROCEDURE 進行處理。
OUT 表示 PRCEDURE 通過這個變量將值傳回給調用者。
IN OUT 則是這兩種的組合。
三、執行存儲過程方式:
1、Call 存儲過程名稱(參數);
2、Execute 存儲過程名稱(參數);
注意:在oracle 數據庫中,call命令任何窗口都能使用,但是execute只能在命令窗口使用,否則會報無效的SQL語句的異常。
四、在存儲過程中需要注意事項:
1、在oracle數據庫存儲過程中,表別名不能用as
2、在oracle數據庫存儲過程中,select某一字段時,后面必須緊跟into,如果select整個記錄則必須使用游標處理
3、在使用select....into....時必須保證數據庫有該數據,否則報”no data found”異常
4、在存儲過程中,別名不能和字段名相同,否則雖然編譯能通過,但是運行結果會報錯
五、存儲過程基本語法
--案例一:無參存儲過程 --1.創建結構 CREATE PROCEDURE procedureName--存儲過程名字 AS --as可替換成 is --聲明變量 BEGIN --執行主體 END; --2.案例 create or replace procedure firstPro is begin dbms_output.put_line('Hello World');--打印輸出 exception --存儲過程異常 WHEN OTHERS THEN ROLLBACK; end firstPro; --3.數據庫調用存儲過程:執行結果:output: Hello World --(21) begin-end begin firstPro(); end; --(22)call call firstPro(); --4.刪除存儲過程 drop procedure firstPro;
--案例二:帶參存儲過程(in:入參) --1.案例 create or replace procedure secondPro(num in number) as begin dbms_output.put_line('The input num is :'||num); end; --2.調用 --(21) call secondPro(4); --(22) begin secondPro(7); end; --(23) declare n number; begin n := 1; secondPro(num=>n); end; --or Begin secondPro(num=>1); end; --備注:=> 是 Oracle 中調用 存儲過程的時候, 指定 參數名進行調用 --一般如果是按順序填寫參數的時候,是不需要用=>符號的, --但是Oracle可以讓你在調用的時候,指定"參數名稱=>參數值", 這樣就可以不按參數的順序進行調用. -- => 前面的變量為存儲過程的“形參”且必須於存儲過程中定義的一致,而=>后的參數為“實際參數”。
--案例三:存儲過程:聲明變量 --1.案例 CREATE OR REPLACE procedure thirdPro is n_start number; n_end number; count_num number; use_time number; begin n_start:=dbms_utility.get_time; dbms_output.put_line('This statement start time : '|| n_start ); --查看oracle數據庫版本 SELECT count(*) into count_num FROM v$version; n_end:=dbms_utility.get_time; dbms_output.put_line('This statement end time : '|| n_end ); use_time:= n_end - n_start; dbms_output.put_line('This statement cost '|| use_time ||' miliseconds'); end; --備注: --(1)dbms_utility.get_time 返回當前時間的1/100秒,毫秒 --它是用以前后兩個取點做對s比的,單個是沒有具體意義的,就是用來取差值的! --2.執行存儲過程 --(21) call thirdPro(); --(22) begin thirdPro(); end;
--案例四:動態sql語句執行 --1.案例 CREATE OR REPLACE PROCEDURE FourthProc(id varchar2 ,dicName VARCHAR2) AS mysql VARCHAR2(500); BEGIN mysql:='UPDATE sys_dictionary SET dic_name=:1 WHERE id=:2'; EXECUTE IMMEDIATE mysql USING dicName,id; commit; END; --2.執行存儲過程 CALL FourthProc('22ff8102-95cd-4862-a2ec-d011eca75ef1','男')
--案例五:返回結果集 --1.案例 create or replace procedure FifthPro( cur_OUT OUT SYS_REFCURSOR ) is begin OPEN cur_OUT FOR select cname,merch_no,taxno zjid,'營業執照' zjname,BUSINESS_LICENSE_VALIDITY validity,trunc(BUSINESS_LICENSE_VALIDITY-sysdate) gqdate from quas.base_merchant where BUSINESS_LICENSE_VALIDITY-sysdate < 60 ; end FifthPro;
2.案例五:Test測試存儲過程步驟:Test-》點擊Start Debugger 按鈕:開始執行存儲過程-》點擊run按鈕存儲過程直接執行到結束,返回如圖2的結果Cursor->點擊右上角的按鈕,查看結果集:如圖3所示。(若點擊step into 按鈕,則進入存儲過程詳細代碼,按步執行)
3.java代碼執行存儲過程:
/** * */ package kklazy.reportquery.service; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.transaction.Transactional; import org.hibernate.Session; import org.hibernate.internal.SessionFactoryImpl; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import kklazy.ctps.service.DefaultCtpsService; import kklazy.reportquery.model.ReportQueryEntity; import oracle.jdbc.internal.OracleTypes; /** * @author Administrator * */ @Service("fifthProService") @Transactional(rollbackOn=Exception.class) public class FifthProService extends DefaultCtpsService<ReportQueryEntity, String>{ //注入jdbc連接參數 @Value("${ctps.database.driver}") private String driverClass; @Value("${ctps.database.url}") private String url; @Value("${ctps.database.username}") private String username; @Value("${ctps.database.password}") private String password; /** * 執行存儲過程 */ public List<ReportQueryEntity> execute() { Session session = (Session) this.getJpa().getManager().getDelegate(); SessionFactoryImpl sessionFactory = (SessionFactoryImpl) session.getSessionFactory(); Connection conn = null; ResultSet result = null; List<ReportQueryEntity> allList = new ArrayList<ReportQueryEntity>(); try { conn = sessionFactory.getConnectionProvider().getConnection(); if (conn == null || conn.isClosed()) { try { Class.forName(driverClass); conn = DriverManager.getConnection(url, username, password); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } catch (SQLException e) { e.printStackTrace(); } try { CallableStatement call = conn.prepareCall("{call FifthPro(?,?)}"); System.out.println(); call.setString(1, "00"); call.registerOutParameter(2, OracleTypes.CURSOR); call.execute(); result = (ResultSet)call.getObject(2); if(result == null) { System.out.println("查詢失敗!"); }else { allList = getFindList(result); System.out.println("查詢成功"); } System.out.println("執行存儲過程的結果是:" + result); } catch (SQLException e) { e.printStackTrace(); System.out.println(e); }finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } return allList; } public List<ReportQueryEntity> getFindList(ResultSet result) throws SQLException{ List<ReportQueryEntity> allList = new ArrayList<ReportQueryEntity>(); if(null !=result ) { while (result.next()) { ReportQueryEntity reportEntity = new ReportQueryEntity(); reportEntity.setData1(result.getString(1)); reportEntity.setData2(result.getString(2)); reportEntity.setData3(result.getString(3)); reportEntity.setData4(result.getString(4)); reportEntity.setData5(result.getString(5)); reportEntity.setData6(result.getString(6)); allList.add(reportEntity); } } return allList; } }
案例六、查詢所有數據(游標的具體使用詳見:https://www.cnblogs.com/xiaoliu66007/p/7495753.html)
PL/SQL 中 SELECT 語句只返回一行數據。如果超過一行數據,那么就要使用顯式游標,INTO 子句中要有 SELECT子句中相同列數量的變量。
INTO 子句中也可以是記錄變量。
--案例六:顯式游標 --------1.用游標顯示查詢所有的結果 CREATE OR REPLACE procedure sys_dictionary_proc AS CURSOR dictionary_emp IS SELECT * FROM sys_dictionary where dic_group ='OPERATE_TYPE';--定義游標,該游標指向查詢結果 rowresult sys_dictionary%ROWTYPE; BEGIN OPEN dictionary_emp;--打開游標 LOOP FETCH dictionary_emp INTO rowresult;--將游標中的值賦給rowresult EXIT WHEN dictionary_emp%NOTFOUND;--判斷:游標不存在時跳出循環 dbms_output.put_line('分組:'||rowresult.dic_group||'值:'||rowresult.DIC_VALUE||'顯示名:'||rowresult.dic_name); END LOOP; CLOSE dictionary_emp;--關閉游標 END; drop procedure sys_dictionary_proc; --2.調用 CALL sys_dictionary_proc();
3.output結果:
分組:OPERATE_TYPE值:1顯示名:新增
分組:OPERATE_TYPE值:2顯示名:修改
分組:OPERATE_TYPE值:3顯示名:刪除