MySQL replace into那些隱藏的風險



MySQL中 replace into是否像預期樣:若表中有已經存在的數據,則把已經存在的數據刪除,插入新數據?

准備數據


CREATE TABLE `test_replace` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `str1` char(10) DEFAULT NULL, 
  `str2` char(10) DEFAULT NULL, 
  PRIMARY KEY (`id`), 
  UNIQUE KEY `uqx_str` (`str1`) 
) ENGINE=InnoDB;

insert into test_replace(id,str1,str2) values(2,1234,'aaabbbb'),(4,123456,'bbbbxxxx');

select * from test_replace; 
+----+--------+----------+ 
| id | str1   | str2     | 
+----+--------+----------+ 
|  2 | 1234   | aaabbbb  | 
|  4 | 123456 | bbbbxxxx | 
+----+--------+----------+ 
2 rows in set (0.00 sec)

replace into時存在主鍵沖突


replace into test_replace(id,str1,str2) values(2,'xxxx','yyy'); 
Query OK, 2 rows affected (0.00 sec)

select * from test_replace; 
+----+--------+----------+ 
| id | str1   | str2     | 
+----+--------+----------+ 
|  2 | xxxx   | yyy      | 
|  4 | 123456 | bbbbxxxx | 
+----+--------+----------+


binlog中記錄內容

replace into時存在唯一索引沖突


replace into test_replace(id,str1,str2) values(8,'xxxx','ppppp'); 
Query OK, 2 rows affected (0.01 sec)

select * from test_replace; 
+----+--------+----------+ 
| id | str1   | str2     | 
+----+--------+----------+ 
|  4 | 123456 | bbbbxxxx | 
|  8 | xxxx   | ppppp    | 
+----+--------+----------+

show create table `test_replace`\G 
*************************** 1. row *************************** 
       Table: test_replace 
Create Table: CREATE TABLE `test_replace` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `str1` char(10) DEFAULT NULL, 
  `str2` char(10) DEFAULT NULL, 
  PRIMARY KEY (`id`), 
  UNIQUE KEY `uqx_str` (`str1`) 
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
###下一次插入非沖突數據時自增主鍵為9

binlog中記錄內容

replace into時存在主鍵沖突&唯一索引沖突


replace into test_replace(id,str1,str2) values(8,'123456','主鍵和唯一索引沖 
突'); 
Query OK, 3 rows affected (0.01 sec)

####插入了這條數據后,原來的兩條數據(主鍵4,8)變成了一條(主鍵 8),數據丟失!!!
select * from test_replace; 
+----+--------+-----------------------------+ 
| id | str1   | str2                        | 
+----+--------+-----------------------------+ 
|  8 | 123456 | 主鍵和唯一索引沖突          | 
+----+--------+-----------------------------+

show create table test_replace\G 
*************************** 1. row *************************** 
       Table: test_replace 
Create Table: CREATE TABLE `test_replace` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `str1` char(10) DEFAULT NULL, 
  `str2` char(10) DEFAULT NULL, 
  PRIMARY KEY (`id`), 
  UNIQUE KEY `uqx_str` (`str1`) 
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 
1 row in set (0.00 sec)

binlog中記錄內容

存在問題

場景2:

  • replace into時存在唯一索引沖突:會把沖突數據刪掉,插入新數據,但binlog中記錄的是update格式,從庫同步update binlog不會更新該表的自增主鍵,主庫自增主鍵9,從庫自增主鍵8,若主從庫角色發生切換后,新主庫會存在主鍵沖突問題
  • replace into唯一索引沖突會導致下游大數據hive(同步binlog寫入hive中)中數據和mysql中數據不一致問題(hive基於唯一主鍵進行處理,mysql一條數據,hive中多條數據情況)

場景3:

  • replace into時存在主鍵沖突&唯一索引沖突:會把表中主鍵沖突和唯一索引沖突的數據都刪掉,再插入新數據,丟失一條數據

場景2和場景3我們線上mysql5.7環境均躺槍~
經驗證:mysql5.7 和mysql8.0均是上訴情況

結論

replace into在只存在主鍵沖突時會按預期的那樣;若只有唯一索引沖突時 主從切換后導致新主庫主鍵沖突錯誤、下游大數據數據不一致問題;同時存在主鍵沖突和唯一索引沖突可能會導致丟失數據。業務上不應使用replace into,應該在代碼對唯一數據沖突作處理


免責聲明!

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



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