前言
通过多线程并发处理,根据值域规则过滤原始数据,将符合规则的数据插入到数据库中,并记录不符合规则的数据。
代码
//获取a表数据总量
Integer endNumber = InfoMapper.getOriginCount();
Integer beginNumber;
Integer pageSize = 100000;
//分批处理,每次处理10万条数据,id排序
do {
beginNumber = Math.max((endNumber - 100000), 0);
if (0 == beginNumber) {
pageSize = endNumber;
}
originList = InfoMapper.getOriginList(beginNumber, pageSize);
endNumber = beginNumber;
//多线程
originLists = ListUtils.partition(originList, 20000);
countDownLatch = new CountDownLatch(originLists.size());
for (List<Map<String, String>> origin : originLists) {
//过滤数据
asyncService.filterOrigin(origin, ruleMap, countDownLatch);
}
countDownLatch.await();
} while (endNumber > 0);
/**
* 根据值域规则过滤原数据
*/
@Async("initDataThreadPoolExecutor")
public void filterOrigin(List<Map<String,String>> originMapList,Map<String,List<InitRuleVo>> ruleMap, CountDownLatch countDownLatch)
{
log.info("根据值域规则过滤原数据线程启动"+Thread.currentThread().getName());
try {
String value;
Boolean insertFlag;
for (Map<String,String> originMap:originMapList) {
insertFlag =true;
//遍历原数据的字段名
for (Map.Entry<String,String> origin: originMap.entrySet()){
//根据字段名获取规则数据
if(CollectionUtils.isNotEmpty(ruleMap.get(origin.getKey()))){
value=origin.getValue();
//根据规则过滤数据
for(InitRuleVo rule : ruleMap.get(origin.getKey())){
insertFlag = getDataBoolean(value, insertFlag, rule);
}
}
}
LocalCache.putValidData("initCount",(Integer)LocalCache.get("initCount")+1);
//插入符合要求的数据
if(insertFlag){
originMap.keySet().retainAll(FieldList);
InfoMapper.insertOrigin(originMap);
}
//记录未通过的数据id
else{
filterIdList.add(originMap.get("id"));
}
}
}catch (Exception e) {
e.printStackTrace();
LocalCache.remove("initLog");
LocalCache.remove("initCount");
LocalCache.remove("allCount");
} finally {
countDownLatch.countDown();
log.info("-----完成初始化匹配---------------" + countDownLatch.getCount() + "-------------------------");
}
}
/**
*过滤条件
*/
public Boolean getDataBoolean(String value, Boolean insertFlag, PatientInitRuleVo rule) {
//0能否为空
if("0".equals(rule.getRuleCode())){
//1不可以为空
if("1".equals(rule.getRuleContent())&& StringUtils.isBlank(value)){
insertFlag=false;
}
}
//1特殊字符
else if("1".equals(rule.getRuleCode())){
if(StringUtils.isBlank(value)){
insertFlag=false;
}else{
String[] shieldArray=rule.getRuleContent().split(",");
for (String shield:shieldArray) {
if(!shield.contains("%")&&value.equals(shield)){
insertFlag=false;
}else if(shield.startsWith("%")&&shield.endsWith("%")&&
value.contains(shield.replaceAll("%",""))){
insertFlag=false;
}else if(!shield.startsWith("%")&&shield.endsWith("%")&&
value.endsWith(shield.replaceAll("%",""))){
insertFlag=false;
}else if(shield.startsWith("%")&&!shield.endsWith("%")&&
value.startsWith(shield.replaceAll("%",""))){
insertFlag=false;
}
}
}
}
//2数据长度
else if("2".equals(rule.getRuleCode())){
if(StringUtils.isBlank(value)){
insertFlag=false;
}else{
if(rule.getRuleContent().contains("-")){
String[] lengthArray=rule.getRuleContent().split("-");
if(value.length()<Integer.valueOf(lengthArray[0])||
value.length()>Integer.valueOf(lengthArray[1])){
insertFlag=false;
}
}else{
if(value.length()!=Integer.valueOf(rule.getRuleContent())){
insertFlag=false;
}
}
}
}
//3日期格式
else if("3".equals(rule.getRuleCode())){
if(StringUtils.isBlank(value)){
insertFlag=false;
}else{
SimpleDateFormat sdf = new SimpleDateFormat(rule.getRuleContent());
try{
sdf.parse(value);
}catch (Exception e){
insertFlag=false;
}
}
}
//4引用码表
else if("4".equals(rule.getRuleCode())){
if(StringUtils.isBlank(value)){
insertFlag=false;
}else{
if(!rule.getTableContentList().contains(value)){
insertFlag=false;
}
}
}
//5枚举
else if("5".equals(rule.getRuleCode())){
if(StringUtils.isBlank(value)){
insertFlag=false;
}else{
if(!rule.getRuleContent().contains(value)){
insertFlag=false;
}
}
}
//6正则
else if("6".equals(rule.getRuleCode())){
if(StringUtils.isBlank(value)){
insertFlag=false;
}else{
if(!Pattern.compile(rule.getRuleContent()).matcher(value).matches()){
insertFlag=false;
}
}
}
return insertFlag;
}
注释
1.通过调用 InfoMapper
中的 getOriginCount()
方法获取了原始数据的总数量,并将其存储在 endNumber
变量中。
2.beginNumber
用于跟踪分批处理的起始位置,pageSize
表示每次处理的数据量。
3.开始分批处理:
- 计算起始位置
beginNumber
和每次处理的数据量pageSize
。 - 从数据库中获取指定范围的原始数据并存储在
originList
中。 - 将
originList
划分成小块,每个小块包含不超过 20000 条数据,并使用多线程方式进行数据过滤。 - 使用
CountDownLatch
来等待所有数据过滤任务完成。
4.filterOrigin
方法:
filterOrigin
方法被标记为异步执行,它接收一个包含原始数据的列表 originMapList
,一个值域规则映射 ruleMap
,以及一个 CountDownLatch
用于任务控制。
在 filterOrigin
方法中,对 originMapList
中的数据进行遍历,针对每条数据应用一组值域规则(ruleMap
中定义的规则)。根据规则的条件,决定是否插入数据到数据库中。符合规则的数据会被保留,不符合规则的数据会被标记并记录。、最后,countDownLatch.countDown()
用于通知主线程任务完成,减少计数器值。
5.getDataBoolean
方法: 这个方法用于根据值域规则检查数据是否满足规则条件。它接收数据值、一个布尔标志 insertFlag
和一个值域规则对象,并根据规则条件更新 insertFlag
标志。规则包括是否为空、特殊字符、数据长度、日期格式、引用码表、枚举和正则表达式等条件。
6.将符合值域规则的数据插入到b表中。