亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

存儲過程常用技巧3

系統 1690 0

3.4 select into不可乎視的問題
我們知道在pl/sql中要想從數據表中向變量賦值,需要使用select into 子句。
但是它會帶動來一些問題,如果查詢沒有記錄時,會拋出no_data_found異常。
如果有多條記錄時,會拋出too_many_rows異常。
這個是比較糟糕的。一旦拋出了異常,就會讓過程中斷。特別是no_data_found這種異常,沒有嚴重到要讓程序中斷的地步,可以完全交給由程序進行處理。

Java代碼 復制代碼
  1. create?or?replace?procedure?procexception(p?varchar2) ??
  2. as? ??
  3. ??v_postype?varchar2( 20 ); ??
  4. begin ??
  5. ???select?pos_type?into?v_postype?from?pos_type_tbl?where? 1 = 0 ; ??
  6. ????dbms_output.put_line(v_postype); ??
  7. end; ??
  8. ??????
    create or replace procedure procexception(p varchar2)
as 
  v_postype varchar2(20);
begin
   select pos_type into v_postype from pos_type_tbl where 1=0;
    dbms_output.put_line(v_postype);
end;
	
  

執行這個過程

Java代碼 復制代碼
  1. SQL>?exec?procexception( 'a' ); ??
  2. 報錯 ??
  3. ORA- 01403 :?no?data?found ??
  4. ORA- 06512 :?at? "LIFEMAN.PROCEXCEPTION" ,?line? 6 ??
  5. ORA- 06512 :?at?line? 1 ??
    SQL> exec procexception('a');
報錯
ORA-01403: no data found
ORA-06512: at "LIFEMAN.PROCEXCEPTION", line 6
ORA-06512: at line 1
  


處理這個有三個辦法
1. 直接加上異常處理。

Java代碼 復制代碼
  1. create?or?replace?procedure?procexception(p?varchar2) ??
  2. as? ??
  3. ??v_postype?varchar2( 20 ); ??
  4. ?? ??
  5. begin ??
  6. ???select?pos_type?into?v_postype?from?pos_type_tbl?where? 1 = 0 ; ??
  7. ????dbms_output.put_line(v_postype); ??
  8. exception? ??
  9. ??when?no_data_found?then ??
  10. ????dbms_output.put_line( '沒找到數據' ); ??
  11. end;??
    create or replace procedure procexception(p varchar2)
as 
  v_postype varchar2(20);
  
begin
   select pos_type into v_postype from pos_type_tbl where 1=0;
    dbms_output.put_line(v_postype);
exception 
  when no_data_found then
    dbms_output.put_line('沒找到數據');
end;
  

這樣做換湯不換藥,程序仍然被中斷??赡苓@樣不是我們所想要的。
2. select into做為一個獨立的塊,在這個塊中進行異常處理

Java代碼 復制代碼
  1. create?or?replace?procedure?procexception(p?varchar2) ??
  2. as? ??
  3. ??v_postype?varchar2( 20 ); ??
  4. ?? ??
  5. begin ??
  6. ??begin ??
  7. ???select?pos_type?into?v_postype?from?pos_type_tbl?where? 1 = 0 ; ??
  8. ????dbms_output.put_line(v_postype); ??
  9. ?exception? ??
  10. ??when?no_data_found?then ??
  11. ????v_postype?:=? '' ; ??
  12. ??end; ??
  13. ??dbms_output.put_line(v_postype); ??
  14. end;??
    create or replace procedure procexception(p varchar2)
as 
  v_postype varchar2(20);
  
begin
  begin
   select pos_type into v_postype from pos_type_tbl where 1=0;
    dbms_output.put_line(v_postype);
 exception 
  when no_data_found then
    v_postype := '';
  end;
  dbms_output.put_line(v_postype);
end;
  

這是一種比較好的處理方式了。不會因為這個異常而引起程序中斷。
3.使用游標

Java代碼 復制代碼
  1. create?or?replace?procedure?procexception(p?varchar2) ??
  2. as? ??
  3. ??v_postype?varchar2( 20 ); ??
  4. ??cursor?c_postype?is?select?pos_type??from?pos_type_tbl?where? 1 = 0 ; ??
  5. begin ??
  6. ??open?c_postype; ??
  7. ????fetch?c_postype?into?v_postype; ??
  8. ??close?c_postype; ??
  9. ??dbms_output.put_line(v_postype); ??
  10. end;??
    create or replace procedure procexception(p varchar2)
as 
  v_postype varchar2(20);
  cursor c_postype is select pos_type  from pos_type_tbl where 1=0;
begin
  open c_postype;
    fetch c_postype into v_postype;
  close c_postype;
  dbms_output.put_line(v_postype);
end;
  

這樣就完全的避免了no_data_found異常。完全交由程序員來進行控制了。

第二種情況是too_many_rows 異常的問題。
Too_many_rows 這個問題比起no_data_found要復雜一些。
給一個變量賦值時,但是查詢結果有多個記錄。
處理這種問題也有兩種情況:
1. 多條數據是可以接受的,也就是說從結果集中隨便取一個值就行。這種情況應該很極端了吧,如果出現這種情況,也說明了程序的嚴謹性存在問題。
2. 多條數據是不可以被接受的,在這種情況肯定是程序的邏輯出了問題,也說是說原來根本就不會想到它會產生多條記錄。
對于第一種情況,就必須采用游標來處理,而對于第二種情況就必須使用內部塊來處理,重新拋出異常。
多條數據可以接受,隨便取一條,這個跟no_data_found的處理方式一樣,使用游標。
我這里僅說第二種情況,不可接受多條數據,但是不要忘了處理no_data_found哦。這就不能使用游標了,必須使用內部塊。

Java代碼 復制代碼
  1. create?or?replace?procedure?procexception2(p?varchar2) ??
  2. as? ??
  3. ??v_postype?varchar2( 20 ); ??
  4. ? ??
  5. begin ??
  6. ??begin ??
  7. ????select?pos_type?into?v_postype?from?pos_type_tbl?where?rownum?<? 5 ; ??
  8. ??exception ??
  9. ????when?no_data_found?then ??
  10. ??????v_postype?:= null ; ??
  11. ????when?too_many_rows?then ??
  12. ??????raise_application_error(- 20000 , '對v_postype賦值時,找到多條數據' ); ??
  13. ??end; ??
  14. ?dbms_output.put_line(v_postype); ??
  15. end;??
    create or replace procedure procexception2(p varchar2)
as 
  v_postype varchar2(20);
 
begin
  begin
    select pos_type into v_postype from pos_type_tbl where rownum < 5;
  exception
    when no_data_found then
      v_postype :=null;
    when too_many_rows then
      raise_application_error(-20000,'對v_postype賦值時,找到多條數據');
  end;
 dbms_output.put_line(v_postype);
end;
  

需要注意的是一定要加上對no_data_found的處理,對出現多條記錄的情況則繼續拋出異常,讓上一層來處理。
總之對于select into的語句需要注意這兩種情況了。需要妥當處理啊。

3.5 在存儲過程中返回結果集
我們使用存儲過程都是返回值都是單一的,有時我們需要從過程中返回一個集合。即多條數據。這有幾種解決方案。比較簡單的做法是寫臨時表,但是這種做法不靈活。而且維護麻煩。我們可以使用嵌套表來實現.沒有一個集合類型能夠與java的jdbc類型匹配。這就是對象與關系數據庫的阻抗吧。數據庫的對象并不能夠完全轉換為編程語言的對象,還必須使用關系數據庫的處理方式。

Java代碼 復制代碼
  1. create?or?replace? package ?procpkg?is ??
  2. ???type?refcursor?is?ref?cursor; ??
  3. ???procedure?procrefcursor(p?varchar2,?p_ref_postypeList??out?refcursor); ??
  4. end?procpkg; ??
  5. ??
  6. create?or?replace? package ?body?procpkg?is ??
  7. ??procedure?procrefcursor(p?varchar2,?p_ref_postypeList?out??refcursor) ??
  8. ??is ??
  9. ????v_posTypeList?PosTypeTable; ??
  10. ??begin ??
  11. ????v_posTypeList?:=PosTypeTable();--初始化嵌套表 ??
  12. ????v_posTypeList.extend; ??
  13. ????v_posTypeList( 1 )?:=?PosType( 'A001' , '客戶資料變更' ); ??
  14. ????v_posTypeList.extend; ??
  15. ????v_posTypeList( 2 )?:=?PosType( 'A002' , '團體資料變更' ); ??
  16. ????v_posTypeList.extend; ??
  17. ????v_posTypeList( 3 )?:=?PosType( 'A003' , '受益人變更' ); ??
  18. ????v_posTypeList.extend; ??
  19. ????v_posTypeList( 4 )?:=?PosType( 'A004' , '續期交費方式變更' ); ??
  20. ????open?p_ref_postypeList? for ??select?*?from?table(cast?(v_posTypeList?as?PosTypeTable)); ??
  21. ??end; ??
  22. end?procpkg;??
    create or replace package procpkg is
   type refcursor is ref cursor;
   procedure procrefcursor(p varchar2, p_ref_postypeList  out refcursor);
end procpkg;

create or replace package body procpkg is
  procedure procrefcursor(p varchar2, p_ref_postypeList out  refcursor)
  is
    v_posTypeList PosTypeTable;
  begin
    v_posTypeList :=PosTypeTable();--初始化嵌套表
    v_posTypeList.extend;
    v_posTypeList(1) := PosType('A001','客戶資料變更');
    v_posTypeList.extend;
    v_posTypeList(2) := PosType('A002','團體資料變更');
    v_posTypeList.extend;
    v_posTypeList(3) := PosType('A003','受益人變更');
    v_posTypeList.extend;
    v_posTypeList(4) := PosType('A004','續期交費方式變更');
    open p_ref_postypeList for  select * from table(cast (v_posTypeList as PosTypeTable));
  end;
end procpkg;
  


在包頭中定義了一個游標變量,并把它作為存儲過程的參數類型。
在存儲過程中定義了一個嵌套表變量,對數據寫進嵌套表中,然后把嵌套表進行類型轉換為table,游標變量從這個嵌套表中進行查詢。外部程序調用這個游標。
所以這個過程需要定義兩個類型。

Java代碼 復制代碼
  1. create?or?replace?type?PosType?as?Object?( ??
  2. ??posType?varchar2( 20 ), ??
  3. ??description?varchar2( 50 ) ??
  4. );??
    create or replace type PosType as Object (
  posType varchar2(20),
  description varchar2(50)
);
  

create or replace type PosTypeTable is table of PosType;
需要注意,這兩個類型不能定義在包頭中,必須單獨定義,這樣java層才能使用。

在外部通過pl/sql來調用這個過程非常簡單。

Java代碼 復制代碼
  1. set?serveroutput?on; ??
  2. declare? ??
  3. ??type?refcursor?is?ref?cursor; ??
  4. ??v_ref_postype?refcursor; ??
  5. ??v_postype?varchar2( 20 ); ??
  6. ??v_desc?varchar2( 50 ); ??
  7. begin ??
  8. ??procpkg.procrefcursor( 'a' ,v_ref_postype); ??
  9. ??loop ??
  10. ????fetch??v_ref_postype?into?v_postype,v_desc; ??
  11. ????exit?when?v_ref_postype%notfound; ??
  12. ????dbms_output.put_line( 'posType:' ||?v_postype?||? ';description:' ?||?v_desc); ??
  13. ??end?loop; ??
  14. end;??
    set serveroutput on;
declare 
  type refcursor is ref cursor;
  v_ref_postype refcursor;
  v_postype varchar2(20);
  v_desc varchar2(50);
begin
  procpkg.procrefcursor('a',v_ref_postype);
  loop
    fetch  v_ref_postype into v_postype,v_desc;
    exit when v_ref_postype%notfound;
    dbms_output.put_line('posType:'|| v_postype || ';description:' || v_desc);
  end loop;
end;
  


注意:對于游標變量,不能使用for循環來處理。因為for循環會隱式的執行open動作。而通過open for來打開的游標%isopen是為true的。也就是默認打開的。Open一個已經open的游標是錯誤的。所以不能使用for循環來處理游標變量。

我們主要討論的是如何通過jdbc調用來處理這個輸出參數。

Java代碼 復制代碼
  1. conn?=? this .getDataSource().getConnection(); ??
  2. CallableStatement?call?=?conn.prepareCall( "{call?procpkg.procrefcursor(?,?)}" ); ??
  3. call.setString( 1 ,? null ); ??
  4. call.registerOutParameter( 2 ,?OracleTypes.CURSOR); ??
  5. call.execute(); ??
  6. ResultSet?rsResult?=?(ResultSet)?call.getObject( 2 ); ??
  7. while ?(rsResult.next())?{ ??
  8. ??String?posType?=?rsResult.getString( "posType" ); ??
  9. ??String?description?=?rsResult.getString( "description" ); ??
  10. ??...... ??
  11. }??
    conn = this.getDataSource().getConnection();
CallableStatement call = conn.prepareCall("{call procpkg.procrefcursor(?,?)}");
call.setString(1, null);
call.registerOutParameter(2, OracleTypes.CURSOR);
call.execute();
ResultSet rsResult = (ResultSet) call.getObject(2);
while (rsResult.next()) {
  String posType = rsResult.getString("posType");
  String description = rsResult.getString("description");
  ......
}
  


這就是jdbc的處理方法。

Ibatis處理方法:
1.參數配置

Java代碼 復制代碼
  1. <parameterMap?id= "PosTypeMAP" ? class = "java.util.Map" >? ??
  2. ?<parameter?property= "p" ?jdbcType= "VARCHAR" ?javaType= "java.lang.String" ?/>? ??
  3. ?<parameter?property= "p_ref_postypeList" ?jdbcType= "ORACLECURSOR" ?javaType= "java.sql.ResultSet" ?mode= "OUT" ?typeHandler= "com.palic.elis.pos.dayprocset.integration.dao.impl.CursorHandlerCallBack" ?/>? ??
  4. </parameterMap> ??
  5. ??
  6. 2 .調用過程 ??
  7. ??<procedure?id?= "procrefcursor" ?parameterMap?= "PosTypeMAP" > ??
  8. ??????{call?procpkg.procrefcursor(?,?)} ??
  9. ??</procedure> ??
  10. ??
  11. 3 .定義自己的處理器 ??
  12. ?? public ? class ?CursorHandlerCallBack? implements ?TypeHandler{ ??
  13. ???? public ?Object?getResult(CallableStatement?cs,? int ?index)? throws ?SQLException?{ ??
  14. ????????ResultSet?rs?=?(ResultSet)cs.getObject(index); ??
  15. ????????List?result?=? new ?ArrayList(); ??
  16. ???????? while (rs.next())?{ ??
  17. ????????????String?postype?=rs.getString( 1 ); ??
  18. ????????????String?description?=?rs.getString( 2 ); ??
  19. ????????????CodeTableItemDTO?posTypeItem?=? new ?CodeTableItemDTO(); ??
  20. ????????????posTypeItem.setCode(postype); ??
  21. ????????????posTypeItem.setDescription(description); ??
  22. ????????????result.add(posTypeItem); ??
  23. ????????} ??
  24. ???????? return ?result; ??
  25. ????} ??
  26. ??
  27. ??
  28. ??
  29. 4 .?dao方法 ??
  30. ???? public ?List?procPostype()?{ ??
  31. ????????String?p?=? "" ; ??
  32. ????????Map?para?=? new ?HashMap(); ??
  33. ????????para.put( "p" ,p); ??
  34. ????????para.put( "p_ref_postypeList" , null ); ??
  35. ????????? this .getSqlMapClientTemplate().queryForList( "pos_dayprocset.procrefcursor" ,??para); ??
  36. ????????? return ?(List)para.get( "p_ref_postypeList" ); ??
  37. ????}??
    <parameterMap id="PosTypeMAP" class="java.util.Map"> 
 <parameter property="p" jdbcType="VARCHAR" javaType="java.lang.String" /> 
 <parameter property="p_ref_postypeList" jdbcType="ORACLECURSOR" javaType="java.sql.ResultSet" mode="OUT" typeHandler="com.palic.elis.pos.dayprocset.integration.dao.impl.CursorHandlerCallBack" /> 
</parameterMap>

2.調用過程
  <procedure id ="procrefcursor" parameterMap ="PosTypeMAP">
      {call procpkg.procrefcursor(?,?)}
  </procedure>

3.定義自己的處理器
  public class CursorHandlerCallBack implements TypeHandler{
	public Object getResult(CallableStatement cs, int index) throws SQLException {
		ResultSet rs = (ResultSet)cs.getObject(index);
        List result = new ArrayList();
		while(rs.next()) {
			String postype =rs.getString(1);
			String description = rs.getString(2);
			CodeTableItemDTO posTypeItem = new CodeTableItemDTO();
			posTypeItem.setCode(postype);
			posTypeItem.setDescription(description);
			result.add(posTypeItem);
		}
		return result;
	}



4. dao方法
	public List procPostype() {
		String p = "";
		Map para = new HashMap();
		para.put("p",p);
		para.put("p_ref_postypeList",null);
		 this.getSqlMapClientTemplate().queryForList("pos_dayprocset.procrefcursor",  para);
		 return (List)para.get("p_ref_postypeList");
	}
  


這個跟jdbc的方式非常的相似.
我們使用的是ibatis的2.0版本,比較麻煩。
如果是使用2.2以上版本就非常簡單的。
因為可以在parameterMap中定義一個resultMap.這樣就無需要自己定義處理器了。
可以從分析2.0和2.0的dtd文件知道。

存儲過程常用技巧3


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲欧美中文字幕专区 | 国产成人精品高清不卡在线 | 99久久免费看精品国产一区 | 国产午夜精品一区二区三区嫩草 | 国产精品久久久久久久9999 | 9re视频这里只有精品 | 夜夜狠狠 | 丰满寡妇一级毛片 | 亚洲国产99 | 国产性tv国产精品 | 四虎影音在线观看 | 日本三级强在线观看 | 国产成人精品高清在线观看99 | 九九免费在线视频 | 一本到视频在线观看 | 五月婷婷激情四射 | 欧美成人h版影片在线观看 欧美成人h精品网站 | 国产美女流白浆的免费视 | 婷婷综合国产激情在线 | a毛片免费看 | 久久久99精品久久久久久 | 午夜一级毛片不卡 | 久久综合久久综合久久 | 草草免费观看视频在线 | 日韩在线欧美 | 久久99精品久久久66 | 欧美日韩亚洲一区 | 婷婷天天 | 欧美日韩亚洲综合在线一区二区 | 免费视频不卡一区二区三区 | 欧美性视频在线 | 四虎永久成人免费 | 夜鲁夜鲁夜鲁在线观看福利 | 国产精品国色综合久久 | 夜夜嗨影院 | 四虎午夜影院 | 国产午夜视频在线观看第四页 | 中文字幕精品视频在线观看 | 九九福利视频 | 精品国产三级 | 欧美大成色www永久网站 |