<p>MySQL 資料庫的死鎖、事務日誌</p>
死鎖和事務日誌也是資料庫事務繞不開的部分,本小節將重點介紹資料庫的死鎖和事務日誌,讓大家對死鎖和事務日誌能有基本的認識。
1. 死鎖
死鎖是指兩個或多個事務在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。當多個事務嘗試以不同的順序鎖定資源,或者多個事務同時鎖定同一個資源,都有可能產生死鎖。
場景:兩個事務同時處理 customer 表
兩個事務同時執行了第一條 update 語句,更新並鎖定了該行資料,緊接著又都執行第二條 update 語句,此時發現該行已經被對方鎖定,然後兩個事務都等待對方釋放鎖,同時又持有對方需要的鎖,陷入死迴圈,需要外力介入才能解除死鎖。
mysql> CREATE TABLE `customer` (
`id` int(11) NOT NULL,
`last_name` varchar(30) DEFAULT NULL,
`first_name` varchar(30) DEFAULT NULL,
`birth_date` date DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
`balance` decimal(10,0) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
事務1 :
start transaction;
update customer set balance = 100 where id = 1;
update customer set balance = 200 where id = 2;
commit;
事務2:
start transaction;
update customer set balance = 300 where id = 2;
update customer set balance = 400 where id = 1;
commit;
為了解決死鎖問題,資料庫實現了各種死鎖檢測和死鎖超時機制。越複雜的儲存引擎,越能檢測到死鎖的迴圈以來,並返回錯誤
InnoDB 儲存引擎可以自動檢測事務的死鎖,並回滾一個或幾個事務來防止死鎖。但是有些場景 InnoDB是無法檢測到死鎖的,比如在同一事務中使用 InnoDB 之外的儲存引擎、lock tables 設定表鎖定的語句,此時要通過設定 innodb_lock_wait_timeout 這個系統引數來解決。通過鎖等待超時來解決死鎖問題,通常不是好的辦法,因為很有可能導致大量事務的鎖等待。當發生鎖等待超時,資料庫會丟擲如下報錯資訊:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
調整 innodb_lock_wait_timeout 的方法有兩種:
-
臨時:在MySQL中直接用命令列執行
-- innodb_lock_wait_timeout的預設值為50秒 mysql> show variables like 'innodb_lock_wait_timeout'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | innodb_lock_wait_timeout | 50 | +--------------------------+-------+ 1 row in set (0.00 sec) mysql> set innodb_lock_wait_timeout=51; Query OK, 0 rows affected (0.00 sec)
-
永久:將以下兩個引數新增至配置檔案 my.cnf,並重啟 MySQL:
innodb_lock_wait_timeout=50
我們在程式設計時,也要儘可能的減小死鎖發生的概率。以下是針對 InnoDB 儲存引擎減小死鎖發生概率的一些建議:
- 類似業務模組,儘可能按照相同的訪問順序來訪問,防止產生死鎖;
- 同一個事務中,儘可能做到一次鎖定需要的所有資源,減少死鎖發生概率;
- 同一個事務中,不要使用不同儲存引擎的表,比如 MyISAM 和 InnoDB 表出現在同一事務中;
- 儘可能控制事務的大小,減少鎖定的資源量和鎖定時間長度;
- 對於容易產生死鎖的業務模組,嘗試升級鎖顆粒度,通過表級鎖減少死鎖發生概率。
2. 事務日誌
使用事務日誌可以提高事務的安全性和效率:
-
修改表資料時,只需要在記憶體中進行修改,再持久化到磁碟上的事務日誌,而不用每次都將修改的資料持久化到磁碟。事務日誌持久化後,記憶體中所修改的資料可以慢慢再刷到磁碟,這種方式稱為預寫式日誌,修改資料需要寫兩次磁碟;
-
效率快很多,因為事務日誌採用追加方式,寫日誌的操作只是磁碟上一小塊區域的順序IO,不像隨機IO需要在磁碟多個地方移動磁頭;
-
萬一資料庫發生崩潰,可以通過已經持久化的事務日誌,來自動恢復資料。
3. 小結
本小節主要介紹了死鎖和事務日誌。需要重點關注的是,死鎖的基本概念、以及減小死鎖發生概率的幾種方法。