MySQL數據庫innodb_rollback_on_timeout參數


在使用MySQL數據庫時,有時會出現ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 這樣的報錯。而在一個事務中,如果其中一條sql執行時出現此報錯,對本事務的其他腳本是否有影響呢,后面如果執行commit操作,報錯之前語句的結果是否成功呢? 這個結果與隔離級別以及innodb_rollback_on_timeout參數設置有關。

注: MySQL默認隔離級別為 REPEATABLE-READ,innodb_rollback_on_timeout為OFF,本文基於innodb表(支持事務)進行測試。

1. 准備工作

1.1  測試環境

MySQL 8.0

1.2 創建測試表及預備數據

創建一張測試表,並插入一條記錄

mysql> use testdb;
Database changed
mysql> create table test1(id int primary key,name varchar(20));
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test1 values(1,'1wdrt5');
Query OK, 1 row affected (0.00 sec)

mysql> select  * from  test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
+----+--------+
1 row in set (0.00 sec)

下面將根據不同的隔離級別及innodb_rollback_on_timeout啟停情況進行測試。

2. 測試過程

2.1  隔離級別REPEATABLE-READ &  innodb_rollback_on_timeout =OFF

a) 測試過程:

 
session A session B

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1 where id=1 for update;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
+----+--------+
1 row in set (0.00 sec)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
+----+--------+
2 rows in set (0.00 sec)

 

 

 

 

 

 

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select  * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
+----+--------+
1 row in set (0.00 sec)

mysql> insert into test1 values(2,'2edft6');
Query OK, 1 row affected (0.00 sec)

mysql> delete from  test1 where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.02 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
+----+--------+
2 rows in set (0.00 sec)

 

 

 

 

 

b) 測試結果:

隔離級別REPEATABLE-READ &  innodb_rollback_on_timeout =OFF (2個參數均為默認值)的情況下,即使事務中有超時回滾報錯,超時前的sql不會回滾,依舊執行成功。

2.2   隔離級別為READ-COMMITTED  &  innodb_rollback_on_timeout =OFF

a) 測試過程

session A  session B

mysql> show global variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.01 sec)

mysql> use testdb;
Database changed
mysql> begin ;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
+----+--------+
2 rows in set (0.00 sec)

mysql> select * from test1 where id =1 for update;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
+----+--------+
1 row in set (0.00 sec)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
+----+--------+
2 rows in set (0.00 sec)

mysql> insert into test1 values(3,'3eft6');
Query OK, 1 row affected (0.00 sec)

mysql> delete from test1 where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

 

 

 

 

b)測試結果:

隔離級別為READ-COMMITTED &  innodb_rollback_on_timeout =OFF 情況下,即使事務中有超時回滾報錯,超時前的sql不會回滾,依舊執行成功,同2者均為默認值的情況。

2.3  隔離級別REPEATABLE-READ &  innodb_rollback_on_timeout =ON

注: innodb_rollback_on_timeout不能在線修改,需要修改配置文件后重啟生效

測試過程:

a) 修改配置文件,重啟數據庫

在my.cnf文件里添加innodb_rollback_on_timeout=on  再重啟數據庫即可生效

mysql> show global variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

mysql> show global variables like 'innodb_rollback_on_timeout';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_rollback_on_timeout | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

b) 事務測試過程

session A session B

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

mysql> select * from test1 where id=1 for update;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
+----+--------+
1 row in set (0.00 sec)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

mysql> use testdb;
Database changed
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

mysql> insert into test1 values(4,'4rgy7');
Query OK, 1 row affected (0.00 sec)

mysql> delete from test1 where id=1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

c) 測試結果:

隔離級別REPEATABLE-READ &  innodb_rollback_on_timeout =ON 的情況下,事務中有超時回滾報錯時,超時前sql也會回滾。

2.4   隔離級別為READ-COMMITTED  &  innodb_rollback_on_timeout =ON

a) 參數調整

mysql> set global  transaction_isolation='READ-COMMITTED';
mysql> exit
#  重新登錄
mysql> show global variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set (0.00 sec)

mysql> show global variables like 'innodb_rollback_on_timeout';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| innodb_rollback_on_timeout | ON    |
+----------------------------+-------+
1 row in set (0.00 sec)

b) 測試過程

session A  session B

mysql> use testdb;
Database changed
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select  * from  test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

mysql> select * from test1 where id =1 for  update;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
+----+--------+
1 row in set (0.00 sec)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select  * from  test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
|  5 | 5thu8  |
+----+--------+
4 rows in set (0.00 sec)

 

 

 

mysql> use testdb;
Database changed
mysql> select  * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
+----+--------+
3 rows in set (0.00 sec)

mysql> insert into test1 values(5,'5thu8');
Query OK, 1 row affected (0.01 sec)

mysql> delete from test1 where id =1;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select  * from test1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 1wdrt5 |
|  2 | 2edft6 |
|  3 | 3eft6  |
|  5 | 5thu8  |
+----+--------+
4 rows in set (0.00 sec)

c)  測試結果

隔離級別為READ-COMMITTED  &  innodb_rollback_on_timeout =ON的情況下,即使事務中有超時回滾報錯,超時前的sql不會回滾,依舊執行成功,同2者均為默認值的情況。

3. 小結

在MySQL8.0 中,僅有在隔離級別為READ-COMMITTED  &  innodb_rollback_on_timeout =ON情況下,事務中有超時回滾報錯時,超時前sql也會回滾。

隔離級別 innodb_rollback_on_timeout 結果
REPEATABLE-READ OFF 超時回滾前的SQL不會自動回滾
READ-COMMITTED OFF 超時回滾前的SQL不會自動回滾
REPEATABLE-READ ON 超時回滾前的SQL自動回滾
READ-COMMITTED ON 超時回滾前的SQL不會自動回滾

TIPS:

1)  測試過程中可以查看information_schema.innodb_trx表觀察事務情況,在不同的版本中事務情況不一樣.例如,隔離級別REPEATABLE-READ & innodb_rollback_on_timeout=on的情況下,MySQL5.6 中整個事務回滾后會自動創建一個事務,而MySQL5.7則不會再自動創建事務。

2)  在生產環境使用中,建議將innodb_rollback_on_timeout 設置為ON。應用程序一定要做好事務控制,在一個事務出現異常時必須進行顯式rollback


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM