高併發場景下數據重複插入的問題以及DuplicateKeyException異常在高併發下或批量插入數據時如何優化

問題:

       1.高併發時,數據庫插入操作拋出DuplicateKeyException異常;

       2.批量插入數據的時,數據庫插入操作拋出DuplicateKeyException異常;

異常信息如下:

      org.springframework.dao.DuplicateKeyException: ....(具體信息省略......)


解決方案:

 

      方案一:捕獲異常,適用於需要對異常處理的程序,如交易訂單號重複,給客戶友好提示;

        try{
            // 入庫操作
            inset into ...
        }catch (DuplicateKeyException e){
            // 返回響應信息或或略
        }

     方案二:數據庫層面上進行忽略,這樣遇到重複值就會跳過,後面的數據任然可以插入,適用於對單條數據的操作要求不嚴                       格,如批量處理數據;

1.insert ignore into ...
當插入數據時,如出現錯誤時,如重複數據,將不返回錯誤,只以警告形式返回。
所以使用ignore請確保語句本身沒有問題,否則也會被忽略掉。
例如: 
INSERT IGNORE INTO table (XXX) VALUES ('xxx') 
這種方法很簡便,但是有一種可能,就是加入不是因爲重複數據報錯,而是因爲其他原因報錯的,也同樣被忽略了。

2.on duplicate key update 
當primary或者unique重複時,則執行update語句,如update後爲無用語句,如id=id,則同1功能相同,但錯誤不會被忽略掉。
例如: 
INSERT INTO table (XXX) VALUES ('xxx') ON duplicate KEY UPDATE id = id 
這種方法的前提條件,就是,需要插入的約束,需要是主鍵(primary key)或者唯一約束(unique key)。

3.insert … select … where not exist 
根據select的條件判斷是否插入,可以不光通過primary key 和unique來判斷,也可通過其它條件。
例如: 
INSERT INTO table (XXX) SELECT 'xxx' FROM dual WHERE NOT EXISTS (SELECT id FROM table WHERE id = 1) 
這種方法其實就是使用了mysql的一個臨時表的方式,但是裏面使用到了子查詢,效率也會有一點點影響,不是很推薦級。

4.replace into 
如果存在primary key or unique相同的記錄,則先刪除掉。再插入新記錄。
例如: 
REPLACE INTO table SELECT 1, 'xxx' FROM table 
這種方法就是不管原來有沒有相同的記錄,都會先刪除掉然後再插入。

      方案三:在對數據操作之前,先去數據庫查重,然後對數據操作加鎖或休眠線程等待,例如:redis 或線程sleep;不推薦,                         浪費系統性能,降低了系統的效率;

            
原因:

        mysql在批量插入數據的時候,如果有一個字段具有unique約束或是primary key ,而插入數據重複的話,就會拋出DuplicateKeyException,導致後續批量數據無法插入;

相關知識點:

      1.異常處理;

      2.數據庫操作語句;

      3.鎖機制;


代碼示例:

     如上。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章