fix(测试跟踪): 功能用例批量编辑性能优化

--bug=1014258 --user=陈建星 【测试跟踪】功能列表用例条数过多时,批量编辑接口性能需要优化 {#_orginal_url#}
This commit is contained in:
chenjianxing 2022-06-27 15:59:19 +08:00 committed by jianxing
parent e050476c7c
commit d18ed3d200
7 changed files with 120 additions and 25 deletions

View File

@ -1,6 +1,7 @@
package io.metersphere.base.mapper.ext;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.dto.CustomFieldResourceDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -20,4 +21,8 @@ public interface ExtCustomFieldResourceMapper {
List<CustomFieldResource> getByResourceIds(@Param("tableName") String tableName, @Param("resourceIds") List<String> resourceIds);
long countFieldResource(@Param("tableName") String tableName, @Param("resourceId") String resourceId, @Param("fieldId") String field_id);
int batchUpdateByResourceIds(@Param("tableName") String tableName, @Param("resourceIds") List<String> resourceIds, @Param("record") CustomFieldResourceDTO customField);
void batchInsertIfNotExists(@Param("tableName") String tableName, @Param("record") CustomFieldResourceDTO customField);
}

View File

@ -10,6 +10,12 @@
</insert>
<update id="updateByPrimaryKeySelective">
update ${tableName}
<include refid="updateValueColumn"/>
where resource_id = #{record.resourceId,jdbcType=VARCHAR}
and field_id = #{record.fieldId,jdbcType=VARCHAR}
</update>
<sql id="updateValueColumn">
<set>
<if test="record.value != null">
`value` = #{record.value,jdbcType=VARCHAR},
@ -18,8 +24,28 @@
text_value = #{record.textValue,jdbcType=LONGVARCHAR},
</if>
</set>
where resource_id = #{record.resourceId,jdbcType=VARCHAR}
and field_id = #{record.fieldId,jdbcType=VARCHAR}
</sql>
<update id="batchUpdateByResourceIds">
update ${tableName}
<include refid="updateValueColumn"/>
where resource_id in
<foreach collection="resourceIds" item="resourceId" separator="," open="(" close=")">
#{resourceId}
</foreach>
</update>
<update id="batchInsertIfNotExists">
INSERT INTO ${tableName} (resource_id, field_id, `value`, text_value)
SELECT
'${record.resourceId}',
'${record.fieldId}',
'${record.value}',
'${record.textValue}'
FROM DUAL
WHERE NOT EXISTS(
select resource_id
from ${tableName}
where resource_id = #{record.resourceId} and field_id = #{record.fieldId}
)
</update>
<delete id="deleteByResourceId">
delete from ${tableName}

View File

@ -21,10 +21,7 @@ import org.mybatis.spring.SqlSessionUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.*;
import java.util.stream.Collectors;
public class ServiceUtils {
@ -302,6 +299,26 @@ public class ServiceUtils {
return sqlSessionFactory.openSession(ExecutorType.BATCH);
}
/**
* 批量操作
*/
public static void batchOperate(List data, int batchSize, Class mapperClazz, BiConsumer operateFunc) {
if (CollectionUtils.isEmpty(data)) {
return;
}
SqlSessionFactory sqlSessionFactory = CommonBeanFactory.getBean(SqlSessionFactory.class);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
Object mapper = sqlSession.getMapper(mapperClazz);
for (int i = 0; i < data.size(); i++) {
operateFunc.accept(data.get(i), mapper);
if (i % batchSize == 0) {
sqlSession.flushStatements();
}
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
public static String getCopyName(String name) {
return "copy_" + name + "_" + UUID.randomUUID().toString().substring(0, 4);
}

View File

@ -0,0 +1,26 @@
package io.metersphere.commons.utils;
import java.util.List;
import java.util.function.Consumer;
public class SubListUtil {
/**
* 将较长的数组截断成较短的数组进行批处理
*/
public static void dealForSubList(List totalList, Integer batchSize, Consumer<List> subFunc) {
int count = totalList.size();
int iteratorCount = count / batchSize;
for (int i = 0; i <= iteratorCount; i++) {
int endIndex, startIndex;
startIndex = i * batchSize;
endIndex = ((endIndex = (i + 1) * batchSize) > count) ? count : endIndex;
if (endIndex == startIndex) {
break;
}
List subList = totalList.subList(startIndex, endIndex);
subFunc.accept(subList);
}
}
}

View File

@ -15,9 +15,11 @@ import io.metersphere.commons.constants.TemplateConstants;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.ServiceUtils;
import io.metersphere.commons.utils.SubListUtil;
import io.metersphere.controller.request.customfield.CustomFieldResourceRequest;
import io.metersphere.dto.CustomFieldDao;
import io.metersphere.dto.CustomFieldItemDTO;
import io.metersphere.dto.CustomFieldResourceDTO;
import io.metersphere.track.dto.CustomFieldResourceCompatibleDTO;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@ -130,6 +132,21 @@ public class CustomFieldResourceService {
return extCustomFieldResourceMapper.getByResourceId(tableName, resourceId);
}
public void batchUpdateByResourceIds(String tableName, List<String> resourceIds, CustomFieldResourceDTO customField) {
if (CollectionUtils.isEmpty(resourceIds)) {
return;
}
SubListUtil.dealForSubList(resourceIds, 5000, (subIds) ->
extCustomFieldResourceMapper.batchUpdateByResourceIds(tableName, subIds, customField));
}
public void batchInsertIfNotExists(String tableName, List<String> resourceIds, CustomFieldResourceDTO customField) {
ServiceUtils.batchOperate(resourceIds, 5000, ExtCustomFieldResourceMapper.class, (resourceId, batchMapper) -> {
customField.setResourceId((String) resourceId);
((ExtCustomFieldResourceMapper) batchMapper).batchInsertIfNotExists(tableName, customField);
});
}
protected List<CustomFieldResource> getByResourceIds(String tableName, List<String> resourceIds) {
if (CollectionUtils.isEmpty(resourceIds)) {
return new ArrayList<>();

View File

@ -2,6 +2,7 @@ package io.metersphere.service;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.dto.CustomFieldDao;
import io.metersphere.dto.CustomFieldResourceDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -45,4 +46,12 @@ public class CustomFieldTestCaseService extends CustomFieldResourceService {
public List<CustomFieldResource> getByResourceId(String resourceId) {
return super.getByResourceId(TABLE_NAME, resourceId);
}
public void batchUpdateByResourceIds(List<String> resourceIds, CustomFieldResourceDTO customField) {
super.batchUpdateByResourceIds(TABLE_NAME, resourceIds, customField);
}
public void batchInsertIfNotExists(List<String> ids, CustomFieldResourceDTO customField) {
super.batchInsertIfNotExists(TABLE_NAME, ids, customField);
}
}

View File

@ -1500,6 +1500,9 @@ public class TestCaseService {
}
public List<TestCaseDTO> findByBatchRequest(TestCaseBatchRequest request) {
if (!request.getCondition().isSelectAll()) {
request.getCondition().setIds(request.getIds());
}
return listTestCase(request.getCondition(), true);
}
@ -1717,6 +1720,7 @@ public class TestCaseService {
String name = customField.getName();
String value = JSONObject.parse(customField.getValue()).toString();
TestCaseWithBLOBs testCaseWithBLOBs = new TestCaseWithBLOBs();
testCaseWithBLOBs.setUpdateTime(System.currentTimeMillis());
if (StringUtils.equalsAnyIgnoreCase(name, "用例等级")) {
testCaseWithBLOBs.setPriority(value);
@ -1733,26 +1737,17 @@ public class TestCaseService {
if (CollectionUtils.isEmpty(request.getIds())) {
return;
}
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
TestCaseMapper mapper = sqlSession.getMapper(TestCaseMapper.class);
List<TestCaseWithBLOBs> testCases = extTestCaseMapper.getCustomFieldsByIds(request.getIds());
for (int i = 0; i < testCases.size(); i++) {
TestCaseWithBLOBs testCase = testCases.get(i);
customField.setResourceId(testCase.getId());
int row = customFieldTestCaseService.updateByPrimaryKeySelective(customField);
if (row < 1) {
customFieldTestCaseService.insert(customField);
}
testCase.setUpdateTime(System.currentTimeMillis());
TestCaseExample example = new TestCaseExample();
example.createCriteria().andIdEqualTo(testCase.getId());
mapper.updateByExampleSelective(testCase, example);
if (i % 1000 == 0) {
sqlSession.flushStatements();
}
customFieldTestCaseService.batchUpdateByResourceIds(request.getIds(), customField);
// 如果没有字段则添加
customFieldTestCaseService.batchInsertIfNotExists(request.getIds(), customField);
if (request.getCondition().isSelectAll()) {
// 如果全选去掉这个查询条件避免ids过长
request.getCondition().setIds(null);
}
sqlSession.flushStatements();
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
// 更新修改时间
bathUpdateByCondition(request, testCaseWithBLOBs);
}
}