写这个题目是由于看到论坛里面的一个帖子:http://www.itpub.net/thread-992141-1-1.html。
虽然不清楚楼主的具体目的是什么,但是楼主提出的问题确实有点意思。因为Oracle中根本没有读锁,楼主的要求和Oracle尽可能提高并发的目的是截然相反的。
写这篇文章的目的并不是说这个需求有什么普遍性,而是为了说明在Oracle中其实没有什么是做不到的,即使这个需求和Oracle的设计本意相违背,另外希望这篇文章中的一些思路能起到抛砖引玉的作用。
楼主提出的问题是“怎么样让一个表,一个时间只能一个人读”,简单概括一下就是建立起读锁的机制。而且这个读锁还不能是共享锁,而必须是有个独占锁。
考虑到Oracle中根本不存在读锁,那么必须将思路进行转化。
最先想到的是,将查询转化为DML,这样就可以获取到锁,避免其他用户对改对象同时进行访问。
最简单的实现方式莫过于建立一个存储过程,在存储过程中首先LOCK TABLE,然后进行查询,将查询的结果返回。
简单实现如下:
SQL> CREATE TABLE TITPUB个人空间9ms,Drv4r2D
2 (
2_HP&jN1qj0 3 ID NUMBER PRIMARY KEY,
#ks~s
K7I'Y0 4 NAME VARCHAR2(30)
:`kr6s9Z$W,aD0 5 );
表已创建。
SQL> INSERT INTO T SELECT ROWNUM, TNAME FROM TAB;
已创建23行。
SQL> COMMIT;
提交完成。
下面构建函数:
SQL> CREATE OR REPLACE FUNCTION F_QUERY_T RETURN SYS_REFCURSOR ASITPUB个人空间j#S:X Y GMM n"\
2 V_CURSOR SYS_REFCURSOR;
P0~qp"Y.M8?%oTN0 3 BEGINITPUB个人空间4Ug-L0J}3g-^
4 LOCK TABLE T IN EXCLUSIVE MODE;ITPUB个人空间i{Ui8t#IF9|~
5 OPEN V_CURSOR FOR 'SELECT * FROM T';
;XP
|(JR
VP2\)Q)QWB0 6 RETURN V_CURSOR;ITPUB个人空间]Q:IOF#A%[;y
7 END;ITPUB个人空间6N5Pm7V&ODKNd
8 /
函数已创建。
SQL> SELECT F_QUERY_T FROM DUAL;
F_QUERY_T
J)f-N l+a`/j.wG1z0--------------------ITPUB个人空间`s;@.C hB;t9Z*Y }-W.T
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ID NAME
5d&Yx Ef Ub-IO!J0---------- ------------------------------
$cg|.`k$BG7{#]0 1 CHAINED_ROWSITPUB个人空间-k}6Rb tLbf
2 DEPTITPUB个人空间(C @rb5kl
3 EMPITPUB个人空间!P](f*U+Av Z,U_`
4 BONUSITPUB个人空间5v P7Yab#a){n g
5 SALGRADE
8C W.|
khD0 6 DUMMY
{JMLp4` rT6k0 7 T_PKITPUB个人空间4l+T~2dv&J3U.E
8 S_T
x g~9_2l)K`,KX0 9 MV_CAPABILITIES_TABLEITPUB个人空间R0l*}'QQ0WcJD2f
10 TB_OBJECT_1136
E*`#C:|y1uF0 11 MLOG$_TB_OBJECT_1136
-N&jTs:go%m%ta2c0 12 RUPD$_TB_OBJECT_1136ITPUB个人空间bn4m
lY
13 MV_TB_OBJECT_1136ITPUB个人空间#XS)b^t%{_rP
14 ORD_ORDER
O;t$~[`{H3R0 15 TT
!XZU/uV#aN/p9`K0 16 MV_T
a$`:D#@:@lPw0 17 T_PRIMARY
:FXcnc]Kj+q0 18 T_UPDATEITPUB个人空间vd!Wz6S([#lgB
19 TITPUB个人空间;T+C3af5_!?8A"^
20 INF_PRODUCTITPUB个人空间*}NnW O
iO
21 INF_DRUG
b;`s R(U8H5U!r+B0 22 T_OLDITPUB个人空间;OFn0fk
23 INF_PRODUCT_PROPERTY
已选择23行。
下面在另外一个会话登陆,仍然通过函数来访问:
SQL> SET SQLP 'SQL2> '
m.CFg:G e_0g7J0SQL2> SELECT F_QUERY_T FROM DUAL;
会话被锁定,只有会话1提交或回滚,会话2才能继续查询:
SQL> COMMIT;
提交完成。
这时会话2解锁:
,t{2a~6i(f7a6Z
]\0F_QUERY_TITPUB个人空间kKD!Bf+_ dHr
--------------------
7Bo;~$Wm)H _~f0CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
ID NAMEITPUB个人空间O~6h ox'D!G
P-W h3l
---------- ------------------------------ITPUB个人空间hG\g%O}a4jh
1 CHAINED_ROWSITPUB个人空间w0Z3^OE5?
2 DEPTITPUB个人空间-aU?*]ax\z'z
3 EMPITPUB个人空间
l
XY4|`a
4 BONUSITPUB个人空间s-v9SS.|
~
5 SALGRADEITPUB个人空间%F;M1naK
6 DUMMYITPUB个人空间CWAc"rr7^/o
7 T_PKITPUB个人空间'R"ZL7I:N&e6W w'X1Rv;K
8 S_TITPUB个人空间,rGP7}e|iw
9 MV_CAPABILITIES_TABLE
(U-iDQO0j#s0 10 TB_OBJECT_1136ITPUB个人空间6rC[\@t.y-Q
11 MLOG$_TB_OBJECT_1136ITPUB个人空间&Li
XU [6O'H}
12 RUPD$_TB_OBJECT_1136ITPUB个人空间5XUJ!i+uo*]Y1zYgD
13 MV_TB_OBJECT_1136ITPUB个人空间S+K-Mx2HO1~
14 ORD_ORDER
;k&jt'XBEv,q0 15 TT
[(S7kq3I{0 16 MV_T
vPe+|+c'U0 17 T_PRIMARY
4l o%i|Ws&y5m*v0 18 T_UPDATEITPUB个人空间 Z*xH vS~%S
19 T
Y2m E4O$\0 20 INF_PRODUCT
+Q
}9}|1xQ a$x0 21 INF_DRUGITPUB个人空间J^(l QM/z
W OXU4o
22 T_OLD
8WRgu!Ob0M
z6c0 23 INF_PRODUCT_PROPERTY
已选择23行。
T1C1R~)S9?5ha~0SQL2> ROLLBACK;
回退已完成。
通过这种方法,简单的实现了读锁的功能,不过这种方法的缺点也很明显,要求用户必须通过函数的方式访问,而直接通过SQL方式访问是可以绕过锁机制的。