PLSQL中显示游标使用的4个步骤

上一篇 / 下一篇  2012-09-21 09:18:13 / 个人分类:数据库

t U` I)F VKI)C M0  本例简单介绍一下游标处理的4个过程中涉及到的加锁,一致性读的问题.51Testing软件测试网2Z&I V_ H e(zw

51Testing软件测试网/d$WpZ"`

  显式游标处理需四个 PL/SQL步骤:

'X ](lA9ACqQ0

:G8Irv9\H'D\5e ~0  1、定义/声明游标:就是定义一个游标名,以及与其相对应的SELECT 语句。

F X#U$h'Z H,O7pzSp0

(FX2xKW e9Um8P0  格式:

-g tC*CS+e0
    CURSOR cursor_name[(parameter[, parameter]…)]51Testing软件测试网||bE]c dT&n
           [RETURN datatype]
d-x3L,sAq`0    IS
+IN2A,Q"v4g W(Iz0        select_statement;
51Testing软件测试网] o]dTtP

  游标参数只能为输入参数,其格式为:51Testing软件测试网$V t/G"va

51Testing软件测试网"pO7h*a(c

  parameter_name [IN] datatype [{:= | DEFAULT} expression]51Testing软件测试网XIge.@/}l4g$FS

M/Qe[X0  在指定数据类型时,不能使用长度约束。如NUMBER(4),CHAR(10) 等都是错误的。

2^A${,K}9c C9K051Testing软件测试网 @XzN5NS$y+m

  [RETURN  datatype]是可选的,表示游标返回数据的数据。如果选择,则应该严格与select_statement中的选择列表在次序和数据类型上匹配。一般是记录数据类型或带“%ROWTYPE”的数据。51Testing软件测试网'@-~(U,J"x!E)Rt

T&S$vpy"R0  2、打开游标:就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有FOR UPDATE选项,OPEN 语句还将锁定数据库表中游标结果集合对应的数据行。

%O!L!mJ[;j$|'n2gt0

8z(n G.dj0  格式:

r'o'U7GfrV051Testing软件测试网I w oq\ }"ln

  OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];51Testing软件测试网.D~6w{5[1R:ugIA

51Testing软件测试网n1AnS|

  在向游标传递参数时,可以使用与函数参数相同的传值方法,即位置表示法和名称表示法。PL/SQL 程序不能用OPEN 语句重复打开一个游标。

3id[@r ca0

]H&?zQ8a|D0  3、提取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中。

zL j bLe0

,w4I8~;V[C_6Hf{0  格式:

a5S1nu2zM051Testing软件测试网 }*?a'q5YP

  FETCH cursor_name INTO {variable_list | record_variable };

/ftA,nx m0

g O1jkuG^&z0   执行FETCH语句时,每次返回一个数据行,然后自动将游标移动指向下一个数据行。当检索到最后一行数据时,如果再次执行FETCH语句,将操作失败, 并将游标属性%NOTFOUND置为TRUE。所以每次执行完FETCH语句后,检查游标属性%NOTFOUND就可以判断FETCH语句是否执行成功并 返回一个数据行,以便确定是否给对应的变量赋了值。

5K-d;`0ZM)IpF#n0

Y7asG@0v7JX0  4关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。关闭后的游标可以使用OPEN 语句重新打开。

Mo1WU!Y ?0

.us.dvT0  格式:51Testing软件测试网kd-`z+^

!M5?["gl-N2Ljd0  CLOSE cursor_name;51Testing软件测试网!Q'i^YZM

51Testing软件测试网5W.@f}k`e5m&X

  下面用一个例子来说明:51Testing软件测试网n:g2j.|M{P:T8\H

51Testing软件测试网r$~3Y9o+eRsQ(m

CREATE OR REPLACE PROCEDURE testcur IS
"C|c_}0NPn[0  CURSOR c_cursor(r_no NUMBER DEFAULT 5)IS51Testing软件测试网b3C9~n-G9oJ2R!T
    SELECT ISBN, TITLE
3p&|3J7E3l v[ _0      FROM BOOKS51Testing软件测试网~s lcF*Wsq%M{
&nbsp;&nbsp;&nbsp;&nbsp; WHERE rownum < r_no51Testing软件测试网.j%T#F+r|$E c
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FOR UPDATE;
f)XZ:jk.b0&nbsp; v_isbn BOOKS.ISBN%TYPE;
4} HGv)v1y[/[0&nbsp; v_title&nbsp;&nbsp; BOOKS.TITLE%TYPE;

a D8D#ro(^ P051Testing软件测试网 ~:uU[|

BEGIN
AEz\ Aa?6e0&nbsp; --OPEN c_cursor(5);
8R9sU!qZB}+y%a0&nbsp; OPEN c_cursor(r_no=>7);
N0F v[{'Rmq-gQc0&nbsp; DBMS_OUTPUT.PUT_LINE('opened cursor'); --afater open
h`8S H!ZI4_0&nbsp; --DBMS_LOCK.SLEEP(30);
51Testing软件测试网~Jsli1_4l` H

51Testing软件测试网`b%dF f#d)[,`

&nbsp; FETCH c_cursor
Ew4eLf0&nbsp;&nbsp;&nbsp; INTO v_isbn, v_title;
6c:]|\ @.w2?o,|0&nbsp; DBMS_OUTPUT.PUT_LINE('fetched cursor');
Z&h9X o^sz0&nbsp; --DBMS_LOCK.SLEEP(30);
V4\RoT6uXs;o"OG0&nbsp; WHILE c_cursor%FOUND LOOP
(^5{M)wRu0&nbsp;&nbsp;&nbsp; DBMS_OUTPUT.PUT_LINE(v_isbn || '---' || to_char(v_title));51Testing软件测试网Q'SXw yq0b
&nbsp;&nbsp;&nbsp; FETCH c_cursor
#]6e Np1H[(d0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INTO v_isbn, v_title;
G)c6b` C:me0&nbsp; END LOOP;
+PN5q-zAq*u0&nbsp; CLOSE c_cursor;
Gwc`._/o] `#P0&nbsp; DBMS_OUTPUT.PUT_LINE('closed cursor');
&^s W:Q!VHG g(N0&nbsp; ROLLBACK;
U:d#^me+i b x0&nbsp; DBMS_OUTPUT.PUT_LINE('ended transaction');51Testing软件测试网 b v5oZ!yIWZ7TR
END testcur;
51Testing软件测试网nK3o0PB/v

51Testing软件测试网Bw]q2`{ w.{G

  定义/声明游标的时候只是把SQL与游标关联,在open的时候才和表发生查询关系,如果有for update会有

e4`~ ?M:C'u7j051Testing软件测试网1~II5P|.{

  加锁发生,如在本例中,OPEN c_cursor后,通过debug的方式停止在'--afater open',通过

#iy}fz'@ C'sM0

Kf3vR)K0  select * from v$lock where sid in (select distinct sid from v$session where username='PLSQL')可以看到有加锁的记录,本例是以PLSQL用户登录的.在fetch的过程中,Oracle会保证一致性读,可以通过 将For update去掉,在fetch的过程中在另外一个session中更新并提交数据来观察.大家可以参考我的另外一篇blog http://blog.csdn.net/kkdelta/article/details/7183981模拟了这个过程.close cursor并不会释放for update获得的锁,事务结束才释放。51Testing软件测试网t;T0`5e#x!\

51Testing软件测试网!zfUD ~+H.o+P

  另外,最先我是想用DBMS_OUTPUT.PUT_LINE和DBMS_LOCK.SLEEP配合来观察加锁和释放锁的现象,结果是 DBMS_OUTPUT.PUT_LINE要在整个存储过程执行完之后才会输出,后来只好在PL/SQL Developer中通过debug的方式观察,大家要注意了。51Testing软件测试网lp9n&~I&LO

51Testing软件测试网-bE vHOXb

  在sqlplus中使用游标可以用以下方式:

@5R6D:q3Le0bnZ051Testing软件测试网+Qx@X+w0n_f

  variable c refcursor;

f\tA]xhPE0N051Testing软件测试网@'dj;}C g.My#U

  exec open :c for SELECT ISBN, TITLE FROM BOOKS WHERE rownum < 5 FOR UPDATE;

*D5M(U V$B:Y0

fJV)?i0Ut#]n8ZS:RO0  print c;

'R[B ?u8O9ER051Testing软件测试网7K PPK)I;g}SiD

  rollback;

h(Y[J&S q0J0

O*Q1g`ED4h0N0  同样exec open 的时候会加锁,最后需要显示结束事务才能释放锁。

,ke%mfiN051Testing软件测试网PqG _)Y!~

  PLSQL中还有一个称为游标变量的概念,与游标不同的是,游标变量是动态的,而游标是静态的。游标只能与指定的查询相连,即固定指向一个查询 的内存处理区域,而游标变量则可与不同的查询语句相连,它可以指向不同查询语句的内存处理区域(但不能同时指向多个内存处理区域,在某一时刻只能与一个查 询语句相连)。

H YN^ U/H9D051Testing软件测试网sz-S%J4VE p

  声明一个游标变量的需要注意的步骤:51Testing软件测试网U7b^C`f C5fl

51Testing软件测试网Qtq zc

  1、定义一个REF CURSOU数据类型,如:

'J p)\,c-~ys051Testing软件测试网)p%PJ@&L7\

  TYPE ref_cursor_type IS REF CURSOR;

S%h1] h9qU0

8r)r ~ @.^{V0  2、声明一个该数据类型的游标变量,如:51Testing软件测试网:f,B"sf8aP

.q/l\Dn:H6`,n0  cv_ref REF_CURSOR_TYPE;51Testing软件测试网qJ]r1u&[

%_ r8X1A#d0  3、在打开的时候和一个SQL语句关联:

J/z uje+L q0

CP(ND?6O_p0  OPEN cursor_variable_name

7};i.u9K!Yp\ o L0

]'? ~6\A |4a&a[0  FOR select_statement;

kH\`of K$u:D0

d?.W_nD [.y]0  后面这和游标的使用相同了,如下例:

,hTx-FX-Q051Testing软件测试网 ^w3Z9D8|w~ p

8[#F&KmiW R|0DECLARE51Testing软件测试网zpf3Ry3K
    TYPE refcur_type IS REF CURSOR;
.wm8V ^Zff ^"Z0    book_refcur refcur_type ;51Testing软件测试网gngt-`,Cqm$n$|
    v_isbn varchar2(100);51Testing软件测试网 OoF3b8M;@P
    v_title   varchar2(100); 
-G$qT&Z ?[`:M9f0BEGIN51Testing软件测试网&Ee5N&g(}3r)_u;@
    OPEN book_refcur FOR
6O:D eULEv#J_!O0    SELECT ISBN, TITLE FROM BOOKS WHERE rownum<3;51Testing软件测试网Q-G#TV h|
 51Testing软件测试网 Rx q3h7uEt0_1G9K
    FETCH book_refcur INTO v_isbn,v_title;
/] T4b{9DL9K0    WHILE book_refcur%FOUND LOOP51Testing软件测试网Pzk&x%Y a
       DBMS_OUTPUT.PUT_LINE(v_isbn||': '||v_title);
4V6T,}7pTHE?-OW7m+C0    FETCH book_refcur INTO v_isbn,v_title;
"L)HD[I'i0    END LOOP;51Testing软件测试网HH8kP%}6p1Nzz
    CLOSE book_refcur;51Testing软件测试网X?mFn
   
YYc Y7Y9M/k&cYVD a0    -- open cursoe with another sql statement51Testing软件测试网`S Q"VQ0v,Qo
    DBMS_OUTPUT.PUT_LINE('------- open cursoe with another sql statement');
m \~YRj5hq0    OPEN book_refcur FOR51Testing软件测试网;t;J njU[W^ ?/e+F-o
    SELECT ISBN, category FROM BOOKS WHERE rownum<3;
:Kxm']0bb0 
u:qtpp0wI0    FETCH book_refcur INTO v_isbn,v_title;51Testing软件测试网qgip+L*kj_1}$T
    WHILE book_refcur%FOUND LOOP
W,X N,}6G%S%y }}0       DBMS_OUTPUT.PUT_LINE(v_isbn||': category is: '||v_title);51Testing软件测试网1eD@H(`
    FETCH book_refcur INTO v_isbn,v_title;51Testing软件测试网.]H&VT#}w
    END LOOP;
f|6^/}H Xg8WU q I0    CLOSE book_refcur;   
3g5~8JuU@-w.F0END;

TAG:

 

评分:0

我来说两句

Open Toolbar