Browse Source

质检资料保存时动态扩容数据库实体表字段长度

lvy 4 weeks ago
parent
commit
cbd160f1b1

+ 55 - 0
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/ExcelTabServiceImpl.java

@@ -1233,6 +1233,9 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
                     String delSql = "delete from " + tabName + " where p_key_id=" + tableInfo.getPkeyId();
                     String sqlInfo = "";
                     LinkedHashMap<String, String> dataMap2 = tableInfo.getDataMap();
+                    if (!updateFieldLength(tabName, dataMap2)) {
+                        throw new ServiceException("字段长度超出限制, 系统无法进行自增,请前往后台管理系统手动设置");
+                    }
                     /*检查发现有p_key_id缺失的情况,导致表单数据丢失,所以强制覆盖*/
                     dataMap2.put("p_key_id", tableInfo.getPkeyId());
                     //统计保存的字段
@@ -1343,6 +1346,58 @@ public class ExcelTabServiceImpl extends BaseServiceImpl<ExcelTabMapper, ExcelTa
        // return R.success(fileName1);
     }
 
+    public boolean updateFieldLength(String tableName, Map<String, String> fieldNameAndLengthMap) {
+        if (fieldNameAndLengthMap == null || fieldNameAndLengthMap.isEmpty()) {
+            return true;
+        }
+        fieldNameAndLengthMap.remove("id");
+        fieldNameAndLengthMap.remove("p_key_id");
+        fieldNameAndLengthMap.remove("group_id");
+        if (fieldNameAndLengthMap.isEmpty()) {
+            return true;
+        }
+        String fields = fieldNameAndLengthMap.keySet().stream().map(key -> "'" + key + "'").collect(Collectors.joining(","));
+        List<Map<String, Object>> fieldMap = jdbcTemplate.queryForList("select distinct COLUMN_NAME as fieldName, CHARACTER_MAXIMUM_LENGTH as fieldLength from information_schema.COLUMNS where  TABLE_NAME = '" + tableName +
+                "' and COLUMN_NAME in (" + fields + ")");
+        Map<String, Integer> map = fieldMap.stream().collect(toMap(k -> k.get("fieldName") + "", v -> {
+            if (v.get("fieldLength") == null) {
+                return 0;
+            }
+            return Integer.parseInt(v.get("fieldLength") + "");
+        }, Math::max));
+
+        List<WbsFormElement> elementList = jdbcTemplate.query("SELECT id,e_key,e_length from m_wbs_form_element WHERE f_id = (SELECT id from m_table_info WHERE tab_en_name = '" + tableName
+                        +"' and is_deleted = 0  limit 1) and is_deleted = 0 and e_key in ( " +  fields + ")", new BeanPropertyRowMapper<>(WbsFormElement.class));
+        StringBuilder sql = new StringBuilder();
+        sql.append("alter table ").append(tableName);
+        elementList.forEach(element -> {
+            String data = fieldNameAndLengthMap.get(element.getEKey());
+            if (data != null && element.getELength() != null && data.length() > element.getELength()) {
+                int length = data.length();
+                // 取整
+                length = (length / 10 + 1) * 10;
+                Integer fieldLength = map.get(element.getEKey());
+                if (fieldLength != null && fieldLength < element.getELength()) {
+                    element.setELength(length);
+                    sql.append(" modify column ").append(element.getEKey()).append(" ").append("varchar").append("(").append(length).append("),");
+                }
+            }
+        });
+        if (sql.indexOf("modify") > 0) {
+            TransactionStatus transactionStatus = this.beginTransaction(transactionManager1);
+            try {
+                jdbcTemplate.batchUpdate("update m_wbs_form_element set e_length = ? where id = ?", elementList.stream().map(element -> new Object[]{element.getELength(), element.getId()}).collect(Collectors.toList()));
+                jdbcTemplate.execute(sql.toString());
+                transactionManager1.commit(transactionStatus);
+            } catch (Exception e) {
+                transactionManager1.rollback(transactionStatus);
+                log.error("更新字段长度失败, error: " + e.getMessage());
+                return false;
+            }
+        }
+        return true;
+    }
+
     public String reason(String log) {
         /*保存的时候错误提示例如:字段过短提示 yangyj*/
         StringBuilder sb = new StringBuilder();

+ 128 - 56
blade-service/blade-manager/src/main/java/org/springblade/manager/service/impl/WbsFormElementServiceImpl.java

@@ -62,6 +62,8 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
     public static final Integer DEFAULT_ELEMENT_LENGTH_DATE = 100;
     //实体表字段默认长度
     private static final String ELEMENT_LENGTH_ENTITY = "200";
+    //数据库动态表总字段最大长度
+    private static final Integer MYSQL_MAX_COLUMN_LENGTH = 16328;
 
     @Override
     public IPage<WbsFormElementVO> selectWbsFormElementPage(IPage<WbsFormElementVO> page, WbsFormElementVO wbsFormElement) {
@@ -141,23 +143,30 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
 
     @Override
     public WbsFormElement saveAndSyn(WbsFormElement wbsFormElement, String tableName) {
-        try {
 
-            String isExitSql = "select * from information_schema.TABLES where TABLE_NAME='" + tableName + "'";
-            List<Map<String, Object>> tabList = jdbcTemplate.queryForList(isExitSql);
-            if (tabList.size() <= 0) {
-                throw new ServiceException("未获取到对应的实体表名称initTableName");
-            }
+        String isExitSql = "select * from information_schema.TABLES where TABLE_NAME='" + tableName + "'";
+        List<Map<String, Object>> tabList = jdbcTemplate.queryForList(isExitSql);
+        if (tabList.size() <= 0) {
+            throw new ServiceException("未获取到对应的实体表名称initTableName");
+        }
 
 
-            //获取实体表主库信息
-            TableInfo tableInfo = tableInfoMapper.selectById(wbsFormElement.getFId());
-            if (tableInfo == null) {
-                throw new ServiceException("没有找到主库信息,确认fid是否正确");
-            } else {
-                tableName = tableInfo.getTabEnName();
-            }
+        //获取实体表主库信息
+        TableInfo tableInfo = tableInfoMapper.selectById(wbsFormElement.getFId());
+        if (tableInfo == null) {
+            throw new ServiceException("没有找到主库信息,确认fid是否正确");
+        } else {
+            tableName = tableInfo.getTabEnName();
+        }
+
 
+        //当前表总字段长度
+        int sumLength = baseMapper.selectSumColumnLength(jdbcTemplate.queryForObject("SELECT DATABASE()", String.class), tableName);
+        if (sumLength + wbsFormElement.getELength() > MYSQL_MAX_COLUMN_LENGTH) {
+            updateTableFieldLength(tableName);
+            throw new ServiceException("无法添加字段,可用长度:" + (MYSQL_MAX_COLUMN_LENGTH - sumLength) + ",已自动调整其他字段长度,请重新添加");
+        }
+        try {
             // 删除 元素和实体表不匹配的字段
             //baseMapper.deleteElementByfId2();
 
@@ -193,6 +202,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                     throw new ServiceException("请输入正确的长度,范围为10-1000");
                 } else {
                     //新增
+                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
                     baseMapper.insert(wbsFormElement);
 
                     //同步
@@ -209,6 +219,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                     throw new ServiceException("请输入正确的长度,范围为10-255");
                 } else {
                     //新增
+                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
                     baseMapper.insert(wbsFormElement);
 
                     //同步
@@ -240,6 +251,7 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                     throw new ServiceException("请输入正确的长度,范围为0-100");
                 } else {
                     //新增
+                    wbsFormElement.setELength(DEFAULT_ELEMENT_LENGTH_VARCHAR);
                     baseMapper.insert(wbsFormElement);
 
                     //同步
@@ -305,19 +317,21 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
         wbsFormElementList.forEach(obj -> obj.setStatus(1));
         boolean b = this.updateBatchById(wbsFormElementList);
 
-        //字段级字段长度缓存
-        Map<String, Integer> lengthMap = new HashMap<>();
 
-        //查询当前表的所有字段级字段长度
-        List<Map<String, Object>> filedLengths = baseMapper.selectFiledLength(initTableName);
-        for (Map<String, Object> filedLength : filedLengths) {
-            BigInteger length = (BigInteger) filedLength.get("length");
-            if (length == null) {
-                continue;
-            }
-            lengthMap.put(filedLength.get("key").toString(), length.intValue());
+        //当前设置的字段总长度
+        Integer nowTotalLength = 0;
+        for (WbsFormElement wbsFormElement : wbsFormElementList) {
+            // + 10 预留字段长度,用来保存在excel中的位置信息,比如:xx_^_12_12, 不适合一个字段存储多个位置
+            nowTotalLength += wbsFormElement.getELength() + 10;
+        }
+        //当前表总字段长度
+        int sumLength = baseMapper.selectSumColumnLength(jdbcTemplate.queryForObject("SELECT DATABASE()", String.class), initTableName);
+        if (nowTotalLength > MYSQL_MAX_COLUMN_LENGTH) {
+            //修改元素字段长度
+            throw new ServiceException("无法添加字段,可用长度:" + (MYSQL_MAX_COLUMN_LENGTH - sumLength));
         }
 
+
         //修改实体表信息
         if (b) {
             String fId = "";
@@ -361,40 +375,14 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
                 int row1 = wbsTreeMapper.isThereAField(initTableName, eKey);
                 if (row1 > 0) {
                     try {
-                        //1、查询当前表当前字段
-
-                        //字段配置的长度
-                        Integer filedLength = lengthMap.get(eKey);
-                        if(filedLength == null){
-                            throw new RuntimeException("字段不存在");
-                        }
-                        //获取当前字段数据的最长数据长度
-                        Integer maxLength = baseMapper.selectFiledDataMaxLength(initTableName, eKey);
-                        //初始长度
-                        int initLength = 250;
-                        //当前字段数据长度为null
-                        if (maxLength == null) {
-                            //设置初始长度
-                            baseMapper.updateFiledType(initTableName, eKey, "varchar", initLength);
-                            wbsFormElement.setELength(initLength);
-                            baseMapper.updateById(wbsFormElement);
-                        } else {
-                            //动态扩容 每次根据最大数据长度扩容100
-                            int newLength = maxLength + 100;
-                            //如果字段的长度与扩容后的值一致则不去修改字段
-                            if (filedLength == newLength) {
-                                continue;
-                            }
-                            //如果数据的最大长度 +100 都大于字段配置的长度  则重新设置字段的长度
-                            if (filedLength >= newLength) {
-                                baseMapper.updateFiledType(initTableName, eKey, "varchar", newLength);
-                                wbsFormElement.setELength(newLength);
-                                baseMapper.updateById(wbsFormElement);
-                                continue;
-                            }
-                            baseMapper.updateFiledType(initTableName, eKey, "varchar", eLength);
-                        }
+                        // + 10 预留字段长度,用来保存在excel中的位置信息,比如:xx_^_12_12, 不适合一个字段存储多个位置
+                        baseMapper.updateFiledType(initTableName, eKey, "varchar", eLength + 10);
                     } catch (Exception e) {
+                        // 数据库字段长度大于修改长度,则忽略
+                        if (e.getMessage().contains("Data truncated for column '" + eKey + "' at row 1")) {
+                            continue;
+                        }
+                        e.printStackTrace();
                         this.updateBatchById(beforeUpdateWbsFormElements);
                         throw new RuntimeException("字段长度范围超出总最大限制,请尝试缩小当前字段长度或其他字段长度");
                     }
@@ -965,4 +953,88 @@ public class WbsFormElementServiceImpl extends BaseServiceImpl<WbsFormElementMap
         }
     }
 
+
+    /**
+     * 修改当前表所有字段的长度 (只用于字段缩减)
+     * 1、字段数量超过80 表数据超过500条 把数据长度为0的旧字段长度改为50
+     * 超过:新字段的默认长度改为150,并且
+     */
+    public void updateTableFieldLength(String tableName) {
+        TableInfo tableInfo = tableInfoMapper.selectOne(Wrappers.<TableInfo>lambdaQuery()
+                .eq(TableInfo::getTabEnName, tableName)
+                .last("limit 1"));
+
+        List<WbsFormElement> wbsFormElements = baseMapper.selectList(Wrappers.<WbsFormElement>lambdaQuery()
+                .eq(WbsFormElement::getFId, tableInfo.getId()));
+        //元素是否存在
+        if (CollectionUtil.isEmpty(wbsFormElements)) {
+            return;
+        }
+        //字段级字段长度缓存
+        Map<String, Integer> lengthMap = new HashMap<>();
+        //查询当前表的所有字段级字段长度
+        List<Map<String, Object>> filedLengths = baseMapper.selectFiledLength(tableName);
+        //表是否存在
+        if (CollectionUtil.isEmpty(filedLengths)) {
+            return;
+        }
+        for (Map<String, Object> filedLength : filedLengths) {
+            BigInteger length = (BigInteger) filedLength.get("length");
+            if (length == null) {
+                continue;
+            }
+            //记录字段与字段长度
+            lengthMap.put(filedLength.get("key").toString(), length.intValue());
+        }
+
+        //这张表是否拥有数据超过500条
+        Integer count = jdbcTemplate.queryForObject("select count(0) from " + tableName, Integer.class);
+
+
+        for (WbsFormElement wbsFormElement : wbsFormElements) {
+
+            String eKey = wbsFormElement.getEKey();
+            //字段不存在
+            if (lengthMap.get(eKey) == null) {
+                continue;
+            }
+            Integer dataLength = baseMapper.selectFiledDataMaxLength(tableName, eKey);
+
+            if (wbsFormElements.size() > 80 && count > 500) {
+                //数据长度
+                dataLength = dataLength == 0 ? 50 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+            } else if (wbsFormElements.size() > 80 && count < 500) {
+                //数据长度
+                dataLength = dataLength == 0 ? 100 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+            } else if (wbsFormElements.size() < 80 && count > 500) {
+                //数据长度
+                dataLength = dataLength == 0 ? 200 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+            } else {
+                //数据长度
+                dataLength = dataLength == 0 ? 200 : lengthMap.get(eKey) + 100;
+                //如果当前需要设置的长度大于当前字段长度,则跳过
+                if (dataLength > wbsFormElement.getELength()) {
+                    continue;
+                }
+                if (dataLength < 200) {
+                    dataLength = 200;
+                }
+            }
+            baseMapper.updateFiledType(tableName, eKey, "varchar", dataLength);
+            wbsFormElement.setELength(dataLength);
+            baseMapper.updateById(wbsFormElement);
+        }
+    }
 }