前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >update 修改单表的多个字段,造成数据混乱

update 修改单表的多个字段,造成数据混乱

作者头像
老叶茶馆
发布2020-06-24 17:24:50
9400
发布2020-06-24 17:24:50
举报

作者:杨建,知数堂优秀校友。 原文:https://www.cnblogs.com/keme/p/13101115.html

1、问题描述1.1、模拟问题现象1.2、问题故障原因1.3、解决故障2、问题总结2.1、快照读(select)2.2、当前读3、延伸思考

1、问题描述

今天 QQ群里在讨论一个问题,在某个环境里面,需要修改单个表的多个字段,造成了数据混乱,跟理想修改的数据不一致。

1.1、模拟问题现象

代码语言:javascript
复制
# 注意: 创建的表没有主键,且 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)

![img](./image/update 修改多字段,造成数据混乱/1.png)

修改的条件是a=2,为啥修改的结果是(3,13),不应该是(3,12)吗?

是不是很多人以为修改的结果是(3,12),是不是感觉数据是乱的,如果一条数据改回正常还是挺简单,关键数据量很多改的就费劲了啊,时间还长。

1.2、问题故障原因

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

代码语言:javascript
复制
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、解决故障

代码语言:javascript
复制
# 我先改回原来数据
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)

![img](./image/update 修改多字段,造成数据混乱/2.png)

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 引擎
  • 表中无主键

如果表中有主键,或者是其他引擎,正确操作,请看下面的大神文章

代码语言:javascript
复制
https://imysql.com/2008_06_17_sth_about_update_duplicate_key

全文完。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老叶茶馆 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、问题描述
    • 1.1、模拟问题现象
      • 1.2、问题故障原因
        • 1.3、解决故障
        • 2、问题总结
          • 2.1、快照读(select)
            • 2.2、当前读
            • 3、延伸思考
            相关产品与服务
            云数据库 SQL Server
            腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档