表格文件导入-进度展示和速度优化

时间 2021/6/18 16:28:17 加载中...

表格文件导入

进度展示

进度展示设计效果视频:

背景:

由于导入的表格文件内容特别的多,所以导入之后后台一直在处理,浏览器等待一段时间就会提示 504,其实是接口没有即可返回的原因。

办法:

文件上传之后,接口立刻返回,提示后台在处理。
文件的处理单独一个线程去处理。处理过程与结果通过 WebSocket 显示到页面上。

使用的技术:

WebSocket

导入优化

业务说明:

导入的目的是建立【分类】和【标准】的映射关系。
所以导入的表格信息有【分类名称】,【标准名称,标准体系,标准表】
【标准名称,标准体系,标准表】这属于一条标准信息的多个字段。
在导入的时候要先保证【分类名称】和【标准名称】已经在库中存在。

最初的导入方案:

导入的表格文件,会对表格每行内容进行校验,校验逻辑就是看数据在数据库中是否已经存在,且要保证唯一,不能没有,也不能有多个。且要查出在数据库中的整条记录,因为后面的逻辑要用到。

这里导入慢的一个主要原因就是在校验的时候是遍历查询数据库的。所以会很慢。

图:
导入方案一

修改成批量处理后的方案:

主要是对校验环节的遍历查询数据库,修改为批量查询数据库。
以及遍历插入数据库,修改为批量插入数据库。

图:
导入方案二

代码

主要代码就是批量查询的代码 和 批量插入的代码

批量查询的业务代码

  1. @Override
  2. public List<ClassStandard> getByNameAndClassCodeBatch(HashSet<List<Object>> checkClassfiyList) throws Exception {
  3. String sql = "select ID,ClassName,ParentID,ClassCode,ForceInfo from nv_class_standard where status = 1\n" +
  4. "and ClassName = ? and OrganizationID = ? and classCode like ?";
  5. return dataContext.excuteQueryBatch(sql, checkClassfiyList, ClassStandard.class, 10000, DataConfigEnum.MySql);
  6. }

后台数据库访问分批查询

  1. public <T> List<T> excuteQueryBatch(String sql, Collection<List<Object>> paramsList, Class<T> type, int batchNumber, DataConfigEnum config) throws Exception {
  2. List<T> result = new ArrayList<>();
  3. List<String> sqlBuilder = new ArrayList<>();
  4. List<Object> paraList = new ArrayList<>();
  5. int i = 0;
  6. for (List<Object> item : paramsList) {
  7. sqlBuilder.add(sql);
  8. paraList.addAll(item);
  9. if ((i + 1) % batchNumber == 0) {
  10. String theSql = String.join(" union ", sqlBuilder);
  11. result.addAll(this.excuteQuery(theSql, paraList.toArray(), type, config));
  12. sqlBuilder.clear();
  13. paraList.clear();
  14. }
  15. i++;
  16. }
  17. if (sqlBuilder.size() > 0 && paraList.size() > 0) {
  18. String theSql = String.join(" union ", sqlBuilder);
  19. result.addAll(this.excuteQuery(theSql, paraList.toArray(), type, config));
  20. }
  21. return result;
  22. }

分批保存的业务代码

  1. for (List<String> item : rowValList) {
  2. // 只有数量是 7 的才是校验通过的数据
  3. if (item.size() == 7) {
  4. Integer classId = Integer.parseInt(item.get(4));
  5. String classCode = item.get(5);
  6. Integer normalValueId = Integer.parseInt(item.get(6));
  7. paraList.add(Arrays.asList(new Object[]{classId, classCode, normalValueId, loginUserCode, classId, normalValueId}));
  8. paraIdList.add(Arrays.asList(normalValueId));
  9. if (paraList.size() >= 2000) {
  10. myWebSocketMsger.showMsg("数据保存到数据库:共" + paraIdList.size() + "条");
  11. classValueRelationService.addClassValueRelationBatch(paraList, paraIdList);
  12. myWebSocketMsger.showMsg("数据保存到数据库【完成】");
  13. paraList.clear();
  14. paraIdList.clear();
  15. }
  16. }
  17. }
  18. if (paraList.size() > 0) {
  19. myWebSocketMsger.showMsg("数据保存到数据库:共" + paraIdList.size() + "条");
  20. classValueRelationService.addClassValueRelationBatch(paraList, paraIdList);
  21. myWebSocketMsger.showMsg("数据保存到数据库【完成】");
  22. } else {
  23. myWebSocketMsger.showMsg("没有校验通过的数据,保存了0条");
  24. }
  1. String sql = "insert into nv_class_value_relation (ClassId, ClassCode, ValueId, CreateUser, CreateTime)\n" +
  2. " select ?,?,?,?,now() from DUAL " +
  3. " where not exists ( select * from nv_class_value_relation where classId = ? and valueId = ? and status = 1)";
  4. dataContext.executeSqlBatch(sql, paraList, DataConfigEnum.MySql);
  1. public void executeSqlBatch(String sql, List<List<Object>> paramsList, DataConfigEnum config) throws SQLException {
  2. Connection connection = null;
  3. try {
  4. connection = getInstance(config).getConnection();
  5. connection.setAutoCommit(false);
  6. PreparedStatement statement = connection.prepareStatement(sql);
  7. statement.clearBatch();
  8. if (paramsList != null) {
  9. for (int i = 0; i < paramsList.size(); i++) {
  10. List<Object> params = paramsList.get(i);
  11. if (params != null) {
  12. for (int j = 0; j < params.size(); j++) {
  13. statement.setObject(j + 1, params.get(j));
  14. }
  15. statement.addBatch();
  16. }
  17. }
  18. }
  19. statement.executeBatch();
  20. connection.commit();
  21. connection.setAutoCommit(true);
  22. } finally {
  23. if (connection != null && !connection.isClosed()) {
  24. connection.close();
  25. }
  26. }
  27. }
扫码分享
版权说明
作者:SQBER
文章来源:http://www.sqber.com/articles/table-data-import-improve.html
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。