http://www.ywnds.com/?p=9560mysql
1、innodb_rollback_on_timeout變量sql
有時侯會發生事務超時的狀況,MySQL會返回相似這樣的錯誤:shell
1
|
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction.
|
那事務超時後會發生什麼呢?此時就須要注意到innodb_rollback_on_timeout了。session
這是官方文檔對innodb_rollback_on_timeout的解釋:ide
在MySQL 5.6&5.7中默認值爲OFF,當InnoDB默認狀況下僅回滾事務超時的最後一條語句。若是innodb_rollback_on_timeout值爲ON,則事務超時後將致使InnoDB停止並回滾整個事務。字體
2、驗證innodb_rollback_on_timeout=off的狀況spa
Session Arest
開啓一個事務,使用讀鎖鎖住一行數據。code
1
2
3
4
5
6
7
|
session a: db01> start transaction;
session a: db01> select * from t1 where id = 1 lock in share mode ;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
+----+------+
|
Session Borm
顯示開啓事務,插入數據後查詢到事務ID是4891。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
session b:db01> start transaction;
session b:db01> insert into t1 value(3,3);
session b:db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 4891
trx_state: RUNNING
trx_mysql_thread_id: 4
trx_query: select * from information_schema.innodb_trx
*************************** 2. row ***************************
trx_id: 4888
trx_state: RUNNING
trx_mysql_thread_id: 5
trx_query: NULL
|
再在此事務中執行會形成鎖等待的語句,超時後查詢發現,數據(3,3)順利插入,可是理應更新的數據(1,11)沒有了,說明發生了文檔所說的回滾最新的一條語句。 事務並不會自動結束,否則就會破壞事務的原子性。
1
2
3
4
5
6
7
8
9
10
11
|
session b:db01> update t1 set age = 11 where id = 1 ;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session b:db01> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
3 rows in set (0.00 sec)
|
查詢事務,發現4891事務還存在。
1
2
3
4
5
6
7
8
9
10
11
|
session b:db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 4891
trx_state: RUNNING
trx_mysql_thread_id: 4
trx_query: select * from information_schema.innodb_trx
*************************** 2. row ***************************
trx_id: 4888
trx_state: RUNNING
trx_mysql_thread_id: 5
trx_query: NULL
|
若是此時Session B執行回滾事務,新插入的數據(3,3)被回滾了。那麼Session A也就天然看不到曾經被更改的數據了(不針對讀未提交隔離級別)。
若是Session B執行提交,在Session A能夠看到數據(3,3) 。
1
|
session b:db01> commit ;
|
Session A
1
2
3
4
5
6
7
8
|
session a:db01>select * from t1 ;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
|
innodb_rollback_on_timeout=off的狀況下,顯示開啓事務,形成鎖等待超時時,會回滾形成超時的那條語句,可是事務不會結束。
3、驗證innodb_rollback_on_timeout=on的狀況
注意:
1. innodb_rollback_on_timeout不支持動態修改,修改須要停服務。
2. innodb_rollback_on_timeout=on的狀況下,5.6版本和5.7版本的行爲會不同,爲了不麻煩,一併在下表作對比。
Session A(5.6&5.7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
session a: db01> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
+----+------+
session a: db01> start transaction;
session a: db01> select * from t1 where id = 1 lock in share mode ;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
+----+------+
|
Session B(5.6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
session b: db01> start transaction ;
session b: db01> insert into t1 value(3,3);
session b: db01> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
session b: db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 5388
trx_state: RUNNING
trx_mysql_thread_id: 2
trx_query: select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx
*************************** 2. row ***************************
trx_id: 5387
trx_state: RUNNING
trx_mysql_thread_id: 1
trx_query: NULL
|
Session C(5.7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
session c: db01> start transaction ;
session c: db01> insert into t1 value(3,3);
session c: db01> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----+------+
session c: db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 3201284
trx_state: RUNNING
trx_mysql_thread_id: 2
trx_query: select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx
*************************** 2. row ***************************
trx_id: 422128392099664
trx_state: RUNNING
trx_mysql_thread_id: 3
trx_query: NULL
|
Session B(5.6)和Session C(5.7)分別開啓事務,插入數據(3,3)。查詢到新增的事務分別是5388和3201284。
而後都執行會形成鎖等待的語句:
Session B(5.6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
session b: db01> update t1 set age = 11 where id =1 ;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session b: db01> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
+----+------+
session b: db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 5401
trx_state: RUNNING
trx_mysql_thread_id: 2
trx_query: select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx
*************************** 2. row ***************************
trx_id: 5387
trx_state: RUNNING
trx_mysql_thread_id: 1
trx_query: NULL
|
Session C(5.7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
session c: db01> update t1 set age = 11 where id = 1 ;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session c: db01> select * from t1;
+----+------+
| id | age |
+----+------+
| 1 | 1 |
| 2 | 2 |
+----+------+
session c: db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 422128392099664
trx_state: RUNNING
trx_mysql_thread_id: 3
trx_query: NULL
|
超時後再查詢發現:
1. 新插入的數據都回滾了。
2. Session B(5.6)原先的事務5388已經不見了,新增長了一個事務5401。說明5.6版本狀況下,innodb_rollback_on_timeout=on,鎖超時後,接收下一句語句時會當即開啓一個新事務。
3. Session C(5.7)原先的事務3201284已經不見了。
再驗證不顯示開始事務的狀況,發現此時Session B(5.6)沒有自動開啓事務。
1
2
3
4
5
6
7
8
9
|
session b: db01> rollback ;
session b: db01> update t1 set age = 11 where id =1 ;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session b: db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 5387
trx_state: RUNNING
trx_mysql_thread_id: 1
trx_query: NULL
|
1
2
3
4
5
6
7
8
|
session c: db01> update t1 set age = 11 where id = 1 ;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
session c: db01> select trx_id,trx_state,trx_mysql_thread_id,trx_query from information_schema.innodb_trx\G
*************************** 1. row ***************************
trx_id: 422128392099664
trx_state: RUNNING
trx_mysql_thread_id: 3
trx_query: NULL
|
innodb_rollback_on_timeout=on時,在5.6的版本下,由上文加粗加紅的字體能夠看到事務的ID的發祥變化,說明開啓了一個新的事務。由此明白事務會總體回滾,而後新開一個事務接收下一次查詢。可是在5.7版本下,回滾時候以後就不會再新開啓一個事務了。
4、總結
若是使用MySQL 5.6:
innodb_rollback_on_timeout=off的狀況下,會回滾最後的形成鎖等待的語句,事務沒有自動結束.可是這樣會形成數據的不一致,破壞了事務的原子性。
innodb_rollback_on_timeout=on的狀況下,整個事務回滾後會自動建立一個事務。
若是使用MySQL 5.7:
innodb_rollback_on_timeout=off的狀況下和5.6版本是同樣的。
innodb_rollback_on_timeout=on的狀況下,整個事務已經自動回滾,不會再自動建立事務。
因此無論是5.6的版本仍是5.7的版本,innodb_rollback_on_timeout最好設置成ON,這樣能夠避免破壞事務原子性,保證數據一致性。惟一的區別是在5.7版本下須要本身手動開啓一個事務。