使用jpa時,調用saveAll()方法報More than one row with the given identifier was found

業務場景:

採集服務持續採集數據並放入容器中,每當容器的數量大於1000時,會將容器內的數據放入緩存容器,並清空容器,執行一次保存緩存容器的操作,保存結束後清空緩存數據。

報錯場景:

在保存這1000條緩存容器的數據時候偶爾會報More than one row with the given identifier was found...的錯誤

一般情況這個錯誤:More than one row with the given identifier was found.....都是查詢的時候發生,這次發現在保存時任然也會出現這樣的錯誤。接下來寫了一個test代碼:

@Component
public class ThreadTest2 {

    CollectDataDao collectDataDao;

    @Autowired
    public void setCollectDataDao(CollectDataDao collectDataDao) {
        this.collectDataDao = collectDataDao;
    }

    public void testSaveAll() throws  InterruptedException {
        List<CollectData> collectDataList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            CollectData collectData = new CollectData();
            collectData.setApmac("123");
            collectData.setMac("321");
            collectData.setCreatedTime(new Date());
            collectData.setDate(new Date());
            collectData.setStatus(i);
            collectDataList.add(collectData);
        }
        for (int j = 0; j < 10; j++) {
            try {
                CollectData save = collectDataDao.save(collectDataList.get(0));
                CollectData save1 = collectDataDao.save(collectDataList.get(1));
                CollectData save2 = collectDataDao.save(collectDataList.get(2));
                CollectData save3 = collectDataDao.save(collectDataList.get(0));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

當程序save3時就會報這樣的錯誤,通過debugger發現通過save方法(這裏主鍵id是自增)原對象會被填充自生成的id,當再一次被保存時就會產生上面的異常。

我們知道使用jpa時,有id的會被執行更新操作,而這裏是報錯,同過查看源碼可以看到

jpa在保存的時候會判斷是否是一個新的對象,如果是一個新的對象,並且存在id纔會執行更新操作。

結論:

jpa在保存的時候如果對同一個對象保存多次就會報More than one row with the given identifier was found的異常。

 

回到項目的問題,在批量保存的時候報的這個錯誤的原因通過分析可以知道,如果容器的數量到達1000時容器裏的數據就會放到緩存容器,原容器被清空,在保存緩存容器數據還沒保存結束,容器又達到1000,此時容器又會將數據放入緩存容器中並再保存,導致緩存容器存在2000條數據並有一些已經保存,最後造成了異常。

 

 

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