本文章使用 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