DBMS_LOCK包

包DBMS_LOCK为用户提供了与锁相关的接口,从而使得PL程序具有了控制并发的能力。通过DBMS_LOCK提供的接口,可以进行请求特定模式的锁、更改锁定模式或者释放锁等操作。

包DBMS_LOCK提供与Oracle兼容的应用程序接口。

下表展示了DBMS_LOCK包的子程序。

子程序 描述 过程/函数
ALLOCATE_UNIQUE 为锁分配唯一的锁标识 过程
REQUEST 请求特定模式的锁 函数
CONVERT 将锁转换为特定的模式 函数
RELEASE 释放一个锁 函数
SLEEP 使程序休眠一定的时间 过程

以下内容介绍了DBMS_LOCK包中各种函数和过程的语法、参数和说明。

下表展示了DBMS_LOCK支持的锁模式和取值,以及各个锁模式之间的兼容性。

已授予锁 请求NL锁 请求SS锁 请求SX锁 请求S锁 请求SSX锁 请求X锁
NL(1) 成功 成功 成功 成功 成功 成功
SS(2) 成功 成功 成功 成功 成功 失败
SX(3) 成功 成功 成功 失败 失败 失败
S(4) 成功 成功 失败 成功 失败 失败
SSX(5) 成功 成功 失败 失败 失败 失败
X(6) 成功 失败 失败 失败 失败 失败

示例:DBMS_LOCK包

drop table t_lock;
create table t_lock(id int);

-- 加锁
create or replace function u_lock(LockName VARCHAR2(64), LockMode INTEGER, TimeOut INTEGER, bCommitOnRelease BOOLEAN) return number as
    lockhandle VARCHAR2(100);
    status     INTEGER;
begin
    dbms_lock.allocate_unique(LockName, lockhandle, 30);
    status := dbms_lock.request(lockhandle,
                                LockMode, --锁定模式
                                TimeOut, --最多等待时间
                                bCommitOnRelease); -- 事务提交放锁
    return status;
end;
/
-- 放锁
create or replace function u_release(LockName VARCHAR2(64)) return number as
    lockhandle VARCHAR2(100);
    status     INTEGER;
begin
    dbms_lock.allocate_unique(LockName, lockhandle, 30);
    status := dbms_lock.release(lockhandle);
    return status;
end;
/
-- 多个session并发执行下面的脚本,不会出现重复数据
DECLARE
    v_result NUMBER;
    v_rand NUMBER;
    v_count NUMBER;
BEGIN
    FOR i IN 1 .. 10000 LOOP
        -- 获取0-10000之间的随机整数
        select floor(rand()*(10000)) into v_rand;
        v_result:= u_lock('lock_test', DBMS_LOCK.X_MODE, 1, FALSE);
        IF v_result = 0 THEN
            select count(*) into v_count from t_lock where id = v_rand;
            IF v_count = 0 THEN
                insert into t_lock values(v_rand);
                -- dbms_output.put_line(v_rand);
            END IF;
        END IF;
        v_result:= u_release('lock_test');

    END LOOP;
END;
/
-- 查询是否有重复数据
select count(*) from t_lock group by t_lock.id having (count(*)) > 1;
COUNT(int)      |
总数目:0

drop table t_lock;