作者: kent鵬 轉載請註明出處: http://www.cnblogs.com/xieyupeng/p/7476717.html 1.游標(游標)Cursor 在寫java程式中有集合的概念,那麼在pl/sql中也會用到多條記錄,這時候我們就要用到游標,游標可以存儲查詢返回的多條數據。 語法: ...
作者: 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連接oracle的jar包
可以在虛擬機中xp的oracle安裝目錄下找到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(); } }
作者: kent鵬
出處: http://www.cnblogs.com/xieyupeng/
關於作者:專註JAVAEE領域,請多多賜教!
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。