自己写代码的时候有时候会琢磨如何写的好一点,然后某一天灵感来了就记录一下。(才入职没多久)主要是分享一下思路。
业务需求:导入的员工的Excel数据,导入以后需要和数据库里面的进行比对,以及对excel里面的数据进行一个校验,如果存在就修改,不存在就新增。
未优化的代码:(部分代码,这个不是我写的)
for (UserExcel user : userExcels) {
SpringContextUtils.getBean(StaffStandardMapper.class).selectOne(Wrappers.<StaffStandard>lambdaQuery()
.eq(StaffStandard::getPhoneNum, req.getPhoneNum())
.eq(StaffStandard::getStaffNumber, user.getStaffNumber()));
// 保存用户详情
b = standardService.saveUserDetail(staff, req, redisUser);
b = saveOrUpdateProftitles(user.getHonorName(), staff.getStaffId());
isysuserservice.update(Wrappers.<SysUser>lambdaUpdate().set(SysUser::getIsForbidden, 1).eq(SysUser::getStaffId, staff.getStaffId()));
isysuserservice.update(Wrappers.<SysUser>lambdaUpdate().set(SysUser::getIsForbidden, 0).eq(SysUser::getStaffId, staff.getStaffId()));
}
可以看到在循环里面对数据库进行多次连接操作。
下面和上面是两个业务接口
优化后的代码:
Map<String, Integer> socialAgency = socialAgencyConfigService.getSocialAgencyConfigs().stream().collect(Collectors.toMap(SocialAgencyConfig::getSocialAgencyName, SocialAgencyConfig::getSocialAgencyId));
Map<String, Integer> paymentName = paymentMethodBaseMapper.getPaymentName().stream().collect(Collectors.toMap(PaymentMethodBase::getPaymentMethodName, PaymentMethodBase::getPaymentMethodId));
List<Integer> staffIds = excels.stream().map(e -> extractIdFromStaffNumber(e.getStaffNumber())).collect(Collectors.toList());
Map<Integer, StaffStandard> staffStandardMap = staffStandardMapper.selectList(Wrappers.<StaffStandard>lambdaQuery().in(StaffStandard::getStaffId, staffIds).select(StaffStandard::getStaffId)).stream().collect(Collectors.toMap(StaffStandard::getStaffId, staffStandard -> staffStandard));
Map<Integer, StaffDetail> staffDetailMap = detailService.list(Wrappers.<StaffDetail>lambdaQuery().in(StaffDetail::getStaffId, staffIds).select(StaffDetail::getStaffId).select(StaffDetail::getPersonId)).stream().collect(Collectors.toMap(StaffDetail::getStaffId, staffDetail -> staffDetail));
主要思路:能批量处理的就一次性处理,这里我是拿到需要查询的主键一次性把后面Excel里面需要比对的数据从数据库里查出来,相当于是把数据库的数据存到JVM内存。存储为Map,以员工ID为主键,员工信息为value。主要是后面在比对的时候可以直接根据ID拿到查出来的员工信息。
然后针对校验通过的员工Excel数据,需要在数据库里修改,这里我直接把需要修改的员工信息单独存在一个集合里面,然后直接一个批量修改。代码如下;
LinkedHashSet<StaffStandard> successStaffStandards = new LinkedHashSet<>();
successStaffStandards.add(staffStandard);
this.updateBatchById(successStaffStandards);
这么做的话就不用每一次循环都去操作数据库很多次,减少了操作数据库次数。
思路分享:
1、能批量处理的尽可能批量处理,减少在循环中对数据库的操作。
2、查询时尽量只查出需要的字段,没用的字段不用查出。
3、一次性把需要的数据查出来,然后在服务层进行一个数据处理。
3、如果一次性查出来的数据太多,可能会导致内存溢出,这种情况可以进行一个分页查询,分批次进行一个处理。
如果对你有用的话点一个赞吧!