我们有一张表:

create table mylock(
id int(10) not null,
name varchar(50),
primary key(id)
)engine=innodb default charset=utf8;

如果我问

update mylock set name='obama' where id=1;

会对那些数据加锁呢?

你一定会不加思索的说,在这个事务中,当然是id=1这一行,加上行锁嘛。

但是事实真是如此吗?那么让我们来做一个实验。

首先在你的mysql服务器上执行如下语句:

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

这表示你每一行语句都是自动提交的,在你执行完毕语句后,都是commit的。

我们需要执行以下语句,保证我们的几个session都是在一个事务之中。

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from mylock;
+----+----------------+
| id | name           |
+----+----------------+
|  1 | Obama          |
|  2 | David Thompson |
|  3 | 三毛           |
|  4 | Mr.Homer       |
+----+----------------+
4 rows in set (0.00 sec)

现在我们的表里有以上几条数据。

然后我们在第一个回话session1执行如下语句:

session1:


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

session2:

mysql> update mylock set name='Bush' where name ='Obama';

然后,session2就是长长的等待。

知道你去session1上commit之后,session2才更新成功。

mysql> update mylock set name='Bush' where name ='Obama';
Query OK, 1 row affected (14.51 sec)
Rows matched: 1  Changed: 1  Warnings: 0

这个实验告诉我们,有些行锁是会锁住全表的。那么这些行是哪些行呢?

将在后面的实验进行解读。