DBMS_LOCK
功能描述
DBMS_LOCK包可以对数据库锁进行管理和控制。
比如某些开发程序,在高并发的情况下,必须控制好并发请求的运行时间和次序, 来保证处理数据的正确性和完整性。对于这种业务需求,可以使用内置包DBMS_LOCK,把需要做并发控制的参数加上锁,实现并发控制。 dbms_lock包提供了多种锁模式,各个模式都有自己的冲突列表,各个锁模式的含义及取值如下表:
名字 | 描述 | 值 |
---|---|---|
nl_mode | NULL | 1 |
ss_mode | Sub Shared,表示在一个对象的子部分获取共享锁 | 2 |
sx_mode | Sub Exclusive,表示在一个对象的子部分获取独占锁 | 3 |
s_mode | Shared,表示对整个对象获取共享锁 | 4 |
ssx_mode | Shared Sub Exclusive,表示整个对象已有共享锁,但是还要对某些子部分获取独占锁 | 5 |
x_mode | Exclusive,表示对整个对象获取独占锁 | 6 |
当要获取一个对象的锁时,如果这个对象的锁正被其他会话所持有,那么需要根据该对象的锁正被持有的模式以及当前要获取的锁的模式来判断本次是否能够成功获取,这就是不同锁模式的冲突。不同锁模式的冲突列表如下:
HELD MODE | GET NL | GET SS | GET SX | GET S | GET SSX | GET X |
---|---|---|---|---|---|---|
NL | Success | Success | Success | Success | Success | Success |
SS | Success | Success | Success | Success | Success | Failed |
SX | Success | Success | Success | Success | Failed | Failed |
S | Success | Success | Failed | Success | Failed | Failed |
SSX | Success | Success | Failed | Failed | Failed | Failed |
X | Success | Failed | Failed | Failed | Failed | Failed |
该内置包包含以下子程序:
子程序 | 描述 |
---|---|
ALLOCATE_UNIQUE | 为指定的锁名分配一个唯一的锁id。 |
CONVERT | 锁模式的转换。 |
REQUEST | 请求一个指定模式的锁。 |
RELEASE | 用来显示释放由REQUEST函数占有的锁。 |
SLEEP | 指定session睡眠时间。 |
注意事项
无。
示例
1、 创建函数并发控制锁模式nl_mode与sx_mode。
create or replace function lock_test(lock_mode int ,lock_expired int ,release_on_commit boolean) returns int as $$ --lock_mode取1到6整数
declare
v_ret int;
v_name varchar(100) :='test';
v_handle varchar(100);
begin
dbms_output.enable();
dbms_output.serveroutput(true);
dbms_output.put_line('----- session start -----');
select dbms_lock.allocate_unique(v_name,lock_expired) into v_handle;
v_ret :=dbms_lock.request(v_handle , lock_mode , lock_expired , release_on_commit);
if v_ret <> 0 then
--获取锁失败
dbms_output.put_line('---lock request lock failed ---');
return v_ret;
else
dbms_output.put_line('---now request lock success ---');
end if;
--获取锁成功,此处添加请求业务逻辑
dbms_lock.sleep(lock_expired+20);
--执行完成,应该要释放掉锁
if v_ret = 0 then
v_ret := dbms_lock.release(v_handle);
end if;
return v_ret;
end;
$$ language plpgsql;
2、会话1中执行 CALL lock_test(1,2,false),切换至会话2同时执行CALL lock_test(3,20,false)。
CALL lock_test(1,2,false);
CALL lock_test(3,20,false);
会话1和会话2可以同时获得锁,同时出现如下执行结果:
----- session start -----
---now request lock success ---
lock_test
-----------
0
(1 row)
3、 会话1执行 CALL lock_test(1,2,true),切换至会话2同时执行CALL lock_test(3,20,true);
CALL lock_test(1,2,true);
CALL lock_test(3,20,true);
会话1和会话2可以同时获得锁,同时出现如下执行结果:
----- session start -----
---now request lock success ---
lock_test
-----------
0
(1 row)
ALLOCATE_UNIQUE
语法格式
dbms_lock.allocate_unique(
lockname IN VARCHAR2,
lockhandle OUT VARCHAR2,
expiration_secs IN INTEGER DEFAULT 864000
) RETURN INTEGER;
参数说明
lockname
产生唯一的LockID。大小不超过128B,大小写敏感。不能以'ORA$'开头,这是为oracle提供的产品保留的。
lockhandle
返回值,request,convert,release调用。
expiration_secs
执行'allocate_unique'后,Clean Up的时间间隔。
CONVERT
语法格式
dbms_lock.convert(
lockhandle IN VARCHAR2,
lockmode IN INTEGER,
timeout IN NUMBER DEFAULT maxwait
) RETURN INTEGER;
参数说明
lockname
生成的唯一ID的锁的名称。
lockhandle
返回值,request,convert,release调用。
expiration_secs
执行'allocate_unique'后,Clean Up的时间间隔。
RELEASE
语法格式
dbms_lock.release(
lockhandle IN VARCHAR2
) RETURN INTEGER;
dbms_lock.release(
id IN INTEGER
) RETURN INTEGER;
参数说明
lockhandle,id
用户分配的锁定标识符。
REQUEST
语法格式
dbms_lock.request(
lockhandle IN VARCHAR2,
lockmode IN INTEGER DEFAULT x_mode,
timeout IN INTEGER DEFAULT maxwait,
release_on_commit IN BOOLEAN DEFAULT FALSE
) RETURN INTEGER;
参数说明
lockhandle,id
用户分配的锁定标识符,allocate_unique取得的handle。
lockmode
请求的锁的模式。
timeout
继续尝试授予锁定的秒数,如果在此时间段内无法授予锁,则调用返回值 1 ( timeout)。
release_on_commit
将此参数设置为TRUE以释放提交或回滚时的锁定。否则,锁会一直持有,直到它被显式释放或会话结束。默认为FALSE。
SLEEP
语法格式
dbms_lock.sleep(
seconds IN NUMBER
);
参数说明
seconds
睡眠时间。