pg_advisory_lock 正确使用方法

pg_advisory_lock和pg_advisory_unlock是配对使用的,但是如果之间的部分出现异常时,可能会导致不能正确的调用pg_advisory_unlock.例如:

create or replace function test_insert_advisory(integer)
	returns integer
as $$
	declare	
	begin
		perform pg_advisory_lock($1::bigint);
		insert test(id) values($1);
		perform pg_advisory_unlock($1::bigint);
		return $1;
	end;
$$ language plpgsql strict;

虽然看起来没什么问题,但是如果insert异常时不会释放锁,就需要靠dba手动检查释放了.

改进方法

使用bit标志位来判断,操作锁的同时操作标志位,位操作函数定义如下:


/****************************************************************************************
	将第x个bit位设置为1,ibit的值范围0-31
00000000000000000000000000000000
****************************************************************************************/
create or replace function SE_flag_add(iflag integer, ibit integer) 
    returns integer 
as $$
	select iflag + (1<<ibit);
$$ language sql strict; 
/****************************************************************************************
	将第x个bit位设置为0,ibit的值范围0-31
00000000000000000000000000000000
****************************************************************************************/
create or replace function SE_flag_remove(iflag integer, ibit integer) 
    returns integer 
as $$
	select iflag - (1<<ibit);
$$ language sql strict;
/****************************************************************************************
	判断第x个bit位是否为1,ibit的值范围0-31
00000000000000000000000000000000
****************************************************************************************/
create or replace function SE_flag_bitisone(iflag integer, ibit integer) 
    returns boolean 
as $$
	select  (case ((iflag >> ibit) & 1) when 1 then
		true
	else
		false
	end);
$$ language sql strict; 

改进刚才的函数
加锁和释放时同时操作锁和标志位,当异常时根据标志位来确定是否释放锁.

create or replace function test_insert_advisory(integer)
	returns integer
as $$
	declare	
		v_flag integer;
	begin
		v_flag := 0;
		select pg_advisory_lock($1::bigint),SE_flag_add(v_flag,0);
		--多次锁定是只要设置不同的bit位即可
		--select pg_advisory_lock(345),SE_flag_add(v_flag,1);
		--不管insert正确与否都保证释放锁
		insert test(id) values($1);
		--select pg_advisory_unlock(345),SE_flag_remove(v_flag,1);
		select pg_advisory_unlock($1::bigint),SE_flag_remove(v_flag,0);
		return $1;
		exception
			when others then
				/*if(SE_flag_bitisone(v_flag,1) ) then
					perform pg_advisory_unlock(345);
				end if;*/
				if(SE_flag_bitisone(v_flag,0) ) then
					perform pg_advisory_unlock($1::bigint);
				end if;
	end;
$$ language plpgsql strict;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kmblack1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值