oracle為什么盡量不要使用外鍵的最好理解


對於死鎖問題相信大家都是很頭疼的,為什么不要使用外鍵呢?最簡單的回答就是太容易產生死鎖了。

經過個人的測試,我發現外鍵刪除的時候,是按照表會話的順序執行的,也就是說如果只有一個事務,只要子表刪掉外鍵表的項,外鍵表就可以刪除,但是如果同時有多個事務,這就難說了,具體舉例子如下:

首先我們創建表並創建數據,順序執行如下代碼:

create table t_p (id number primary key, name varchar2(30)); 

create table t_f (fid number, f_name varchar2(30), foreign key (fid) references t_p); 

insert into t_p values (1, 'a'); 

insert into t_f values (1, 'a'); 

insert into t_p values (2, 'b'); 

insert into t_f values (2, 'c'); 

commit; 

 然后測試如下:我在本用戶下(C##BENDIHELI)和System下開啟兩個sql工作表:

其中在C##BENDIHELI記為sql1,system下記為sql2

如果程序的執行順序為:

1.sql1:delete t_f where fid = 2; 

2.sql2:delete c##bendiheli.t_f where fid = 1; 

3.sql1:delete t_p where id = 2; 

此時sql1等待,因為sql2未提交(這就是我理解的外鍵表需要找會話,本會話可以繼續,如果有其他會話未提交,他就等待)

4.sql2:delete c##bendiheli.t_p where id = 1; 

此時sql2等待,因為sql1未提交

 

現在的程序sql1的事務等待sql2的提交,sql2的事務等待sql1的提交,完了,鎖住了。

至於本人理解外鍵是按照會話尋找的原因是,即使我把2換成insert into c##bendiheli.t_f values(1,'duidu'),3仍然會等待,因為2沒提交

若我執行順序為如下,則可以,這樣就更能理解我的想法,就是外鍵按照非本會話的會話順序執行

1.sql1:delete t_f where fid = 2; 

2.sql2:insert into c##bendiheli.t_f values(1,'duidu')

3.sql1:delete t_p where id = 2; 

此時sql1等

4.sql2:commit;

提交后sql1就不再等待

 

解決方案:外鍵加索引

create index ind_t_f_fid on t_f(fid);

 

個人理解,這樣就解決了外鍵按照會話找連接表的,而是通過索引來找,這樣以來上方出現死鎖的程序就不再出現死鎖,因為這樣在本事務內,直接找索引即可。 

 

本文的理解借鑒於博主:https://blog.csdn.net/fenyu8/article/details/53811686


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM