使用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条数据并有一些已经保存,最后造成了异常。

 

 

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