MySQL是現今最為流行的關系型數據庫管理系統之一,在日常企業數據應用中使用十分廣泛。MySQL在并發處理時,雖然讀寫分離能夠有效地分散讀寫請求,以減輕數據庫的負擔,提高數據庫的效率,但是在一些高并發的場景下,比如競價廣告系統中,通過MySQL的并行更新來實現多個廣告主競價時可能會造成死鎖問題。
DEADLOCK DETECTED (mysql-5.6.26) Transaction 41963 was deadlocked on lock resources with another transaci tion and was chosen as the victim. Recursion level : ‘0’
死鎖問題是指兩個或多個事務在執行時,因爭奪同一資源而相互等待的一種情況。在MySQL的并行更新中,如果使用了相同的索引,同時進行更新,在鎖的層面上,雙方產生了互斥的等待,造成了死鎖。
-- Session 1: SELECT * FROM auctions WHERE item_id=123 AND category_id=10 FOR UPDATE; UPDATE auctions SET price=price+1 WHERE item_id=123 AND category_id=10; -- Session 2: SELECT * FROM auctions WHERE item_id=123 AND category_id=10 FOR UPDATE; UPDATE auctions SET price=price+1 WHERE item_id=123 AND category_id=10;
上述代碼中,兩個Session對表auctions執行了相同的SELECT和UPDATE操作,雖然沒有顯式地加鎖,但是在執行SELECT時會自動添加共享鎖,等待執行UPDATE時會升級成排他鎖。當兩個事務同時執行UPDATE操作而在鎖的時候互相等待,就會導致死鎖。
為了避免這種情況,我們可以通過增加隨機數或其他亂序因素來避免鎖競爭,或者在競價系統中使用一些其他非關系型的數據庫,如Redis等。