事務(進程 ID 64)與另一個進程被死鎖在 鎖 資源上,並且已被選作死鎖犧牲品。


訪問頻率比較高的app接口,在后台寫的異常日志會偶爾出現以下錯誤。

事務(進程 ID 64)與另一個進程被死鎖在 鎖 資源上,並且已被選作死鎖犧牲品。請重新運行該事務

 

實所有的死鎖最深層的原因就是一個:資源競爭 

表現一:

    一個用戶A 訪問表A(鎖住了表A),然后又訪問表B

 

    另一個用戶B 訪問表B(鎖住了表B),然后企圖訪問表A

 

    這時用戶A由於用戶B已經鎖住表B,它必須等待用戶B釋放表B,才能繼續,好了他老人家就只好老老實實在這等了

 

    同樣用戶B要等用戶A釋放表A才能繼續這就死鎖了

 

解決方法:

    這種死鎖是由於你的程序的BUG產生的,除了調整你的程序的邏輯別無他法

    仔細分析你程序的邏輯,

    1:盡量避免同時鎖定兩個資源

    2: 必須同時鎖定兩個資源時,要保證在任何時刻都應該按照相同的順序來鎖定資源.

  
表現二:

    用戶A讀一條紀錄,然后修改該條紀錄

    這是用戶B修改該條紀錄

    這里用戶A的事務里鎖的性質由共享鎖企圖上升到獨占鎖(for update),而用戶B里的獨占鎖由於A有共享鎖存在所以必須等A釋

放掉共享鎖,而A由於B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,於是出現了死鎖。

    這種死鎖比較隱蔽,但其實在稍大點的項目中經常發生。

解決方法:

    讓用戶A的事務(即先讀后寫類型的操作),在select 時就是用Update lock

    語法如下:

    select * from table1 (updlock) where ....

==========================

在聯機事務處理(OLTP)的數據庫應用系統中,多用戶、多任務的並發性是系統最重要的技術指標之一。為了提高並發性,目前大部分RDBMS都采用加鎖技術。然而由於現實環境的復雜性,使用加鎖技術又不可避免地產生了死鎖問題。因此如何合理有效地使用加鎖技術,最小化死鎖是開發聯機事務處理系統的關鍵。   

 

死鎖產生的原因    

在聯機事務處理系統中,造成死機主要有兩方面原因。一方面,由於多用戶、多任務的並發性和事務的完整性要求,當多個事務處理對多個資源同時訪問時,若雙方已鎖定一部分資源但也都需要對方已鎖定的資源時,無法在有限的時間內完全獲得所需的資源,就會處於無限的等待狀態,從而造成其對資源需求的死鎖。

    

另一方面,數據庫本身加鎖機制的實現方法不同,各數據庫系統也會產生其特殊的死鎖情況。如在Sybase  SQL  Server  11中,最小鎖為2K一頁的加鎖方法,而非行級鎖。如果某張表的記錄數少且記錄的長度較短(即記錄密度高,如應用系統中的系統配置表或系統參數表就屬於此類表),被訪問的頻率高,就容易在該頁上產生死鎖。   

 

幾種死鎖情況及解決方法    

  清算應用系統中,容易發生死鎖的幾種情況如下:      

  ●  不同的存儲過程、觸發器、動態SQL語句段按照不同的順序同時訪問多張表;     

 

  ●  在交換期間添加記錄頻繁的表,但在該表上使用了非群集索引(non-clustered);     

 

  ●  表中的記錄少,且單條記錄較短,被訪問的頻率較高;   

 

  ●  整張表被訪問的頻率高(如代碼對照表的查詢等)。    

以上死鎖情況的對應處理方法如下:    

  ●  在系統實現時應規定所有存儲過程、觸發器、動態SQL語句段中,對多張表的操作總是使用同一順序。如:有兩個存儲過程proc1、proc2,都需要訪問三張表zltab、z2tab和z3tab,如果proc1按照zltab、z2tab和z3tab的順序進行訪問,那么,proc2也應該按照以上順序訪問這三張表。   

 

  ●  對在交換期間添加記錄頻繁的表,使用群集索引(clustered),以減少多個用戶添加記錄到該表的最后一頁上,在表尾產生熱點,造成死鎖。這類表多為往來賬的流水表,其特點是在交換期間需要在表尾追加大量的記錄,並且對已添加的記錄不做或較少做刪除操作。    

 

  ●  對單張表中記錄數不太多,且在交換期間select或updata較頻繁的表可使用設置每頁最大行的辦法,減少數據在表中存放的密度,模擬行級鎖,減少在該表上死鎖情況的發生。這類表多為信息繁雜且記錄條數少的表。    

 

  如:系統配置表或系統參數表。在定義該表時添加如下語句:    

  with  max_rows_per_page=1    

  ●  在存儲過程、觸發器、動態SQL語句段中,若對某些整張表select操作較頻繁,則可能在該表上與其他訪問該表的用戶產生死鎖。對於檢查賬號是否存在,但被檢查的字段在檢查期間不會被更新等非關鍵語句,可以采用在select命令中使用at  isolation  read  uncommitted子句的方法解決。

該方法實際上降低了select語句對整張表的鎖級別,提高了其他用戶對該表操作的並發性。在系統高負荷運行時,該方法的效果尤為顯著。    

 

例如:    
   select * from  titles  at  isolation  read  uncommitted    
  ●  對流水號一類的順序數生成器字段,可以先執行updata流水號字段+1,然后再執行select獲取流水號的方法進行操作。


免責聲明!

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



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