1. 程式人生 > >Oracle03——遊標、異常、存儲過程、存儲函數、觸發器和Java代碼訪問Oracle對象

Oracle03——遊標、異常、存儲過程、存儲函數、觸發器和Java代碼訪問Oracle對象

height 微軟 數值 getc statement 數據類型 put print .exe

作者: kent鵬

轉載請註明出處: http://www.cnblogs.com/xieyupeng/p/7476717.html

1.遊標(光標)Cursor

在寫java程序中有集合的概念,那麽在pl/sql中也會用到多條記錄,這時候我們就要用到遊標,遊標可以存儲查詢返回的多條數據。

語法:

CURSOR 遊標名 [ (參數名 數據類型,參數名 數據類型,...)] IS SELECT 語句;

例如:cursor c1 is select ename from emp;

遊標的使用步驟:

  • 打開遊標: open c1; (打開遊標執行查詢)
  • 取一行遊標的值:fetch c1 into pjob; (取一行到變量中)
  • 關閉遊標: close c1;(關閉遊標釋放資源)
  • 遊標的結束方式 exit when c1%notfound
  • 註意: 上面的pjob必須與emp表中的job列類型一致:

定義:pjob emp.empjob%type;

光標屬性:%isopen %rowcount(影響的行數) %found %notfound

範例1:使用遊標方式輸出emp表中的員工編號和姓名

declare

  cursor pc is

    select * from emp;

  pemp emp%rowtype;

begin

  open pc;

  loop

    
fetch pc into pemp; exit when pc%notfound; dbms_output.put_line(pemp.empno || || pemp.ename); end loop; close pc; end;

範例2:寫一段PL/SQL程序,為部門號為10的員工漲工資。

declare

  cursor pc(dno myemp.deptno%type) is

    select empno from myemp where deptno = dno;

  pno myemp.empno%type;

begin open pc(20); loop fetch pc into pno; exit when pc%notfound; update myemp t set t.sal = t.sal + 1000 where t.empno = pno; end loop; close pc; end;

2.異常

異常是程序設計語言提供的一種功能,用來增強程序的健壯性和容錯性。

系統定義異常

no_data_found (沒有找到數據)

too_many_rows (select …into語句匹配多個行)

zero_divide ( 被零除)

value_error (算術或轉換錯誤)

timeout_on_resource (在等待資源時發生超時)

範例1:寫出被0除的異常的plsql程序

declare

  pnum number;

begin

  pnum := 1 / 0;

exception

  when zero_divide then

    dbms_output.put_line(被0除);

  when value_error then

    dbms_output.put_line(數值轉換錯誤);

  when others then

    dbms_output.put_line(其他錯誤);

end;

用戶也可以自定義異常,在聲明中來定義異常

DECLARE

My_job   char(10);

v_sal   emp.sal%type;

No_data    exception;

cursor c1 is select distinct job from emp    order by job;

如果遇到異常我們要拋出raise no_data;

範例2:查詢部門編號是50的員工

declare

  no_emp_found exception;

  cursor pemp is

    select t.ename from emp t where t.deptno = 50;

  pename emp.ename%type;

begin

  open pemp;

  fetch pemp

    into pename;

  if pemp%notfound then

    raise no_emp_found;

  end if;

  close pemp;

exception

  when no_emp_found then

    dbms_output.put_line(沒有找到員工);

  when others then

    dbms_output.put_line(其他錯誤);

end;

3.存儲過程

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

創建存儲過程語法:

create [or replace] PROCEDURE 過程名[(參數名 in/out 數據類型)]  

AS

begin

        PLSQL子程序體;

End;

或者

create [or replace] PROCEDURE 過程名[(參數名 in/out 數據類型)]  

is

begin

        PLSQL子程序體;

End  過程名;

範例1:給指定的員工漲100工資,並打印出漲前和漲後的工資

分析:我們需要使用帶有參數的存儲過程

create or replace procedure addSal1(eno in number) is

  pemp myemp%rowtype;

begin

  select * into pemp from myemp where empno = eno;

  update myemp set sal = sal + 100 where empno = eno;

  dbms_output.put_line(漲工資前 || pemp.sal || 漲工資後 || (pemp.sal + 100));

end addSal1;

調用

begin

  -- Call the procedure

  addsal1(eno => 7902);     

  commit;

end;

4.存儲函數

create or replace function 函數名(Name in type, Name out type, ...) return 數據類型 is

  結果變量 數據類型;

begin

  

  return(結果變量);

end[函數名];

存儲過程和存儲函數的區別

一般來講,過程和函數的區別在於函數可以有一個返回值;而過程沒有返回值。

但過程和函數都可以通過out指定一個或多個輸出參數。我們可以利用out參數,在過程和函數中實現返回多個值。

範例:使用存儲函數來查詢指定員工的年薪

create or replace function empincome(eno in emp.empno%type) return number is

  psal  emp.sal%type;

  pcomm emp.comm%type;

begin

  select t.sal into psal from emp t where t.empno = eno;

  return psal * 12 + nvl(pcomm, 0);

end;

使用存儲過程來替換上面的例子

create or replace procedure empincomep(eno in emp.empno%type, income out number) is

  psal emp.sal%type;

  pcomm emp.comm%type;

begin

  select t.sal, t.comm into psal, pcomm from emp t where t.empno = eno;

  income := psal*12+nvl(pcomm,0);

end empincomep;

調用:

declare

  income number;

begin

  empincomep(7369, income);

  dbms_output.put_line(income);

end;

5.觸發器

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

1.觸發器作用

l 數據確認

l 實施復雜的安全性檢查

l 做審計,跟蹤表上所做的數據操作等

l 數據的備份和同步

2.觸發器的類型

語句級觸發器 :在指定的操作語句操作之前或之後執行一次,不管這條語句影響 了多少行

行級觸發器(FOR EACH ROW) :觸發語句作用的每一條記錄都被觸發。在行級觸 發器中使用old和new偽記錄變量, 識別值的狀態。

語法:

CREATE  [or REPLACE] TRIGGER  觸發器名

   {BEFORE | AFTER}

   {DELETE | INSERT | UPDATE [OF 列名]}

   ON  表名

   [FOR EACH ROW [WHEN(條件) ] ]

declare

    ……

begin

   PLSQL 塊 

End 觸發器名

範例:插入員工後打印一句話“一個新員工插入成功”

create or replace trigger testTrigger

  after insert on person  

declare

  -- local variables here

begin

  dbms_output.put_line(一個員工被插入);

end testTrigger;

範例:不能在休息時間插入員工

create or replace trigger validInsertPerson

  before insert on person

 

declare

  weekend varchar2(10);

begin

  select to_char(sysdate, day) into weekend from dual;

  if weekend in (星期一) then

    raise_application_error(-20001, 不能在非法時間插入員工);

  end if;

end validInsertPerson;

當執行插入時會報錯

在觸發器中觸發語句與偽記錄變量的值

觸發語句

:old

:new

Insert

所有字段都是空(null)

將要插入的數據

Update

更新以前該行的值

更新後的值

delete

刪除以前該行的值

所有字段都是空(null)

範例:判斷員工漲工資之後的工資的值一定要大於漲工資之前的工資

create or replace trigger addsal4p

  before update of sal on myemp

  for each row

begin

  if :old.sal >= :new.sal then

    raise_application_error(-20002, 漲前的工資不能大於漲後的工資);

  end if;

end;

調用

update myemp t set t.sal = t.sal - 1;

3.觸發器實際應用

需求:使用序列,觸發器來模擬mysql中自增效果

1. 創建序列

1、建立表

復制代碼 代碼如下:

create table user  (   

    id   number(6) not null,   

    name   varchar2(30)   not null primary key  

)  

2、建立序列SEQUENCE

代碼如下:

create sequence user_seq increment by 1 start with 1 minvalue 1 maxvalue 9999999999999 nocache order;

2.創建自增的觸發器

分析:創建一個基於該表的before insert 觸發器,在觸發器中使用剛創建的SEQUENCE

代碼如下:

create or replace trigger user_trigger   

before insert on user  

for each row   

begin  

      select   user_seq.nextval  into:new.id from sys.dual ;   

end;  

3.測試效果

insert into itcastuser(name) values(aa);

commit;

insert into itcastuser(name) values(bb);

commit;

5.Java代碼訪問Oracle對象

1.java連接oraclejar

可以在虛擬機中xporacle安裝目錄下找到jar:ojdbc14.jar

2.數據庫連接字符串

String driver="oracle.jdbc.OracleDriver";

String url="jdbc:oracle:thin:@192.168.56.10:1521:orcl";

String username="scott";

String password="tiger";


測試代碼:

技術分享

3.實現過程與函數的調用

1.調用過程

1.過程定義
--統計年薪的過程

create or replace procedure proc_countyearsal(eno in number,esal out number)

as

begin

   select sal*12+nvl(comm,0) into esal from emp where empno=eno;

end;

 

--調用

declare

   esal number;

begin

   proc_countyearsal(7839,esal);

   dbms_output.put_line(esal);

end;

2.過程調用
    @Test
    public void testProcedure01() {

        String driver = "oracle.jdbc.OracleDriver";

        String url = "jdbc:oracle:thin:@192.168.56.10:1521:orcl";

        String username = "scott";

        String password = "tiger";

        try {

            Class.forName(driver);

            Connection con = DriverManager.getConnection(url, username, password);

            CallableStatement callSt = con.prepareCall("{call proc_countyearsal(?,?)}");

            callSt.setInt(1, 7839);

            callSt.registerOutParameter(2, OracleTypes.NUMBER);

            callSt.execute();

            System.out.println(callSt.getObject(2));

        } catch (Exception e) {

            e.printStackTrace();

        }

    }


2.調用函數

1.函數定義
--統計年薪的函數

create or replace function fun_countyearsal(eno in number)

return number

as

   esal number:=0;

begin

  select sal*12+nvl(comm,0) into esal from emp where empno=eno;

  return esal;

end;

 

--調用

declare

   esal number;

begin

   esal:=fun_countyearsal(7839);

   dbms_output.put_line(esal);

end;

2.函數調用
    @Test
    public void testFunction01() {

        String driver = "oracle.jdbc.OracleDriver";

        String url = "jdbc:oracle:thin:@192.168.56.10:1521:orcl";

        String username = "scott";

        String password = "tiger";

        try {

            Class.forName(driver);

            Connection con = DriverManager.getConnection(url, username, password);

            CallableStatement callSt = con.prepareCall("{?= call fun_countyearsal(?)}");

            callSt.registerOutParameter(1, OracleTypes.NUMBER);

            callSt.setInt(2, 7839);

            callSt.execute();

            System.out.println(callSt.getObject(1));

        } catch (Exception e) {

            e.printStackTrace();

        }

    }


4.遊標引用的java測試

1.定義過程,並返回引用型遊標

--定義過程

create or replace procedure proc_cursor_ref(dno in number,empList out sys_refcursor)

as

begin

  open empList for select * from emp where deptno = dno;

end;

 

--pl/sql中調用

declare

  mycursor_c sys_refcursor;

  myempc emp%rowtype;

begin

  proc_cursor_ref(20,mycursor_c);

  

  loop

    fetch mycursor_c into myempc;

    exit when mycursor_c%notfound;

    dbms_output.put_line(myempc.empno||,||myempc.ename);

  end loop;

  close mycursor_c;

end;

2.java代碼調用遊標類型的out參數

    @Test
    public void testFunction() {

        String driver = "oracle.jdbc.OracleDriver";

        String url = "jdbc:oracle:thin:@192.168.56.10:1521:orcl";

        String username = "scott";

        String password = "tiger";

        try {

            Class.forName(driver);

            Connection con = DriverManager.getConnection(url, username, password);

            CallableStatement callSt = con.prepareCall("{call proc_cursor_ref (?,?)}");

            callSt.setInt(1, 20);

            callSt.registerOutParameter(2, OracleTypes.CURSOR);

            callSt.execute();

            ResultSet rs = ((OracleCallableStatement) callSt).getCursor(2);

            while (rs.next()) {

                System.out.println(rs.getObject(1) + "," + rs.getObject(2));

            }

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

Oracle03——遊標、異常、存儲過程、存儲函數、觸發器和Java代碼訪問Oracle對象