SQL Server推送数据到MQ字段丢失的生产问题排查

背景

从SQL Server推数据到MQ。

SQL查询语句(省略若干查询字段):

select 
CallStartDt,
SeqNum,
CallId,
Service_Id,
UMID
from CallDetail
where CallInsertDt >= CONVERT(varchar(10),DATEADD(MINUTE,-510,GETDATE()),120)+' '+
                cast(DATEPART(HOUR,DATEADD(MINUTE,-510,GETDATE())) as varchar(10))+':'+
                right('0'+cast((DATEPART(MINUTE,DATEADD(MINUTE,-510,GETDATE()))/10)*10 as varchar(10)),2)+':00'
and CallInsertDt < CONVERT(varchar(10),DATEADD(MINUTE,-480,GETDATE()),120)+' '+cast(DATEPART(HOUR,DATEADD(MINUTE,-480,GETDATE())) as varchar(10)) + ':'+ right('0'+cast(DATEPART(MINUTE,DATEADD(MINUTE,-480,GETDATE()))- DATEPART(MINUTE,DATEADD(MINUTE,-480,GETDATE()))%10 as varchar(10)),2)+':00'

在这里插入图片描述

String topic = query.get(TOPIC) + "";
String[] columnArr = (query.get(COLUMN) + "").replace("\\n", "").replace(" ", "").split(",");
String childName = query.get(CHILD_NAME) + "";
String[] childColumnArr = (query.get(CHILD_COLUMN) + "").split(",");
// 调整: 未填写字段名不发送MQ(旧版==null条件始终不满足)
if (query.get(COLUMN) == null || StringUtils.isEmpty(query.get(COLUMN).toString())) {
    jsonObjectReturn.put("msg", "未指定字段名,不发送MQ");
    jsonObjectReturn.put("code", 1);
    return jsonObjectReturn;
}
log.info("execAutoWorkTo autoWordConfigId id:{}, query:{}", jobId, query);
// 批量消息发送
List<String> msgList = new ArrayList<>();
for (Map<String, Object> map : dataList) {
    JSONObject mq = new JSONObject();
    JSONObject childMq = new JSONObject();
    for (String s : columnArr) {
        String dbKey = s.split(":")[0];
        String mqKey = "";
        if (s.contains(":")) {
            mqKey = s.split(":")[1];
        }
        if (StringUtils.isBlank(mqKey)) {
            mq.put(dbKey, map.get(dbKey));
        } else {
            mq.put(mqKey, map.get(dbKey));
        }
    }
    if (StringUtils.isNotBlank(childName) && !"null".equals(childName)) {
        for (String s : childColumnArr) {
            String childDbKey = s.split(":")[0];
            String childMqKey = "";
            if (s.contains(":")) {
                childMqKey = s.split(":")[1];
            }
            if (StringUtils.isBlank(childMqKey)) {
                childMq.put(childDbKey, map.get(childDbKey));
            } else {
                childMq.put(childMqKey, map.get(childDbKey));
            }
        }
        mq.put(childName, childMq);
    }
    msgList.add(JSONObject.toJSONString(mq));
    // 批量发送
    if (msgList.size() == batchNum) {
        List<String> paramList = new ArrayList<>(msgList);
        mqThreadService.execute(() -> {
            try {
                mqMessageService.sendBatchMsg(topic, paramList);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        msgList.clear();
    }
}

在这里插入图片描述

select id, json_extract(datajson, '$.queryTo.column') from auto_word_config where isactive = 1
and cron_exp_status = 1 and to_type='mq' and  json_extract(datajson, '$.queryTo.column') !='';

在这里插入图片描述

本地开发环境复现
在这里插入图片描述

反思

为什么一模一样的程序,一模一样的数据表column字段,旧版没有问题,而新版有问题?

旧版代码和新版一模一样,除了一行:

String columnTmp = (query.get(COLUMN) + "").replaceAll("\\n", "").replaceAll(" ", "");

恍然大悟:这不就是Java最最基础的String工具类replace与replaceAll的区别吗?

String.replace vs replaceAll

  • replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence,字符串序列,即字符串);

  • replaceAll的参数是regex,即基于规则表达式的替换,比如:可通过replaceAll("\\d", "*")把一个字符串所有的数字字符都换成星号;

  • 相同点:都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串;

  • 不同点:replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\\d", "*"),而replace则不会,replace("\\d","*")就是替换"\d"的字符串,而不会解析为正则。

另一个不同点:“\”在java中是一个转义字符,所以需要用两个代表一个。例如System.out.println( “\” ) ;只打印出一个""。但是“\”也是正则表达式中的转义字符,需要用两个代表一个。所以:\\被java转换成\,\又被正则表达式转换成\,因此用replaceAll替换“\”为"\",就要用replaceAll("\\","\\\\"),而replace则replace("\","\\")。

如果只想替换第一次出现的,可以使用replaceFirst(),这个方法也是基于规则表达式的替换。

posted @ 2022-03-02 23:09  johnny233  阅读(35)  评论(0编辑  收藏  举报  来源