mysql> show engine innodb status;
------------
TRANSACTIONS
------------
Trx id counter 15102
Purge done for trx's n:o < 15096 undo n:o < 0 state: running but idle
History list length 944
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 15066, not started
MySQL thread id 53, OS thread handle 0x7f5d57d47700, query id 1615 localhost root
---TRANSACTION 15065, not started
MySQL thread id 52, OS thread handle 0x7f5d57dc9700, query id 1590 localhost root
---TRANSACTION 15097, not started
MySQL thread id 51, OS thread handle 0x7f5d57ecd700, query id 1637 localhost root
---TRANSACTION 0, not started
MySQL thread id 50, OS thread handle 0x7f5d57e0a700, query id 1642 localhost root init
show engine innodb status
---TRANSACTION 15101, ACTIVE 3 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 49, OS thread handle 0x7f5d57d88700, query id 1641 localhost root update
insert into ttt values(0)
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 190 page no 3 n bits 80 index `GEN_CLUST_INDEX` of table `test`.`ttt` trx id 15101 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
------------------
---TRANSACTION 15087, ACTIVE 215 sec
2 lock struct(s), heap size 360, 9 row lock(s)
MySQL thread id 43, OS thread handle 0x7f5d57f0e700, query id 1631 localhost root
可以发现,这时的锁不是范围锁,因为没有了locks gap,但却仍然是行锁而不是表锁,只不过此时等价于表锁。如下
mysql> select * from information_schema.innodb_locks\G
*************************** 1. row ***************************
lock_id: 15102:190:3:1
lock_trx_id: 15102
lock_mode: X
lock_type: RECORD
lock_table: `test`.`ttt`
lock_index: GEN_CLUST_INDEX
lock_space: 190
lock_page: 3
lock_rec: 1
lock_data: supremum pseudo-record
*************************** 2. row ***************************
lock_id: 15087:190:3:1
lock_trx_id: 15087
lock_mode: S
lock_type: RECORD
lock_table: `test`.`ttt`
lock_index: GEN_CLUST_INDEX
lock_space: 190
lock_page: 3
lock_rec: 1
lock_data: supremum pseudo-record
发现确实是行锁而非表锁。并且索引键值那里为"supermum pseudo-record",这表示锁定的是"最大上界伪记录",即锁定的是无穷值。
没索引的时候,哪怕查询具体的行记录都会锁定整个区间,更不用说锁定范围(例如:where id>5)。其实它们的结果都是一样的:锁定整个区间。
4.4 innodb中的锁等待超时
在innodb存储引擎中,当出现锁等待时,如果等待超时,将会结束事务,超时时长通过动态变量innodb_lock_wait_timeout值来决定,默认是等待50秒。关于锁等待超时,可以直接在语句中设置超时时间。可以设置锁等待超时时间的语句包括:wait n的n单位为秒,nowait表示永不超时。
ALTER TABLE tbl_name [WAIT n|NOWAIT] ...
CREATE ... INDEX ON tbl_name (index_col_name, ...) [WAIT n|NOWAIT] ...
DROP INDEX ... [WAIT n|NOWAIT]
DROP TABLE tbl_name [WAIT n|NOWAIT] ...
LOCK TABLE ... [WAIT n|NOWAIT]
OPTIMIZE TABLE tbl_name [WAIT n|NOWAIT]
RENAME TABLE tbl_name [WAIT n|NOWAIT] ...
SELECT ... FOR UPDATE [WAIT n|NOWAIT]
SELECT ... LOCK IN SHARE MODE [WAIT n|NOWAIT]
TRUNCATE TABLE tbl_name [WAIT n|NOWAIT]
超时后结束事务的方式有中断性结束和回滚性结束两种方式,这也是通过变量来控制的,该变量为innodb_rollback_on_timeout,默认为off,即超时后不回滚,也即中断性结束。
mysql> show variables like "innodb%timeout";
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| innodb_flush_log_at_timeout | 1 |
| innodb_lock_wait_timeout | 50 |
| innodb_rollback_on_timeout | OFF |
+-----------------------------+-------+