Mysql 更新相同数据问题

看了极客时间,Mysql 45讲,老师留了一个问题,感觉很有意思,问题如下:

我们创建了⼀个简单的表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为什么要
选择这种策略呢?

 首先,做一个大胆的直觉猜想,3选择看上去就很笨,Mysql应该不会这么做,认真修改过的话,这里结果应该显示修改了1行,而不是0行吧。

带有个人感情色彩,我还是觉得1的可能性更大,但是作为一个严谨的人不能如此草率下结论。

哈哈哈。看了答案,我的想法是大错特错。

下面根据老师的解答来一一验证:

1:开启两个会话A,B,A先执行 update t set a=2 where id=1; B再执行 update t set a=2 where id=1;出现情况如下

会话A

Mysql 更新相同数据问题_第1张图片

会话B 

 

 

 

事务B 已经卡住不动了,说明这时 这一行数据已经被锁住。然后根据老师的解析,加锁只会在Innodb才做,所以不是直接返回的,1就排除了。

2:

会话A

Mysql 更新相同数据问题_第2张图片

会话B

 

会话A

Mysql 更新相同数据问题_第3张图片

由此说明,因为当前事务的隔离级别是可重复读,所以会话A 看不到会话B修改的值,看到的是自已修改的值,所以SQL是认真执行了更新操作。 

或者执行命令 在执行 update语句 前后 执行 show engine innodb status; 会发现 Number of rows updated 值+1 所以是有更新的。

综上 看出应该是结论3正确。

但是又看过一篇 文章 当 

在binlog_format=row

和binlog_row_image=FULL时,

由于MySQL 需要在 binlog 里面记录所有的字段,所以在读数据的时候就会把所有数据都读出来,那么重复数据的update不会执行。即MySQL 调用了 InnoDB 引擎提供的“修改为 (1,55)”这个接口,但是引擎发现值与原来相同,不更新,直接返回


在binlog_format=statement

和binlog_row_image=FULL时,

InnoDB内部认真执行了update语句,即“把这个值修改成 (1,999)“这个操作,该加锁的加锁,该更新的更新。

引用自https://mp.weixin.qq.com/s/UWl4svHdcUIgsHnmhoysTA

你可能感兴趣的:(Mysql 更新相同数据问题)