在论坛上看到有人讨论并发的这个问题,因为平时主要是处理数据仓库,所以对并发的问题一直没有怎么注意,记录一下:
--第一段:
create or replace procedure Delete_Pno(v_Pno varchar2) is
v_state varchar2(20);
begin
begin
select state into v_state from P_Table where Pno = v_Pno;
exception
when no_data_found then
dbms_output.put_line('Pno:' || v_Pno || 'not exists.');
return;
end;
if v_state = 'N' then
delete from P_Table where Pno = v_Pno;
dbms_output.put_line('Pno:' || v_Pno || 'delete success.');
else
dbms_output.put_line('Pno:' || v_Pno || 'has been checked.');
end if;
commit;
exception
when others then
rollback;
end;
--
如果在 select state into v_state 之后,如果发生了状态变化,或者单证删除,都会发生并发性错误。
--需要在select into 语句后面加上forupdate,这样就可以锁住该信息而防止其被修改或删除。
--第二段:
create or replace procedure Delete_Pno(v_Pno varchar2) is
v_state varchar2(20);
begin
delete from P_Table
where Pno = v_Pno
and state = 'N';
if sql%rowcount > 0 then
dbms_output.put_line('Pno:' || v_Pno || 'delete success.');
else
begin
select state into v_state from P_Table where Pno = v_Pno;
exception
when no_data_found then
dbms_output.put_line('Pno:' || v_Pno || 'not exists.');
return;
end;
dbms_output.put_line('Pno:' || v_Pno || 'has been checked.');
end if;
commit;
exception
when others then
rollback;
end;
--先删除必然需要删除的,然后再判断是不存在还是无需删除,这样不会出现并发错误。
--第三段
create or replace procedure Delete_Pno(v_Pno varchar2) is
v_state varchar2(20);
begin
delete from P_Table where Pno = v_Pno returning state into v_state;
if sql%rowcount > 0 then
if v_state = 'N' then
dbms_output.put_line('Pno:' || v_Pno || 'delete success.');
else
rollback;
dbms_output.put_line('Pno:' || v_Pno || 'has been checked.');
return;
end if;
else
dbms_output.put_line('Pno:' || v_Pno || 'not exists.');
end if;
commit;
exception
when others then
rollback;
end;
--用returning返回状态,如果状态是'N'则删除,否则回滚,这样也不会有并发的问题。
要注意delete from P_Table where Pno = v_Pno returning state into v_state;语句属于OUT BIND
就好比是update ... set () = (select ...) 一样,语句和自己的子句之间,是不会造成并发的不一致性的。
-The End-