關于并發問題的測試
?
??? 在論壇上看到有人討論并發的這個問題,因為平時主要是處理數據倉庫,所以對并發的問題一直沒有怎么注意,記錄一下:
?
?
--第一段:
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 ...) 一樣,語句和自己的子句之間,是不會造成并發的不一致性的。
?
?