對於死鎖問題相信大家都是很頭疼的,為什麼不要使用外來鍵呢?最簡單的回答就是太容易產生死鎖了。
經過個人的測試,我發現外來鍵刪除的時候,是按照表會話的順序執行的,也就是說如果只有乙個事務,只要子表刪掉外來鍵表的項,外來鍵表就可以刪除,但是如果同時有多個事務,這就難說了,具體舉例子如下:
首先我們建立表並建立資料,順序執行如下**:
createtable 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就不再等待
解決方案:外來鍵加索引
createindex ind_t_f_fid on t_f(fid);
個人理解,這樣就解決了外來鍵按照會話找連線表的,而是通過索引來找,這樣以來上方出現死鎖的程式就不再出現死鎖,因為這樣在本事務內,直接找索引即可。
本文的理解借鑑於博主:
為什麼盡量不要使用eval函式和with關鍵字
編譯過程 分詞 詞法分析 解析 語法分析 生成 詞法作用域 定義在詞法階段的作用域 作用域 是一套規則,定義了引擎如何在作用域中通過識別符號名稱對變數進行查詢 作用域工作模型 詞法作用域 動態作用域 詞法化 編譯器工作的第一階段,即對 中的字元進行檢查。如果是有狀態的解析還會賦予單詞語義1.效能問題...
盡量不要使用FindWindow
盡量不用 findwindow 最近發現 se6和 se5程序共存時視窗名稱一樣引起的 bug。原因是我們經常使用 findwindow 來獲得視窗控制代碼,然後進行訊息通訊,這樣呼叫簡單,但增加了不同模組之間的依賴性,比如同時有兩個程序時,就可能會找錯視窗。而如果靠人去維護這個視窗名稱,在程式工程...
盡量不要使用可變引數
在某些情況下我們希望函式引數的個數可以根據實際需要來確定,所以c語言中就提供了一種長度不確定的引數,形如 c 語言也繼承了這一語言特性。在採用ansi標準形式時,引數個數可變的函式的原型是 typefuncname typepara1,typepara2,這種形式至少需要乙個普通的形式引數,後面的省...