【Oracle基礎】存儲過程,存儲函數,觸發器,java調用存儲過程

【Oracle基礎】存儲過程,存儲函數,觸發器,java調用存儲過程

1. 存儲過程

存儲過程(Stored Procedure)是在大型數據庫系統中,一組爲了完成特定功能的 SQL 語句集,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是數據庫中的一個重要對象,任何一個設計良好的數據庫應用程序都應該用到存儲過程。

簡單來說:存儲過程就是提前已經編譯好的一段pl/sql語言,放置在數據庫端,可以直接被調用。這一段pl/sql一般都是固定步驟的業務。

  • 語法
create [or replace] PROCEDURE 過程名[(參數名 in/out 數據類型)]
AS
begin
	PLSQL 子程序體;
End;

或者

create [or replace] PROCEDURE 過程名[(參數名 in/out 數據類型)]
is
begin
	PLSQL 子程序體;
End 過程名;
  • 示例
---給指定員工漲100塊錢
create or replace procedure p1(eno emp.empno%type)
as
begin
  update emp set sal=sal+100 where empno=eno;
  commit;
end;
  • 調用
--測試pl
declare 

begin
  p1(7788);
end;

2. 存儲函數

  • 語法
create or replace function 函數名(Name in type, Name in type, ...) return 數據類型 is
	結果變量 數據類型;
begin
	return(結果變量);
end 函數名;
  • 存儲過程和存儲函數的區別
    一般來講,過程和函數的區別在於函數可以有一個返回值;而過程沒有返回值。
    但過程和函數都可以通過 out 指定一個或多個輸出參數。我們可以利用 out 參數,在過程和函數中實現返回多個值。
    如果存儲過程想實現有返回值的業務,我們就必須使用out類型和參數。
    即便是存儲過程使用了out類型的參數,其本質也不是真的有了返回值。
    而是在存儲過程內部給out類型參數賦值,在執行完畢後,我們直接拿着用。
---通過存儲函數實現計算指定員工的年薪
---存儲過程和存儲函數的參數都不能帶長度
---存儲函數的返回值類型不能帶長度
create or replace function f_yearsal(eno emp.empno%type) return number
is
  s number(10);
begin
  select sal*12+nvl(comm,0) into s from emp where empno=eno;
  return s;
end f_yearsal;

--測試f_yearsal
---存儲函數在調用的時候,返回值需要接收
declare 
  s number(10);
begin
  s := f_yearsal(7788);
  dbms_output.put_line(s);
end;

---out類型參數如何使用
---使用存儲過程來算年薪
create or replace procedure p_yearsal(eno emp.empno%type,yearsal out number)
is
  s number(10);
  c emp.comm%type;
begin
  select sal*12,nvl(comm,0) into s,c from emp where empno=eno;
  yearsal := s+c;
end;

---測試p_yearsal
declare
  yearsal number(10);
begin
  p_yearsal(7788,yearsal);
  dbms_output.put_line(yearsal);
end;

--in和out類型的區別是什麼?
---凡是涉及到into查詢語句賦值或者:=賦值操作的參數,都必須使用out來修飾

3. 觸發器

數據庫觸發器是一個與表相關聯的、存儲的 PL/SQL 程序。每當一個特定的數據操作語句(Insert,update,delete)在指定的表上發出時, Oracle 自動地執行觸發器中定義的語句序列

  • 觸發器可用於
  1. 數據確認
  2. 實施複雜的安全性檢查
  3. 做審計,跟蹤表上所做的數據操作等
  4. 數據的備份和同步
  • 觸發器的類型

    • 語句級觸發器 : 在指定的操作語句操作之前或之後執行一次,不管這條語句影響了多少行 。
    • 行級觸發器(FOR EACH ROW) : 觸發語句作用的每一條記錄都被觸發。在行級觸發器中使用 old 和 new 僞記錄變量, 識別值的狀態。
  • 語法

CREATE [or REPLACE] TRIGGER 觸發器名
	{BEFORE | AFTER}
	{DELETE | INSERT | UPDATE [OF 列名]}
	ON 表名
	[FOR EACH ROW [WHEN(條件) ] ]
begin
	PLSQL 塊
End 觸發器名
---觸發器,就是指定一個規則,在我們做增刪改操作的時候,
-------只要滿足該規則,自動觸發,無需調用
-------語句級觸發器
-------行級觸發器:包含有for each row的就是行級觸發器。
-------------------加for each row是爲了使用:old或者:new對象或者一行記錄。

----插入一條記錄,輸出一個新員工入職
--語句級觸發器
create or replace trigger t1
after 
insert
on person
declare
begin
  dbms_output.put_line('一個新員工入職');
end;
---觸發t1
select * from person;
insert into person values(1,'小紅');
commit;

--行級觸發器
create or replace trigger t2
before 
update
on emp
for each row
declare
begin
  if :old.sal>:new.sal then
    raise_application_error(-20001,'不能給員工降薪');
  end if;
end;

--觸發t2
update emp set sal=sal-1 where empno=7788;
commit;

--觸發器實現主鍵自增
---分析:在用戶做插入操作的之前,拿到即將插入的數據,給該數據中的主鍵列賦值。
create or replace trigger auid
before
insert
on person
for each row
declare
begin
  select s_person.nextval into :new.pid from dual;
end;
--使用autoid實現主鍵自增
insert into person(pname) values('a');
commit;

select * from person

在這裏插入圖片描述

4. java調用存儲過程

首先我們可以在虛擬機中oracle 安裝目錄下找到 jar 包 :ojdbc14.jar
當然也可以使用maven工程導入座標。
在這裏插入圖片描述

package com.siyi.oracle;

import oracle.jdbc.OracleTypes;
import oracle.jdbc.oracore.OracleType;
import org.junit.Test;

import java.sql.*;

public class OracleDemo {

    @Test
    public void javaCallOracle() throws ClassNotFoundException, SQLException {
        //加載數據庫驅動
        Class.forName("oracle.jdbc.driver.OracleDriver");
        //得到Connection連接
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.105:1521:orcl", "siyi", "siyi");
        //得到預編譯的Statement對象
        PreparedStatement ps = connection.prepareStatement("select * from emp where empno = ?");
        ps.setObject(1,7788);
        //執行數據庫查詢操作
        ResultSet resultSet = ps.executeQuery();
        //輸出結果
        while(resultSet.next()){
            System.out.println(resultSet.getString("ename"));
        }
        //釋放資源
        resultSet.close();
        ps.close();
        connection.close();
    }

    /**
     * java調用存儲過程
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    @Test
    public void javaCallProcedure() throws ClassNotFoundException, SQLException {
        //加載數據庫驅動
        Class.forName("oracle.jdbc.driver.OracleDriver");
        //得到Connection連接
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.105:1521:orcl", "siyi", "siyi");
        //得到預編譯的Statement對象
        CallableStatement cs = connection.prepareCall("call p_yearsal(?,?)");
        cs.setObject(1,7788);
        cs.registerOutParameter(2, OracleTypes.NUMBER);
        //執行數據庫查詢操作
        cs.executeQuery();
        //輸出結果
        System.out.println(cs.getObject(2));
        //釋放資源
        cs.close();
        connection.close();
    }

    /**
     * java調用存儲函數
     * @throws ClassNotFoundException
     * @throws SQLException
     */
    @Test
    public void javaCallFunction() throws ClassNotFoundException, SQLException {
        //加載數據庫驅動
        Class.forName("oracle.jdbc.driver.OracleDriver");
        //得到Connection連接
        Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.0.105:1521:orcl", "siyi", "siyi");
        //得到預編譯的Statement對象
        CallableStatement cs = connection.prepareCall("{?= call f_yearsal(?)}");
        cs.setObject(2,7788);
        cs.registerOutParameter(1, OracleTypes.NUMBER);
        //執行數據庫查詢操作
        cs.executeQuery();
        //輸出結果
        System.out.println(cs.getObject(1));
        //釋放資源
        cs.close();
        connection.close();
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章