我们创建了一个简单的表 t,并插入一行,然后对这一行做修改。
mysql> CREATE TABLE `t` (
`id` int(11) NOT NULL primary key auto_increment,
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB;
insert into t values(1,2);
这时候,表 t 里有唯一的一行数据 (1,2)。假设,我现在要执行:
mysql> update t set a=2 where id=1;
结果显示,匹配 (rows matched) 了一行,修改 (Changed) 了 0 行。
仅从现象上看,MySQL 内部在处理这个命令的时候,可以有以下三种选择:
1.更新都是先读后写的,MySQL 读出数据,发现 a 的值本来就是 2,不更新,直接返回,执行结束;
2.MySQL 调用了 InnoDB 引擎提供的“修改为(1,2)”这个接口,但是引擎发现值与原来相同,不更新,直接返回;
3.InnoDB 认真执行了“把这个值修改成 (1,2)这个操作,该加锁的加锁,该更新的更新。
你觉得实际情况会是以上哪种呢?你可否用构造实验的方式,来证明你的结论?
进一步地,可以思考一下,MySQL 为什么要选择这种策略呢?
第一个选项,我们可以用一个锁实验来确认。
假设,当前表 t 里的值是 (1,2)。
session B 的 update 语句被 blocked 了,加锁这个动作是 InnoDB 才能做的,所以排除选项 1。
第二个选项,我们可以用一个可见性实验来确认。
假设当前表里的值是 (1,2)。
session A 的第二个 select 语句是一致性读(快照读),它是不能看见 session B 的更新的。
现在它返回的是 (1,3),表示它看见了某个新的版本,这个版本只能是 session A 自己的 update 语句做更新的时候生成。
选项 3,即:InnoDB 认真执行了“把这个值修改成 (1,2)这个操作,该加锁的加锁,该更新的更新