欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

PostgreSQL出現(xiàn)死鎖該如何解決

 更新時間:2022年05月30日 10:34:56   作者:慕楓Java  
昨天在對一張表執(zhí)行一條update語句的時候,沒有修改成功,直接終止執(zhí)行,就瘋狂點擊執(zhí)行,執(zhí)行了很多次這條語句導致了表被死鎖了,這篇文章主要給大家介紹了關(guān)于PostgreSQL出現(xiàn)死鎖該如何解決的相關(guān)資料,需要的朋友可以參考下

什么是數(shù)據(jù)庫死鎖

在操作系統(tǒng)領(lǐng)域當中,死鎖指的是兩個或者兩個以上的進程在運行的過程中,因為爭奪共同的訪問資源而相互等待阻塞,最終導致進程繼無法續(xù)執(zhí)行的一種阻塞現(xiàn)象。那么在數(shù)據(jù)庫領(lǐng)域當中死鎖又是怎樣的表現(xiàn)形式呢?數(shù)據(jù)庫死鎖又會帶來怎樣的問題呢?

在理解數(shù)據(jù)庫死鎖之前,我們先來明確下數(shù)據(jù)庫的鎖到底是什么?有過Java編程經(jīng)驗的同學都知道,Java中的鎖是為了解決共享數(shù)據(jù)的并發(fā)訪問安全問題,防止并發(fā)訪問導致的共享數(shù)據(jù)出現(xiàn)錯亂。那么在數(shù)據(jù)庫領(lǐng)域,數(shù)據(jù)庫中的鎖又是來干什么的呢?實際上在數(shù)據(jù)庫中所也是解決并發(fā)問題。假如在同一時刻,可能存在多個事務(wù)對同一張表的同一個字段進行數(shù)字的加減操作,如果沒有任何的控制措施也同樣會導致各種各樣的數(shù)據(jù)一致性問題。因此數(shù)據(jù)庫的鎖實際上也是為了保證數(shù)據(jù)一致性的一種手段,對可能存在的并發(fā)操作進行控制。

下面以一個例子來進行說明,假設(shè)有這樣兩個事務(wù),事務(wù)A中包含如下語句:

UPDATE?user?SET?name = '小慕'?where id?=?1
UPDATE?product?SET?price?=?price?*?10?WHERE?id?=?2

事務(wù)B中包含如下語句:

UPDATE?product?SET?price?=?price?*?100?WHERE?id?=?2
UPDATE?user SET?name?=?'小楓'?WHERE?id?=?1

如果這兩個事務(wù)并發(fā)執(zhí)行,那么他們可能存在如下的執(zhí)行情況,當事務(wù)A執(zhí)行的時候,首先運行了查詢語句:

UPDATE?user?SET?name = '小慕'?where id?=?1

相當于事務(wù)A給id為1的數(shù)據(jù)行加上了排他鎖,但是事務(wù)并沒有執(zhí)行完也就是說此時事務(wù)A持有user表的id為1的排他鎖,排他鎖的特性就是此時其他事務(wù)不能對數(shù)據(jù)進行刪除和修改,因此只有等待事務(wù)結(jié)束釋放鎖之后才能重新獲取。

此時事務(wù)B執(zhí)行更新語句獲取了product表id為2的排他鎖,接著事務(wù)B開始執(zhí)行user表的update語句,需要獲取user表的id為1的排他鎖。但是此時事務(wù)A并未提交,因此事務(wù)A持有表user的id為1的排他鎖,事務(wù)B只有乖乖阻塞等待事務(wù)A釋放鎖。而此時事務(wù)A執(zhí)行update語句,需要獲取product的id為2的排他鎖,但是此時事務(wù)B持有該排他鎖,因此也需要等待事務(wù)B鎖釋放。

UPDATE?product?SET?price?=?price?*?10?WHERE?id?=?2

事務(wù)A在等待事務(wù)B結(jié)束釋放鎖,而事務(wù)B又在等待事務(wù)A釋放鎖,最終陷入了互相等待的情況也就是所謂的死鎖。

那么數(shù)據(jù)庫出現(xiàn)死鎖又會導致什么問題呢?數(shù)據(jù)庫死鎖會導致嚴重的性能問題,可能平臺因為數(shù)據(jù)庫死鎖而導致運行緩慢,嚴重影響用戶正常使用業(yè)務(wù),因此如果出現(xiàn)數(shù)據(jù)庫死鎖情況需要及時發(fā)現(xiàn)以及解決。

定位死鎖

//先確定數(shù)據(jù)庫有沒有死鎖情況發(fā)生
select?*?from?pg_stat_activity?where?datname?=?'product_db';

//查詢可能鎖了的表的oid
select?oid?from?pg_class?where?relname='product';

//查詢對應(yīng)的pid
select?pid?from?pg_locks?where?relation='oid'??//上面查詢出來的oid

//取消或者終止對應(yīng)的進程破壞死鎖條件
select?pg_cancel_backend(pid);
select?pg_terminate_backend(pid);

死鎖可能原因及解決辦法

以上分析了PostgreSQL出現(xiàn)死鎖后如何定位分析,那么接下來就需要總結(jié)分析分析下PostgreSQL出現(xiàn)死鎖情況的原因以及一般的應(yīng)對解決辦法。

1、索引使用不當導致的死鎖問題

索引使用存在問題的話會導致死鎖問題,假設(shè)在一個數(shù)據(jù)查詢的事務(wù)當中,進行數(shù)據(jù)檢索的時候沒辦法按照SQL中的where條件進行查詢,因此導致了全表掃描,那么此時數(shù)據(jù)庫表的行級鎖會上升為表級鎖。如果此時有多個未能按照where條件進行數(shù)據(jù)查詢的事務(wù)存在,那么就容易導致數(shù)據(jù)庫死鎖問題。也就是說在數(shù)據(jù)庫表數(shù)據(jù)量比較大的時候,對應(yīng)進行數(shù)據(jù)查詢的表沒有建立索引或者說索引創(chuàng)建的不合理導致無法通過索引進行數(shù)據(jù)查詢,只能通過全表索引,這樣的場景下就容易產(chǎn)生死鎖。

如何避免:

在進行數(shù)據(jù)查詢的時候,對應(yīng)的SQL語句不宜太過復雜,也就是說盡量避免多張表的關(guān)聯(lián)查詢。

2、不同事務(wù)之間的訪問順序問題

當用戶A 訪問數(shù)據(jù)庫表A時,此時對表A加了共享鎖,然后又訪問數(shù)據(jù)庫表B。而此時另一個用戶B 訪問表B,對表B加了共享鎖,然后試圖訪問表A。但是用戶A由于用戶B已經(jīng)鎖住表B,它必須等待用戶B釋放表B才能繼續(xù),同樣用戶B要等用戶A釋放表A才能繼續(xù),也就是說互相等待對方釋放資源,從而導致了死鎖的發(fā)生。

如何避免:

這種情況在實際項目中遇到的可能比較多,主要還是需要通過控制代碼的執(zhí)行邏輯,避免多表操作時同時鎖住多個資源。

避免死鎖的建議

(1)如果平臺中存在大事務(wù),盡量將其拆分為小事務(wù)。因為大事務(wù)一般操作的數(shù)據(jù)庫表或者數(shù)據(jù)都比較多,因此造成死鎖或者阻塞的概率就會相對較大。

(2)為數(shù)據(jù)庫表設(shè)計合理的索引,盡量避免數(shù)據(jù)查詢時索引未覆蓋或者索引失效的情況,因為全表掃描會會導致給表中的數(shù)據(jù)行上鎖,大大增加了數(shù)據(jù)庫產(chǎn)生死鎖的概率。

(3)如果業(yè)務(wù)允許,我們可以嘗試將隔離級別調(diào)低,比如將隔離級別從RR調(diào)整為RC,可以避免掉很多因為gap鎖造成的死鎖。

(4)在我們自己的代碼中,盡量以一致的順序獲取對象上的鎖,避免事務(wù)中SQL交互執(zhí)行,從而降低死鎖發(fā)生的概率。

附:數(shù)據(jù)庫中常見的死鎖原因與解決方案

1. 事務(wù)之間對資源訪問順序的交替

出現(xiàn)原因: 

一個用戶A 訪問表A(鎖住了表A),然后又訪問表B;另一個用戶B 訪問表B(鎖住了表B),然后企圖訪問表A;這時用戶A由于用戶B已經(jīng)鎖住表B,它必須等待用戶B釋放表B才能繼續(xù),同樣用戶B要等用戶A釋放表A才能繼續(xù),這就死鎖就產(chǎn)生了。

解決方法: 

這種死鎖比較常見,是由于程序的BUG產(chǎn)生的,除了調(diào)整的程序的邏輯沒有其它的辦法。仔細分析程序的邏輯,對于數(shù)據(jù)庫的多表操作時,盡量按照相同的順序進行處理,盡量避免同時鎖定兩個資源,如操作A和B兩張表時,總是按先A后B的順序處理, 必須同時鎖定兩個資源時,要保證在任何時刻都應(yīng)該按照相同的順序來鎖定資源

2. 并發(fā)修改同一記錄

出現(xiàn)原因:主要是由于沒有一次性申請夠權(quán)限的鎖導致的。

用戶A查詢一條紀錄,然后修改該條紀錄;這時用戶B修改該條紀錄,這時用戶A的事務(wù)里鎖的性質(zhì)由查詢的共享鎖企圖上升到獨占鎖,而用戶B里的獨占鎖由于A有共享鎖存在所以必須等A釋放掉共享鎖,而A由于B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,于是出現(xiàn)了死鎖。這種死鎖比較隱蔽,但在稍大點的項目中經(jīng)常發(fā)生。 

解決方法:

a. 樂觀鎖,實現(xiàn)寫-寫并發(fā)

b. 悲觀鎖:使用悲觀鎖進行控制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機制實現(xiàn),如Oracle的Select … for update語句,以保證操作最大程度的獨占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。

3. 索引不當導致的死鎖

出現(xiàn)原因: 

如果在事務(wù)中執(zhí)行了一條不滿足條件的語句,執(zhí)行全表掃描,把行級鎖上升為表級鎖,多個這樣的事務(wù)執(zhí)行后,就很容易產(chǎn)生死鎖和阻塞。類似的情況還有當表中的數(shù)據(jù)量非常龐大而索引建的過少或不合適的時候,使得經(jīng)常發(fā)生全表掃描,最終應(yīng)用系統(tǒng)會越來越慢,最終發(fā)生阻塞或死鎖。

另外一種情況是由于二級索引的存在,上鎖的順序不同導致的

解決方法:

SQL語句中不要使用太復雜的關(guān)聯(lián)多表的查詢;使用“執(zhí)行計劃”對SQL語句進行分析,對于有全表掃描的SQL語句,建立相應(yīng)的索引進行優(yōu)化。

總結(jié)

到此這篇關(guān)于PostgreSQL出現(xiàn)死鎖該如何解決的文章就介紹到這了,更多相關(guān)pg數(shù)據(jù)庫死鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論