有時爲了避免資源的佔用或重複處理,會要求某個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