2017-02-19 101 views
0

当在mysql(innodb)中创建一个死锁时,如“高性能MySQL”的第10页上的示例。但是如果我在一次交易中更新一行测试,则更新另一行将被阻止并最终超时。这就像innodb使用表级锁而不是使用行级锁进行更新时所在的条件。这种情况不符合innodb的行级锁。mysql innodb table lock - 在另一行上更新一行块更新

MySQL的版本:

mysql> status 
-------------- 
mysql Ver 14.14 Distrib 5.6.26, for Linux (x86_64) using EditLine wrapper 

Connection id:   2 
Current database:  test 
Current user:   [email protected] 
SSL:     Not in use 
Current pager:   stdout 
Using outfile:   '' 
Using delimiter:  ; 
Server version:   5.6.26 MySQL Community Server (GPL) 
Protocol version:  10 
Connection:    Localhost via UNIX socket 
Server characterset: latin1 
Db  characterset: latin1 
Client characterset: utf8 
Conn. characterset: utf8 
UNIX socket:   /var/lib/mysql/mysql.sock 
Uptime:     4 hours 52 min 1 sec 

Threads: 3 Questions: 107 Slow queries: 0 Opens: 69 Flush tables: 1 Open tables: 62 Queries per second avg: 0.006 
-------------- 

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

创建测试表:

mysql> show create table t\G; 
*************************** 1. row *************************** 
     Table: t 
Create Table: CREATE TABLE `t` (
    `a1` int(11) DEFAULT NULL, 
    `b` varchar(10) DEFAULT NULL, 
    `c` varchar(10) DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
1 row in set (0.00 sec) 

ERROR: 
No query specified 

mysql> select * from t; 
+------+------+------+ 
| a1 | b | c | 
+------+------+------+ 
| 1 | a | b | 
| 2 | aa | bb | 
+------+------+------+ 
2 rows in set (0.00 sec) 

然后打开两个独立的会话创建两个交易

会议1

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

mysql> update t set b='x' where a1=2; 
Query OK, 1 row affected (0.00 sec) 
Rows matched: 1 Changed: 1 Warnings: 0 

单位秒宽恕请求2,更新就会被阻塞,最后超时

mysql> start transaction 
    -> ; 
Query OK, 0 rows affected (0.00 sec) 

mysql> update t set c='yy' where a1=1; 
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 

在块,使用InnoDB插件来获得锁定关系

mysql> SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, 
    ->  r.trx_query waiting_query, 
    ->  b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, 
    ->  b.trx_query blocking_query 
    -> FROM  information_schema.innodb_lock_waits w 
    -> INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id 
    -> INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id; 
+----------------+----------------+--------------------------------+-----------------+-----------------+----------------+ 
| waiting_trx_id | waiting_thread | waiting_query     | blocking_trx_id | blocking_thread | blocking_query | 
+----------------+----------------+--------------------------------+-----------------+-----------------+----------------+ 
| 5933   |    6 | update t set c='yy' where a1=1 | 5932   |    5 | NULL   | 
+----------------+----------------+--------------------------------+-----------------+-----------------+----------------+ 
1 row in set (0.00 sec) 

原则,在会话1行锁不会阻止在会话更新2.

如果您遇到过这样的问题,请您帮忙解释会话2被阻止的原因。

+0

你真的没有'PRIMARY KEY'这张桌子吗?对于InnoDB表来说,这是一个“否定”。 –

回答

0

不考虑在没有PRIMARY KEY的InnoDB中使用事务。

并认真考虑在做UPDATE ... WHERE ai = constant时至少使用INDEX(a1)。否则,InnoDB会因为“行级锁定”而变得sl - 不安 - 可能是因为它无法在没有索引的情况下抓住每个“行”。

+0

在测试表'alter table t add primary key(a1);'上添加主键后,innodb在会话1上检测到死锁。并且使用索引'create index ind_t on t(a1);',innodb也检测到死锁。主键和索引之间的区别在于在使用索引时在会话1上使用主键时在会话2上检测到死锁。 – camash

+0

(我不相信可以预测哪个连接的选择是可预测的。) –