innodb_rollback_on_timeout

一、innodb_rollback_on_timeout變量

有時侯會發生事務超時的情況,MySQL會返回類似這樣的錯誤:

 

1

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction.

那事務超時後會發生什麼呢?此時就需要注意到innodb_rollback_on_timeout了。

這是官方文檔對innodb_rollback_on_timeout的解釋:

在MySQL 5.6&5.7中默認值爲OFF,當InnoDB默認情況下僅回滾事務超時的最後一條語句。如果innodb_rollback_on_timeout值爲ON,則事務超時後將導致InnoDB中止並回滾整個事務。

二、驗證innodb_rollback_on_timeout=off的情況

Session A

開啓一個事務,使用讀鎖鎖住一行數據。

 

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 B

顯示開啓事務,插入數據後查詢到事務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的情況下,顯示開啓事務,造成鎖等待超時時,會回滾造成超時的那條語句,但是事務不會結束。

三、驗證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版本下,回滾時候之後就不會再新開啓一個事務了。

四、總結

如果使用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版本下需要自己手動開啓一個事務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章