update 修改單表的多個字段,造成數據混亂


1、問題描述

今天 QQ群里在討論一個問題,在某個環境里面,需要修改單個表的多個字段,造成了數據混亂,跟理想修改的數據不一致。

1.1 模擬問題現象

# 注意: 創建的表沒有主鍵,且 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  是當前讀,讀取的是記錄數據的最新版本,就是  

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 解決故障

# 我先改回原來數據
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 引擎
  • 表中無主鍵

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

https://imysql.com/2008_06_17_sth_about_update_duplicate_key

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM