真實(shí)線上問題之?dāng)?shù)據(jù)庫死鎖如何解決?
數(shù)據(jù)庫死鎖是指在多個(gè)并發(fā)事務(wù)中,彼此之間發(fā)生相互等待的情況,導(dǎo)致所有事務(wù)都無法繼續(xù)執(zhí)行的情形。
數(shù)據(jù)庫死鎖通常由以下原因?qū)е拢?/p>
- 資源競爭:多個(gè)事務(wù)試圖同時(shí)訪問相同的資源,如數(shù)據(jù)庫表、行、頁或鎖,但它們請求資源的順序不同,導(dǎo)致相互等待。
- 未釋放資源:事務(wù)在使用完資源后未及時(shí)釋放,導(dǎo)致其他事務(wù)無法獲得所需的資源。這可能是由于程序錯(cuò)誤或異常情況引起的。
- 不同事務(wù)執(zhí)行速度不同:某些事務(wù)執(zhí)行速度較慢,持有資源的時(shí)間過長,其他事務(wù)需要等待釋放,可能導(dǎo)致死鎖。
- 操作數(shù)據(jù)量過大:事務(wù)在持有鎖的同時(shí),又請求獲取更多的鎖,導(dǎo)致互相等待。
解決(避免)死鎖的方法包括:
- 減少鎖的數(shù)量:使用更低級別的隔離級別如讀提交(Read Committed),而非重復(fù)讀(Repeatable Read),可以避免特定類型的鎖競爭。
- 縮短事務(wù)持有鎖的時(shí)間:優(yōu)化事務(wù)處理邏輯,減少事務(wù)執(zhí)行時(shí)間,降低發(fā)生死鎖的可能性。
- 確定訪問數(shù)據(jù)的固定順序:在訪問多個(gè)資源時(shí),保持一致的訪問順序,以減少死鎖的發(fā)生。
- 降低操作數(shù)據(jù)的量:減少事務(wù)需要操作的數(shù)據(jù)量,盡可能縮短事務(wù)的持有時(shí)間,以減少死鎖的風(fēng)險(xiǎn)。
這些方法可以有效預(yù)防和解決數(shù)據(jù)庫死鎖問題,提升系統(tǒng)的并發(fā)處理能力和穩(wěn)定性。
MySQL 只操作同一條記錄,也會(huì)發(fā)生死鎖嗎?
答案是肯定會(huì)的。
因?yàn)?strong>數(shù)據(jù)庫的鎖機(jī)制針對的是索引而非記錄本身。
在事務(wù)中,當(dāng)我們更新一條記錄時(shí),如果使用普通索引作為條件,數(shù)據(jù)庫會(huì)先獲取普通索引的鎖,然后嘗試獲取主鍵索引的鎖。
若此時(shí)有另一個(gè)線程已經(jīng)獲得了該記錄的主鍵索引鎖,并且同時(shí)在其事務(wù)中試圖獲取該記錄的普通索引鎖,就可能導(dǎo)致死鎖的發(fā)生。
update my_table set name = 'paidaxing',age = 22 where name = "paidaxingwang";
這個(gè)SQL會(huì)先對name加鎖, 然后再回表對id加鎖。
-----
select * from my_table where id = 15 for update;
update my_table set age = 33 where name like "paidaxing%";
-- 以上SQL,會(huì)先獲取主鍵的鎖,然后再獲取name的鎖。
為了預(yù)防這種死鎖情況,可以在應(yīng)用程序中設(shè)定特定的索引獲取順序規(guī)則,比如規(guī)定只能按照主鍵索引 -> 普通索引的順序獲取鎖。這樣可以確保不同線程在獲取鎖時(shí)遵循統(tǒng)一的順序,從而有效地避免死鎖的發(fā)生(通過 SQL 保證)。
什么是死鎖,如何解決?
死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程(或線程)在執(zhí)行過程中,由于競爭資源或者彼此通信而造成的一種阻塞現(xiàn)象。在無外力作用下,它們都無法繼續(xù)向前推進(jìn)。這種狀態(tài)被稱為系統(tǒng)處于死鎖狀態(tài),或者簡稱系統(tǒng)發(fā)生了死鎖。這些相互等待的進(jìn)程被稱為死鎖進(jìn)程。
比如,丈母娘要求先買房才能結(jié)婚,但女婿堅(jiān)持要先結(jié)婚再買房,這種情況類比了死鎖的概念。
發(fā)生死鎖的四個(gè)必要條件是:
- 互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程或線程使用。
- 占有且等待:一個(gè)進(jìn)程因請求資源而阻塞時(shí),繼續(xù)持有已獲得的資源。
- 不可搶占:已獲得的資源在未使用完之前不可被強(qiáng)行剝奪。
- 循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
解除死鎖可以從以下幾個(gè)方面入手:
- 破壞不可搶占條件:設(shè)置資源的優(yōu)先級,允許高優(yōu)先級的進(jìn)程可以搶占低優(yōu)先級進(jìn)程的資源。
- 破壞循環(huán)等待條件:保證所有進(jìn)程(線程)請求資源的順序是一致的,比如按照固定的順序請求資源,例如 A->B->C,避免形成循環(huán)等待。
在數(shù)據(jù)庫中,如果多個(gè)事務(wù)并發(fā)執(zhí)行,也可能會(huì)發(fā)生死鎖。例如,當(dāng)事務(wù) 1 持有資源 A 的鎖,嘗試獲取資源 B 的鎖,同時(shí)事務(wù) 2 持有資源 B 的鎖,嘗試獲取資源 A 的鎖時(shí),就可能導(dǎo)致死鎖的發(fā)生。發(fā)生死鎖時(shí),可能會(huì)出現(xiàn)如下異常情況:
Error updating database. Cause: ERR-CODE: [TDDL-4614][ERR_EXECUTE_ON_MYSQL]
Deadlock found when trying to get lock;
一般來說,對于數(shù)據(jù)庫的死鎖問題,主要是要避免并發(fā)修改的沖突。另外一種方法是保證操作的順序,例如多個(gè)事務(wù)都先操作資源 A,再操作資源 B,這樣可以有效地避免死鎖的發(fā)生。
如何排查死鎖問題?您在生產(chǎn)環(huán)境中是否遇到過?逐步的排查方法是什么?感興趣的小伙伴可以點(diǎn)贊收藏,下期出。