update 修改单表的多个字段,造成数据混乱
1、问题描述
在某个环境里面,需要修改单个表的多个字段,造成了数据混乱,跟理想修改的数据不一致。
1.1 模拟问题现象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
# 注意: 创建的表没有主键,且 t1 表是 innodb 引擎 root@localhost [keme]>create table t1 (a int ,b int ,primary key(a)); Query OK, 0 rows affected (0.02 sec) root@localhost [keme]>insert into t1 values (1,10),(2,20),(3,30); Query OK, 3 rows affected (0.02 sec) Records: 3 Duplicates: 0 Warnings: 0 root@localhost [keme]> select * from t1; +------+------+ | a | b | +------+------+ | 1 | 10 | | 2 | 20 | | 3 | 30 | +------+------+ # 进行修改多个字段 root@localhost [keme]>update t1 set a=a+1,b=a+10 where a=2; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 root@localhost [keme]> select * from t1; +------+------+ | a | b | +------+------+ | 1 | 10 | | 3 | 13 | | 3 | 30 | +------+------+ 3 rows in set (0.00 sec) |
修改的条件是a=2,为啥修改的结果是(3,13),不应该是(3,12)吗?
是不是很多人以为修改的结果是(3,12),是不是感觉数据是乱的,如果一条数据改回正常还是挺简单,关键数据量很多改的就费劲了啊,时间还长。
1.2 问题故障原因
因为 update 是当前读,读取的是记录数据的最新版本,就是
1
2
3
4
|
update t1 set a=a+1,b=a+10 where a=2; update a=a+1 因为要做当前读 现在a =2 +1 后 a=3 ,保证最新值 在做 b=a+10 也需要读到a值的最新的值 还要加锁, 现在a的值已经变成3 , 在加10不就变成13 |
1.3 解决故障
1
2
3
4
5
6
7
8
9
10
11
|
# 我先改回原来数据 root@localhost [keme]>update t1 set a=2,b=20 where a=3 and b=13; # 可以把 a 列暂存在一个临时变量里 root@localhost [keme]> select a into @a from t1 where a=2; # 修改数据 root@localhost [keme]>update t1 set a=@a+1,b=@a+10 where a=@a; #验证结果 是不是 (3,12) |
2、问题总结
我们需要知道一些相关原理: 快照读,当前读
2.1、快照读(select)
执行select的时候,innodb默认会执行快照读,快照读,也就是读取快照的数据,数据虽然是一致的,但是数据是历史数据。
快照读:只是简单的 select ,不包括 select ... lock in share mode, select ... for update
2.2、当前读
select ... lock in share mode
select ... for update
insert
update
delete
当你执行这几个操作的时候默认会执行当前读,也就是会读取最新的记录,也就是别的事务提交的数据你也可以看到。
update 执行当前读,然后把返回的数据加锁,之后执行update。
加锁是防止别的事务在这个时候对这条记录做什么,默认加的是排他锁,也就是只允许读,其他都不可以,这样就可以保证数据不会出错了。
3、延伸阅读
上面的情况是:
- innodb 引擎
- 表中无主键
如果表中有主键,或者是其他引擎,正确操作,请看下面的大神文章
分类:
MySQL
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了