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版本下须要本身手动开启一个事务。