Oracle隊列實現
-- 核心技術點:for update
創建測試表
create table t
( id number primary key,
processed_flag varchar2(1),
payload varchar2(20)
);
創建函數索引
create index
t_idx on
t( decode( processed_flag, 'N', 'N' ) );
插入幾條測試數據
insert into t
select r,
case when mod(r,2) = 0 then 'N' else 'Y' end,
'payload ' || r
from (select level r
from dual
connect by level <= 5)
/
方式一,通過函數返回未鎖定行
創建隊列獲取一行數據的函數
支持Oracle8.0及以后的版本
create or replace
function get_first_unlocked_row
return t%rowtype
as
resource_busy exception;
pragma exception_init( resource_busy, -54 );
l_rec t%rowtype;
begin
for x in ( select rowid rid
from t
where decode(processed_flag,'N','N') = 'N')
loop
begin
select * into l_rec
from t
where rowid = x.rid and processed_flag='N'
for update nowait;
return l_rec;
exception
when resource_busy then null;
when no_data_found then null;
end;
end loop;
return null;
end;
/
獲取未加鎖的第一行數據
declare
l_rec t%rowtype;
begin
l_rec := get_first_unlocked_row;
dbms_output.put_line( 'I got row ' || l_rec.id || ', ' || l_rec.payload );
end;
/
eoda/muphy> I got row 2, payload 2
獲取未加鎖的第二行數據
declare
pragma autonomous_transaction;
l_rec t%rowtype;
begin
l_rec := get_first_unlocked_row;
dbms_output.put_line( 'I got row ' || l_rec.id || ', ' || l_rec.payload );
commit;
end;
/
eoda/muphy> I got row 4, payload 4
方式二,直接通過skip locked實現
獲取未加鎖的第一行數據
declare
l_rec t%rowtype;
cursor c
is
select *
from t
where decode(processed_flag,'N','N') = 'N'
FOR UPDATE
SKIP LOCKED;
begin
open c;
fetch c into l_rec;
if ( c%found )
then
dbms_output.put_line( 'I got row ' || l_rec.id || ', ' || l_rec.payload );
end if;
close c;
end;
/
eoda/muphy> I got row 2, payload 2
獲取未加鎖的第二行數據
declare
pragma autonomous_transaction;
l_rec t%rowtype;
cursor c
is
select *
from t
where decode(processed_flag,'N','N') = 'N'
FOR UPDATE
SKIP LOCKED;
begin
open c;
fetch c into l_rec;
if ( c%found )
then
dbms_output.put_line( 'I got row ' || l_rec.id || ', ' || l_rec.payload );
end if;
close c;
commit;
end;
/
eoda/muphy> I got row 4, payload 4
--參考自Oracle編程藝術 深入理解數據庫體系結構第三版
