串行執行proc

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章