spring boot 集成mqtt,动态数据源,时序数据库TDengine (三)

本文章使用 spring boot3、 java21、maven工程

1、时序数据库TDengine 相关部署参考 Windows 环境下安装时序数据库TDengine,并通过数据库工具DBeaver连接TDengine数据库_tdengine windows安装-CSDN博客

docker 部署 时序数据库TDengine_docker tdengine-CSDN博客

2、TDengine 数据库设计方案  思想参考 用实际案例告诉你,在 TDengine 如何进行数据建模 - TDengine | 涛思数据

本文根据设备和点位编码,点位数据值创建超级表,保存数据时动态创建子表

CREATE STABLE data_capture_kb.kb_point_data (
    ts timestamp, 
    point_value varchar(100)  -- 点位数据值
) TAGS (
	device_id  varchar(64),  -- 设备id
    point_code varchar(64)   -- 点位编码
);

3、解析mqtt消息组装数据入库,实际情况请按自己的业务去获取对应的数据入库

 解析消息

import com.alibaba.fastjson.JSONObject;
import com.hiabr.web.dto.MqttMessageDTO;
import com.hiabr.web.service.KaiBangPointDataService;
import com.hiabr.web.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: hanwei
 * @date: 2025/5/8
 */
@Slf4j
@Service("kaiBangMessageService")
public class KaiBangMessageService implements MessageHandler {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private KaiBangPointDataService kaiBangPointDataService;

    @Override
    public void handleMessage(Message<?> message) throws MessagingException {
        // 处理message
        String payload = message.getPayload().toString();
        JSONObject jsonObject = JSONObject.parseObject(payload);
        String deviceId = jsonObject.getString("deviceId");
        MqttMessageDTO mqttMessage = JSONObject.toJavaObject(jsonObject, MqttMessageDTO.class);
        boolean b = redisUtil.tryGetDistributedLock("KB_"+mqttMessage.getDeviceId(), mqttMessage.getTime(), 30);
        if(b){
            kaiBangPointDataService.insertData(mqttMessage);

        }
    }

}

 读取点位数据入库

import com.alibaba.fastjson.JSONObject;
import com.hiabr.web.annaotation.TargetDataSource;
import com.hiabr.web.dao.KaiBangPointDataDao;
import com.hiabr.web.dto.MqttMessageDTO;
import com.hiabr.web.entity.DeviceInfoEntity;
import com.hiabr.web.enums.DataSourceKey;
import com.hiabr.web.service.KaiBangPointDataService;
import com.hiabr.web.utils.DeviceRatioUtil;
import com.hiabr.web.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 凯邦工厂点位数据服务实现类
 * @author: hanwei
 * @date: 2025/5/9
 */
@Slf4j
@Service
public class KaiBangKaiBangPointDataServiceImpl implements KaiBangPointDataService {

    @Autowired
    private KaiBangPointDataDao kaiBangPointDataDao;

    @Override
    @TargetDataSource(dataSourceKey = DataSourceKey.DB_SLAVE1)
    public boolean insertData(MqttMessageDTO mqttMessage) {
        Map<String, Object> paramsMap = mqttMessage.getParams();
        try{
            Timestamp timestamp = new Timestamp(mqttMessage.getTime());
            for (Map.Entry entry : paramsMap.entrySet()) {
                String subTableName = "kb_point_data_" + mqttMessage.getDeviceId()+"_"+entry.getKey();
                String value = entry.getValue()+"";
                if(value.contains("\u0000")){
                    value = value.replaceAll("\u0000", "");
                }
                kaiBangPointDataDao.insertIntoSub(timestamp,String.valueOf(entry.getKey()),value, mqttMessage.getDeviceId(),subTableName);
            }
            return  true;
        }catch (Exception e){
            log.error("报错:{}",e);
        }
        return false;
    }
}

重点,mapper里面的插入语句 如下:通过超级表往子表写入数据,子表不存在时自动创建并插入数据 子表名可以自定义  本文是用超级表_设备id_点位编码生成子表

<insert id="insertIntoSub">
        insert into data_capture_kb.${subTableName}(ts,point_value)
        using data_capture_kb.kb_point_data tags ( #{deviceId},#{pointCode})
        values ( #{time},'${pointValue}');
    </insert>

写入数据时,数据库会动态创建子表

4、数据查询功能

通过超级表的标签字段可查询所有子表数据,优势:无需关联多张子表

需要查询某一台设备的所有点位信息,只需查询超级表通过设备id 标签过滤

例如:

select * from data_capture_kb.kb_point_data

where device_id ='zhusuji01'

等同于:select * from data_capture_kb.kb_point_data_zhusuji01_k001

                union all 

                select * from data_capture_kb.kb_point_data_zhusuji01_k002

                ..........

                union all

                select * from data_capture_kb.kb_point_data_zhusuji01_kxxx

查询具体某个设备某个点位数据:只需查询超级表通过设备id 点位编码 标签过滤,或者直接查询对应的点位子表

例如:

 
select * from data_capture_kb.kb_point_data
 where device_id ='zhusuji01' and point_code ='K001';

等同于:select * from  data_capture_kb.kb_point_data_zhusuji01_k001


同理     select * from data_capture_kb.kb_point_data
         where device_id ='zhusuji01' and point_code ='K002';

等同于:  select * from  data_capture_kb.kb_point_data_zhusuji01_k002

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hanway116

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值