故事是這樣開始的
在一個月黑風(fēng)高的夜晚
現(xiàn)場報過來,本該打到新服務(wù)的流量,又走到了老服務(wù),老服務(wù)的功能不健全,很可能會讓現(xiàn)場的用戶不能支付。 需要說明一點的是,任何一個從老服務(wù)改造到新服務(wù)的時候,都不是完全把流量切過去,都需要經(jīng)過一點時間去驗證。
比如我們按照地理位置去切,將北京的部分車場(是的,我們是做停車服務(wù)的),切到新服務(wù),其他城市的車場在老服務(wù)
我們采用最簡單的辦法,就是靠一個字段type去控制(0和1)
看似簡單,但是事怪就怪在這個字段上,這個控制字段是屬于后來加到數(shù)據(jù)庫字段的,而且沒有對外去配置,都是通過運維手動去數(shù)據(jù)庫配置的,且數(shù)據(jù)庫字段默認(rèn)值設(shè)置為1。
可總有幾個車場時不時的從0就變成了1。。眾所周知,一個新的字段不在mybatis xml和pojo出現(xiàn),那么就不會有操作改掉
翻遍所有的服務(wù),關(guān)乎這個表的都是update操作,update操作因為沒有這個字段時打死也不會改這個type的
冷靜下來想想,數(shù)據(jù)庫默認(rèn)字段為1,然后0都會變成1。沒有1變成0的,可以肯定的是,先刪除,又新增了,否則沒有別的解釋
經(jīng)過一番查驗,找到這樣一堆代碼(偽代碼)
replace INTO `A` ( park_id, xxxx, xxxx ) SELECT park_id, xxxx, xxxx FROM B where b.park_id = #{parkId}復(fù)制代碼
看到這里,心里嘿嘿一笑,破案了。。。。。
replace INTO
是的,就是replace INTO搞得鬼,大家都知道,replace INTO和insert into的區(qū)別
1、replace into 首先嘗試插入數(shù)據(jù)到表中, 如果發(fā)現(xiàn)表中已經(jīng)有此行數(shù)據(jù)(根據(jù)主鍵或者唯一索引判斷)則先刪除此行數(shù)據(jù),然后插入新的數(shù)據(jù)。
2、如果表中無此數(shù)據(jù),則插入新數(shù)據(jù)。
這就正好驗證了上面的猜想,只有刪除再添加,才會讓type跟隨數(shù)據(jù)庫的默認(rèn)值走
講到這里不妨我們多了解一點這個,有人可能會問,replace是不是取代了insert和delete,畢竟是干了兩件事
MySql手冊關(guān)于replace into的算法:Mysql手冊
MySQL uses the following algorithm for REPLACE (and LOAD DATA ... REPLACE):Try to insert the new row into the tableWhile the insertion fails because a duplicate-key error occurs for a primary key or unique index:Delete from the table the conflicting row that has the duplicate key valueTry again to insert the new row into the tableMySQL對REPLACE(和LOAD DATA…REPLACE)使用以下算法: 嘗試將新行插入表中 當(dāng)由于主鍵或唯一索引出現(xiàn)重復(fù)鍵錯誤而導(dǎo)致插入失敗時: 從表中刪除具有重復(fù)鍵值的沖突行 再次嘗試將新行插入表中復(fù)制代碼
先插入, 出錯了再執(zhí)行delete加insert. 如果自己用程序來做, 個人認(rèn)為效率會低很多,另外這樣寫真的很搞人
這里推薦使用INSERT…ON DUPLICATE KEY UPDATE, 感覺很靠譜. replace的副作用:
-
replace每次要重新分配自增id;
-
replace中執(zhí)行delete時, 在有外鍵的情況下會很麻煩;
-
如果delete時定義的有觸發(fā)器, 則會被執(zhí)行;
-
副作用也會被傳播到replica slave
總結(jié)
開發(fā)當(dāng)中難免遇到奇奇怪怪的各種問題,有問題莫慌,冷靜分析,你認(rèn)為的不可能事件、你認(rèn)為的計算機會發(fā)生錯誤,其實都是自己沒有去完全理解到位,跟蹤到位?。?!【推薦學(xué)習(xí):MySQL視頻教程、SQL視頻教程】
最后祝大家2023,少寫bug,少加班,多漲薪