1. 程式人生 > >MySQL replace into那些隱藏的風險

MySQL replace into那些隱藏的風險

[toc] --- >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中記錄內容 ![](https://img2020.cnblogs.com/blog/1179590/202011/1179590-20201128211334800-1914139692.png) ## 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中記錄內容 ![](https://img2020.cnblogs.com/blog/1179590/202011/1179590-20201128211411580-703890124.png) ## 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中記錄內容 ![](https://img2020.cnblogs.com/blog/1179590/202011/1179590-20201128211424518-476289178.png) ## 存在問題 **場景2:** - replace into時存在唯一索引衝突:會把衝突資料刪掉,插入新資料,但binlog中記錄的是update格式,從庫同步update binlog不會更新該表的自增主鍵,主庫自增**主鍵9**,從庫自增**主鍵8**,若主從庫角色發生切換後,新主庫會存在主鍵衝突問題 - replace into唯一索引衝突會導致下游大資料hive(同步binlog寫入hive中)中資料和mysql中資料不一致問題(hive基於唯一主鍵進行處理,mysql一條資料,hive中多條資料情況) **場景3:** - replace into時存在主鍵衝突&唯一索引衝突:會把表中主鍵衝突和唯一索引衝突的資料都刪掉,再插入新資料,丟失一條資料 **經驗證:mysql5.7 和mysql8.0均是上訴情況** ## 結論 *replace into在只存在主鍵衝突時會按預期的那樣;若只有唯一索引衝突時 主從切換後導致新主庫主鍵衝突錯誤、下游大資料資料不一致問題;同時存在主鍵衝突和唯一索引衝突可能會導致丟失資料。業務上不應使用replace into,應該在程式碼對唯一資料衝突作