龙空技术网

mysql由于快照读,造成数据混乱,该如何解决

程序不就是0和1 146

前言:

目前大家对“mysql快照表”大概比较注意,姐妹们都想要知道一些“mysql快照表”的相关文章。那么小编也在网络上网罗了一些有关“mysql快照表””的相关文章,希望大家能喜欢,兄弟们快快来了解一下吧!

先看看问题场景

某些业务需要更新某一个表的多个字段,很可能更新的结果跟理想值不一致。简单来讲就是执行类似下面的sql会出什么结果?

update test set a = a+1,b=a+1 where id =2

我们来模拟一下上面的sql环境,我们创建一个test表,并使用innodb存储引擎。

create table test (id int,a int,b int,primary key(id));

增加三行数据

insert into test values (1,10,100),(2,20,200),(3,30,300)

进行修改多个字段

update test set a = a+1,b=a+1 where id =2

修改的条件是id=2,为啥修改的结果是(2,21,22),不应该是(2,21,21)吗?是不是很多人以为修改的结果是(2,21,21),是不是感觉数据是乱的,如果数据少,改回去还算省事,关键数据量很多,改的工作量就大了,还容易出错。

原因分析

因为 update 是当前读,读取的是记录数据的最新版本,

update test set a = a+1,b=a+1 where id =2

update a=a+1 因为要做当前读 现在a =20 +1 后 a=21 ,保证最新值,再做 b=a+1

也需要读到a值的最新的值 还要加锁, 现在a的值已经变成21, 再加1就变成22,

那么如果我想按照我们的理想值更新出结果,那要怎么做呢?

问题解决

可以把 a 列暂存在一个临时变量里

select a into @a from test where a=2;

再执行修改

update test set a=@a+1,b=@a+1 where a=@a;

结果就会是(2,21,21)了

总结一下快照读

执行select的时候,innodb默认会执行快照读,快照读,也就是读取快照的数据,数据虽然是一致的,但是数据是历史数据。

快照读:只是简单的 select ,不包括 select … lock in share mode, select … for update

当前读

当你执行这几个操作的时候默认会执行当前都会加锁,也就是会读取最新的记录,也就是别的事务提交的数据你也可以看到。

update 执行当前读,然后把返回的数据加锁,之后执行update。

加锁是防止别的事务在这个时候对这条记录做什么,默认加的是排他锁,也就是只允许读,其他都不可以,这样就可以保证数据不会出错了。

标签: #mysql快照表