有时为了避免资源的占用或重复处理,会要求某个proc只能串行的执行,即:同一时间只能有一个session执行这个proc。
这种需求可以通过dbms_lock来实现。
样例包如下:
CREATE OR REPLACE PACKAGE pkg_lock IS
v_lockname VARCHAR2(12) := 'control_lock';
v_lockhandle VARCHAR2(200);
-- obtain a lock
FUNCTION request_lock(p_lockname VARCHAR2, p_ltype INTEGER) RETURN VARCHAR2;
-- release an existing lock
PROCEDURE release_lock;
-- view the stored lockname
FUNCTION get_lockname RETURN VARCHAR2;
-- view the stored handle
FUNCTION get_lockhandle RETURN VARCHAR2;
END pkg_lock;
/
CREATE OR REPLACE PACKAGE BODY pkg_lock IS
FUNCTION request_lock(p_lockname VARCHAR2, p_ltype IN INTEGER)
RETURN VARCHAR2 IS
v_retval INTEGER;
v_err VARCHAR2(200);
BEGIN
IF v_lockhandle IS NULL THEN
dbms_lock.allocate_unique(p_lockname, v_lockhandle);
v_lockname := p_lockname;
v_retval := dbms_lock.request(v_lockhandle, p_ltype, 1, TRUE);
ELSE
RETURN 0;
END IF;
IF v_retval = 0 THEN
RETURN '1';
ELSE
v_lockhandle := NULL;
RETURN(CASE v_retval WHEN 0 THEN '0 成功' WHEN 1 THEN '1 超时' WHEN 2 THEN
'2 死锁' WHEN 3 THEN '3 参数错误' WHEN 4 THEN '4 已经分配了锁,重复申请' WHEN 5 THEN
'5 无效的 lock handle' END);
END IF;
EXCEPTION
WHEN OTHERS THEN
v_err := substr(SQLERRM, 1, 100);
RETURN - 1;
END request_lock;
------------------------------------------------------------
PROCEDURE release_lock IS
v_retval INTEGER;
BEGIN
IF v_lockhandle IS NOT NULL THEN
v_retval := dbms_lock.release(v_lockhandle);
/*
0 成功
3 参数错误
4 没有拥有特定的锁
5 不合法的 lock handle
*/
IF v_retval = 0 THEN
v_lockhandle := NULL;
END IF;
dbms_output.put_line('release_lock:' || v_retval);
END IF;
END release_lock;
FUNCTION get_lockname RETURN VARCHAR2 IS
BEGIN
RETURN v_lockname;
END;
FUNCTION get_lockhandle RETURN VARCHAR2 IS
BEGIN
RETURN v_lockhandle;
END;
END pkg_lock;
/
这时我们在不同的会话执行如下语句
SET serveroutput ON
DECLARE msg VARCHAR2(200);
BEGIN
msg:= pkg_lock.request_lock('test', dbms_lock.x_mode);
IF msg = '1' THEN
dbms_output.put_line(pkg_lock.get_lockname);
dbms_output.put_line(pkg_lock.get_lockhandle);
dbms_lock.sleep(5);
pkg_lock.release_lock;
ELSE
dbms_output.put_line('get lock failure');
dbms_output.put_line(msg);
END IF;
END;
/
会话1:
test
1073741934107374193418
release_lock:0
PL/SQL procedure successfully completed
会话2:
get lock failure
1 超时
PL/SQL procedure successfully completed