表格文件导入-进度展示和速度优化
2021/6/18 16:28:17
表格文件导入
进度展示
进度展示设计效果视频:
背景:
由于导入的表格文件内容特别的多,所以导入之后后台一直在处理,浏览器等待一段时间就会提示 504,其实是接口没有即可返回的原因。
办法:
文件上传之后,接口立刻返回,提示后台在处理。
文件的处理单独一个线程去处理。处理过程与结果通过 WebSocket 显示到页面上。
使用的技术:
WebSocket
导入优化
业务说明:
导入的目的是建立【分类】和【标准】的映射关系。
所以导入的表格信息有【分类名称】,【标准名称,标准体系,标准表】
【标准名称,标准体系,标准表】这属于一条标准信息的多个字段。
在导入的时候要先保证【分类名称】和【标准名称】已经在库中存在。
最初的导入方案:
导入的表格文件,会对表格每行内容进行校验,校验逻辑就是看数据在数据库中是否已经存在,且要保证唯一,不能没有,也不能有多个。且要查出在数据库中的整条记录,因为后面的逻辑要用到。
这里导入慢的一个主要原因就是在校验的时候是遍历查询数据库的。所以会很慢。
图:
修改成批量处理后的方案:
主要是对校验环节的遍历查询数据库,修改为批量查询数据库。
以及遍历插入数据库,修改为批量插入数据库。
图:
代码
主要代码就是批量查询的代码 和 批量插入的代码
批量查询的业务代码
@Override
public List<ClassStandard> getByNameAndClassCodeBatch(HashSet<List<Object>> checkClassfiyList) throws Exception {
String sql = "select ID,ClassName,ParentID,ClassCode,ForceInfo from nv_class_standard where status = 1\n" +
"and ClassName = ? and OrganizationID = ? and classCode like ?";
return dataContext.excuteQueryBatch(sql, checkClassfiyList, ClassStandard.class, 10000, DataConfigEnum.MySql);
}
后台数据库访问分批查询
public <T> List<T> excuteQueryBatch(String sql, Collection<List<Object>> paramsList, Class<T> type, int batchNumber, DataConfigEnum config) throws Exception {
List<T> result = new ArrayList<>();
List<String> sqlBuilder = new ArrayList<>();
List<Object> paraList = new ArrayList<>();
int i = 0;
for (List<Object> item : paramsList) {
sqlBuilder.add(sql);
paraList.addAll(item);
if ((i + 1) % batchNumber == 0) {
String theSql = String.join(" union ", sqlBuilder);
result.addAll(this.excuteQuery(theSql, paraList.toArray(), type, config));
sqlBuilder.clear();
paraList.clear();
}
i++;
}
if (sqlBuilder.size() > 0 && paraList.size() > 0) {
String theSql = String.join(" union ", sqlBuilder);
result.addAll(this.excuteQuery(theSql, paraList.toArray(), type, config));
}
return result;
}
分批保存的业务代码
for (List<String> item : rowValList) {
// 只有数量是 7 的才是校验通过的数据
if (item.size() == 7) {
Integer classId = Integer.parseInt(item.get(4));
String classCode = item.get(5);
Integer normalValueId = Integer.parseInt(item.get(6));
paraList.add(Arrays.asList(new Object[]{classId, classCode, normalValueId, loginUserCode, classId, normalValueId}));
paraIdList.add(Arrays.asList(normalValueId));
if (paraList.size() >= 2000) {
myWebSocketMsger.showMsg("数据保存到数据库:共" + paraIdList.size() + "条");
classValueRelationService.addClassValueRelationBatch(paraList, paraIdList);
myWebSocketMsger.showMsg("数据保存到数据库【完成】");
paraList.clear();
paraIdList.clear();
}
}
}
if (paraList.size() > 0) {
myWebSocketMsger.showMsg("数据保存到数据库:共" + paraIdList.size() + "条");
classValueRelationService.addClassValueRelationBatch(paraList, paraIdList);
myWebSocketMsger.showMsg("数据保存到数据库【完成】");
} else {
myWebSocketMsger.showMsg("没有校验通过的数据,保存了0条");
}
String sql = "insert into nv_class_value_relation (ClassId, ClassCode, ValueId, CreateUser, CreateTime)\n" +
" select ?,?,?,?,now() from DUAL " +
" where not exists ( select * from nv_class_value_relation where classId = ? and valueId = ? and status = 1)";
dataContext.executeSqlBatch(sql, paraList, DataConfigEnum.MySql);
public void executeSqlBatch(String sql, List<List<Object>> paramsList, DataConfigEnum config) throws SQLException {
Connection connection = null;
try {
connection = getInstance(config).getConnection();
connection.setAutoCommit(false);
PreparedStatement statement = connection.prepareStatement(sql);
statement.clearBatch();
if (paramsList != null) {
for (int i = 0; i < paramsList.size(); i++) {
List<Object> params = paramsList.get(i);
if (params != null) {
for (int j = 0; j < params.size(); j++) {
statement.setObject(j + 1, params.get(j));
}
statement.addBatch();
}
}
}
statement.executeBatch();
connection.commit();
connection.setAutoCommit(true);
} finally {
if (connection != null && !connection.isClosed()) {
connection.close();
}
}
}
扫码分享
版权说明
作者:SQBER
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
{0}
{5}
{1}
{2}回复
{4}
*昵称:
*邮箱:
个人站点:
*想说的话: