feat: 导入功能改为批量插入和批量更新

## 修改内容

### Mapper 接口
- CcdiBizIntermediaryMapper: 新增 insertBatch() 和 updateBatch() 方法
- CcdiEnterpriseBaseInfoMapper: 新增 insertBatch() 和 updateBatch() 方法

### Mapper XML
- 新增 CcdiBizIntermediaryMapper.xml: 实现个人中介的批量插入和更新
- 新增 CcdiEnterpriseBaseInfoMapper.xml: 实现实体中介的批量插入和更新
  - 批量插入使用 VALUES (...), (...), (...) 语法
  - 批量更新使用 foreach 分隔多条 UPDATE 语句

### Service 实现
- importIntermediaryPerson(): 改为两轮处理模式
  - 第一轮:数据验证和分类(区分插入和更新)
  - 第二轮:批量插入新记录 + 批量更新已存在记录

- importIntermediaryEntity(): 改为两轮处理模式
  - 第一轮:数据验证和分类(区分插入和更新)
  - 第二轮:批量插入新记录 + 批量更新已存在记录

## 性能优化
- 从原来的逐条插入/更新改为批量操作
- 减少数据库连接次数,提升大数据量导入性能
- 事务一致性保证,全部成功或全部回滚

编译验证:通过
This commit is contained in:
wkc
2026-02-04 19:52:29 +08:00
parent cca2e620b5
commit 1af2677c05
5 changed files with 238 additions and 22 deletions

View File

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ccdi.domain.CcdiBizIntermediary;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 个人中介Mapper接口
*
@@ -13,4 +15,19 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CcdiBizIntermediaryMapper extends BaseMapper<CcdiBizIntermediary> {
/**
* 批量插入个人中介
*
* @param list 个人中介列表
* @return 插入行数
*/
int insertBatch(List<CcdiBizIntermediary> list);
/**
* 批量更新个人中介
*
* @param list 个人中介列表
* @return 更新行数
*/
int updateBatch(List<CcdiBizIntermediary> list);
}

View File

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.ccdi.domain.CcdiEnterpriseBaseInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 实体中介Mapper接口
*
@@ -13,4 +15,19 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface CcdiEnterpriseBaseInfoMapper extends BaseMapper<CcdiEnterpriseBaseInfo> {
/**
* 批量插入实体中介
*
* @param list 实体中介列表
* @return 插入行数
*/
int insertBatch(List<CcdiEnterpriseBaseInfo> list);
/**
* 批量更新实体中介
*
* @param list 实体中介列表
* @return 更新行数
*/
int updateBatch(List<CcdiEnterpriseBaseInfo> list);
}

View File

@@ -285,7 +285,7 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
}
/**
* 导入个人中介数据
* 导入个人中介数据(批量操作)
*
* @param list Excel实体列表
* @param updateSupport 是否更新支持
@@ -303,8 +303,16 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder();
for (CcdiIntermediaryPersonExcel excel : list) {
// 待插入和更新的列表
List<CcdiBizIntermediary> insertList = new ArrayList<>();
List<CcdiBizIntermediary> updateList = new ArrayList<>();
List<String> personIds = new ArrayList<>();
// 第一轮:数据验证和分类
for (int i = 0; i < list.size(); i++) {
try {
CcdiIntermediaryPersonExcel excel = list.get(i);
// 验证数据
if (StringUtils.isEmpty(excel.getName())) {
throw new RuntimeException("姓名不能为空");
@@ -319,29 +327,26 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
person.setPersonType("中介");
person.setDataSource("IMPORT");
personIds.add(excel.getPersonId());
// 检查唯一性
if (!checkPersonIdUnique(excel.getPersonId(), null)) {
if (updateSupport) {
// 更新模式:查询已存在记录并更新
LambdaQueryWrapper<CcdiBizIntermediary> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(CcdiBizIntermediary::getPersonId, excel.getPersonId());
CcdiBizIntermediary existingPerson = bizIntermediaryMapper.selectOne(wrapper);
if (existingPerson != null) {
person.setBizId(existingPerson.getBizId());
bizIntermediaryMapper.updateById(person);
}
// 需要更新,暂时加入更新列表
updateList.add(person);
} else {
throw new RuntimeException("该证件号已存在");
}
} else {
bizIntermediaryMapper.insert(person);
// 新数据,加入插入列表
insertList.add(person);
}
successNum++;
successMsg.append("<br/>").append(successNum).append("").append(excel.getName()).append(" 导入成功");
} catch (Exception e) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("").append(excel.getName()).append(" 导入失败:");
failureMsg.append("<br/>").append(failureNum).append("").append(list.get(i).getName()).append(" 导入失败:");
failureMsg.append(e.getMessage());
}
}
@@ -349,14 +354,49 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
if (failureNum > 0) {
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new RuntimeException(failureMsg.toString());
} else {
}
// 第二轮:批量处理
try {
// 批量插入新记录
if (!insertList.isEmpty()) {
bizIntermediaryMapper.insertBatch(insertList);
}
// 批量更新已存在的记录
if (!updateList.isEmpty()) {
// 查询已存在记录的bizId
LambdaQueryWrapper<CcdiBizIntermediary> wrapper = new LambdaQueryWrapper<>();
wrapper.in(CcdiBizIntermediary::getPersonId, personIds);
List<CcdiBizIntermediary> existingList = bizIntermediaryMapper.selectList(wrapper);
// 建立personId到bizId的映射
java.util.Map<String, String> personIdToBizIdMap = new java.util.HashMap<>();
for (CcdiBizIntermediary existing : existingList) {
personIdToBizIdMap.put(existing.getPersonId(), existing.getBizId());
}
// 设置bizId到更新列表
for (CcdiBizIntermediary person : updateList) {
String bizId = personIdToBizIdMap.get(person.getPersonId());
if (bizId != null) {
person.setBizId(bizId);
}
}
// 批量更新
bizIntermediaryMapper.updateBatch(updateList);
}
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + "");
return successMsg.toString();
} catch (Exception e) {
throw new RuntimeException("批量操作失败:" + e.getMessage());
}
}
/**
* 导入实体中介数据
* 导入实体中介数据(批量操作)
*
* @param list Excel实体列表
* @param updateSupport 是否更新支持
@@ -374,8 +414,16 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
StringBuilder successMsg = new StringBuilder();
StringBuilder failureMsg = new StringBuilder();
for (CcdiIntermediaryEntityExcel excel : list) {
// 待插入和更新的列表
List<CcdiEnterpriseBaseInfo> insertList = new ArrayList<>();
List<CcdiEnterpriseBaseInfo> updateList = new ArrayList<>();
List<String> socialCreditCodes = new ArrayList<>();
// 第一轮:数据验证和分类
for (int i = 0; i < list.size(); i++) {
try {
CcdiIntermediaryEntityExcel excel = list.get(i);
// 验证数据
if (StringUtils.isEmpty(excel.getEnterpriseName())) {
throw new RuntimeException("机构名称不能为空");
@@ -390,26 +438,29 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
// 检查唯一性
if (StringUtils.isNotEmpty(excel.getSocialCreditCode())) {
socialCreditCodes.add(excel.getSocialCreditCode());
if (!checkSocialCreditCodeUnique(excel.getSocialCreditCode(), null)) {
if (updateSupport) {
// 更新模式
enterpriseBaseInfoMapper.updateById(entity);
// 需要更新,加入更新列表
updateList.add(entity);
} else {
throw new RuntimeException("该统一社会信用代码已存在");
}
} else {
enterpriseBaseInfoMapper.insert(entity);
// 新数据,加入插入列表
insertList.add(entity);
}
} else {
// 没有统一社会信用代码,直接插入
enterpriseBaseInfoMapper.insert(entity);
// 没有统一社会信用代码,直接加入插入列表
insertList.add(entity);
}
successNum++;
successMsg.append("<br/>").append(successNum).append("").append(excel.getEnterpriseName()).append(" 导入成功");
} catch (Exception e) {
failureNum++;
failureMsg.append("<br/>").append(failureNum).append("").append(excel.getEnterpriseName()).append(" 导入失败:");
failureMsg.append("<br/>").append(failureNum).append("").append(list.get(i).getEnterpriseName()).append(" 导入失败:");
failureMsg.append(e.getMessage());
}
}
@@ -417,9 +468,25 @@ public class CcdiIntermediaryServiceImpl implements ICcdiIntermediaryService {
if (failureNum > 0) {
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
throw new RuntimeException(failureMsg.toString());
} else {
}
// 第二轮:批量处理
try {
// 批量插入新记录
if (!insertList.isEmpty()) {
enterpriseBaseInfoMapper.insertBatch(insertList);
}
// 批量更新已存在的记录
if (!updateList.isEmpty()) {
// 批量更新socialCreditCode已在实体中
enterpriseBaseInfoMapper.updateBatch(updateList);
}
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + "");
return successMsg.toString();
} catch (Exception e) {
throw new RuntimeException("批量操作失败:" + e.getMessage());
}
}
}