【微服务】SpringBoot 整合高性能时序数据库 Apache IoTDB 实战操作详解
目录
一、前言
二、Apache IoTDB 介绍
2.1 Apache IoTDB 是什么
2.2 Apache IoTDB 核心特点
2.3 Apache IoTDB 应用场景
2.4 与其他时序数据库对比
三、Docker 部署Apache IoTDB
3.1 创建本地数据映射目录
3.2 启动容器
3.3 使用cli命令连接
3.4 基本使用
四、与SpringBoot 的整合
4.1 前置准备
4.2 基于iotdb-session 的整合过程
4.2.1 添加核心依赖
4.2.2 添加配置文件
4.2.3 添加iotdb配置类
4.2.4 添加数据模型
4.2.5 添加操作iotdb的工具类
4.3 基于iotdb-session的整合测试
4.3.1 提供完整测试代码
4.3.2 核心用例测试
4.4 基于JDBC 方式整合过程
4.4.1 导入核心依赖
4.4.2 添加配置文件
4.4.3 增加数据库连接配置
4.4.4 增加实体值映射对象
4.4.5 增加操作数据库的jpa类型
4.4.6 自定义业务层的service类
4.4.7 自定义接口类
4.4.8 效果测试
五、写在文末
一、前言
在当下数字化深入广泛应用到各个领域,各类物联网设备的使用越来越多,比如各自智能穿戴设备,智能家具,车联网等。这些设备源源不断地产生大量的时序数据,比如传感器读数、设备状态信息等。通常来说,这在这个领域中,时序数据库作为专门存储和管理时序数据的数据库系统,是承载和处理这些数据的关键基础设施。选择合适的时序数据库对于确保数据的高效存储、快速查询和深入分析至关重要。本文以Apache IoTDB为例,从部署到实际在springboot项目中的整合进行详细的分享。
二、Apache IoTDB 介绍
2.1 Apache IoTDB 是什么
Apache IoTDB(Internet of Things Database)是一款开源、高性能的物联网原生时序数据库管理系统,它起源于清华大学,并于2020年9月成为Apache软件基金会的顶级项目。官网:https://iotdb.apache.org/

2.2 Apache IoTDB 核心特点
Apache IoTDB 作为一款性能优异的时序数据库,具备如下核心特点

具体来说,其核心特点的详细说明如下:
-
高效的数据管理与查询
-
灵活的元数据管理:
-
采用树状结构组织元数据,一个实例可包含多个存储组(Storage Group,类似于Namespace或Database的概念),一个存储组里包含多个设备(Device),每个设备包含多个测量值(Measurement)。
-
-
丰富的查询语义:
-
除了基础操作,IoTDB 支持跨设备和传感器的时间对齐查询,以及在时间维度上的聚合(降采样)等。
-
-
-
优化的存储与高性能
-
专为时序数据设计的TsFile:
-
TsFile是一种为物联网设备时序数据存储定制的紧致列式存储文件格式,支持有损、无损等多种高效编码及专有压缩算法。
-
-
高性能读写:
-
IoTDB中可以支持数百万个低功耗和智能联网设备的高速写访问,并提供数据快速读取访问以查询。基准测试表明其读写性能优于一些其他时序数据库。
-
-
-
灵活的部署与集成
-
端-边-云协同架构:
-
IoTDB提供端云一体化的解决方案。在边缘端,提供轻量化的TsFile管理能力;在云端,提供高性能的数据读写以及丰富的查询能力。
-
-
无缝对接大数据生态:
-
IoTDB支持与Hadoop、Spark、Flink等大数据处理框架进行深度集成,并提供了相应的连接器,同时也支持Grafana等可视化工具。
-
-
-
高可用与可扩展性
-
分布式集群支持:IoTDB支持分布式部署,通过Raft协议来确保数据的一致性。系统支持自动负载均衡,并具备高可用性,单节点失效不影响集群服务。
-
2.3 Apache IoTDB 应用场景
IoTDB 应用场景非常广泛,主要包括如下相关的领域:
-
工业物联网(IIoT):
-
在钢铁冶炼、制造业等场景,用于生产全流程实时数据采集与分析,助力产能提升、质量优化与能耗降低
-
-
能源电力:
-
管理发电、输电、用电等全环节数据,提升能效、保障电网安全
-
-
航空航天:
-
处理实时遥测与试飞数据,实现关键系统精准监测,推动设计优化与安全管控
-
-
交通运输:
-
应用于铁路、地铁等场景的智能调度与高效运维,满足高实时、高可靠管理需求
-
-
智能家居:
-
通过监测并控制各种家用设备状态,处理设备产生的时序数据,提供个性化服务
-


小结:
总的来说,Apache IoTDB通过其物联网原生的数据模型、高性能的存储引擎、灵活的部署方式以及与大数据生态的深度集成,为企业处理物联网时序数据提供了一个高效、可靠且低总体拥有成本的解决方案。特别是在工业物联网等对数据管理要求严苛的场景中,IoTDB 展现出了独特的价值。
2.4 与其他时序数据库对比
作为一款时序数据库,相比市面上其他的时序数据库 ,Apache IoTDB有其独特的优势,下面列举了Apache IoTDB与其他主流的时序数据库的多维度对比
| 对比维度 | Apache IoTDB | InfluxDB | TimescaleDB | OpenTSDB |
| 核心架构 | 自研存储引擎 (TsFile),端-边-云协同 | 自研存储引擎 (TSM) | 基于 PostgreSQL 的扩展 | 依赖 HBase 生态 |
| 数据模型 | 树形结构,贴合设备层级 | 基于标签 (Tag) 的扁平模型 | 关系表 | 基于标签 (Tag) 的扁平模型 |
| 查询语言 | 类SQL (IoTDB-SQL) | InfluxQL, Flux | 标准 SQL (兼容PostgreSQL) | RESTful API |
| 压缩与成本 | 超高压缩比,显著降低存储成本 | 支持压缩 | 支持压缩 | 压缩能力依赖HBase |
| 写入性能 | 稳定千万级数据点/秒写入,优化乱序数据 | 高性能写入 | 高性能写入 | 性能受HBase制约 |
| 复杂查询 | 强,支持原生时间对齐、跨设备聚合 | 支持聚合,但时间对齐能力不如IoTDB | 支持,依赖标准SQL能力 | 功能相对基础 |
| 部署与运维 | 轻量级,组件简单,运维成本低 | 单机版简单,集群版闭源 | 依赖PostgreSQL生态 | 依赖HBase等组件,运维复杂 |
三、Docker 部署Apache IoTDB
为了方便后续的使用以及在项目中整合,接下来演示如何基于Docker环境快速部署Apache IoTDB服务,参考下面的操作过程。注意提前准备好服务器的docker环境。完整使用手册:
https://iotdb.apache.org/zh/UserGuide/V1.3.x/QuickStart/QuickStart_apache.html
3.1 创建本地数据映射目录
创建两个目录,作为容器的数据卷
mkdir data
mkdir logs

3.2 启动容器
使用下面的命令启动容器

命令参数说明:
-
-d:容器在后台运行。 -
--name iotdb:为容器指定一个名称,方便管理。 -
-p 6667:6667:将容器的RPC服务端口(6667)映射到主机,这是客户端连接数据库的端口。 -
-v iotdb_data:/iotdb/data和-v iotdb_logs:/iotdb/logs:使用Docker卷(volume)持久化存储数据和日志,避免容器删除后数据丢失。
启动后,你可以使用以下命令进入容器内部,并通过CLI工具连接数据库
3.3 使用cli命令连接
使用下面的命令进入到容器内部
docker exec -it iotdb bash
进入到容器内部后可以看到很多脚本

在容器内使用CLI连接,执行下面的命令:

3.4 基本使用
基于上一步,连接成功后,你会看到IoTDB的命令行界面。可以尝试执行以下SQL命令:
-- 显示现有数据库
SHOW DATABASES;-- 创建测试数据库
CREATE DATABASE root.test;-- 创建时间序列
CREATE TIMESERIES root.test.device1.temperature WITH DATATYPE=FLOAT, ENCODING=PLAIN;
CREATE TIMESERIES root.test.device1.humidity WITH DATATYPE=FLOAT, ENCODING=PLAIN;-- 插入数据
INSERT INTO root.test.device1(timestamp, temperature, humidity) VALUES(100, 25.6, 60.5);-- 查询数据
SELECT * FROM root.test.device1;
操作过程:
1)显示数据库
目前还没有创建过任何数据库

2)创建一个测试数据库

3)创建时间序列并插入数据

4)查询数据
上一步数据插入成功后,查询一下数据

更多的SQL相关的操作可以参考官方提供的文档:https://iotdb.apache.org/zh/UserGuide/V1.3.x/SQL-Manual/SQL-Manual.html

四、与SpringBoot 的整合
IoTDB环境搭好后,下面介绍IoTDB如何与springboot进行整合使用。主流的整合方式主要有两种,基于session的整合使用,以及基于JDBC的使用方式,下面分别做完整的介绍。
4.1 前置准备
为了方便后续整合顺利,需要对基本的技术栈做补充说明:
-
JDK,17;
-
Maven ,3.6.3;
-
Idea , >= 2022.2;
-
springboot, 3.2.0;
基于上述的技术栈,提前搭建一个springboot工程。
4.2 基于iotdb-session 的整合过程
4.2.1 添加核心依赖
其他的依赖可以根据自身的需要酌情添加
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.0</version><relativePath/></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 使用 Session 方式 (推荐) --><dependency><groupId>org.apache.iotdb</groupId><artifactId>iotdb-session</artifactId><version>1.3.1</version> <!-- 建议使用最新稳定版本 --></dependency></dependencies>
4.2.2 添加配置文件
在工程的yml配置文件中增加下面的配置信息
server:port: 8081logging:level:root: infospring:iotdb:ip: 你的IPport: 6667user: rootpassword: rootfetch-size: 10000
4.2.3 添加iotdb配置类
自定义iotdb配置类,该类用于在工程启动的时候初始化iotdb的数据库会话连接
package com.congge.config;import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.session.Session;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class IotDBConfig {@Value("${spring.iotdb.ip}")private String ip;@Value("${spring.iotdb.port}")private int port;@Value("${spring.iotdb.user}")private String user;@Value("${spring.iotdb.password}")private String password;@Value("${spring.iotdb.fetch-size}")private int fetchSize;@Beanpublic Session iotSession() {Session session = new Session(ip, port, user, password, fetchSize);try {session.open(); // 打开连接} catch (IoTDBConnectionException e) {e.printStackTrace();}return session;}
}
4.2.4 添加数据模型
自定义一个数据对象,类似于与表的映射实体类对象,定义与表中保存的映射字段信息
package com.congge.config;import java.util.ArrayList;
import java.util.List;/*** 自定义设备数据实体类*/
public class DeviceData {private long timestamp;private String deviceId;private double temperature;private double humidity;private boolean status;// 构造器、getter、setterpublic DeviceData() {}public DeviceData(long timestamp, String deviceId, double temperature, double humidity, boolean status) {this.timestamp = timestamp;this.deviceId = deviceId;this.temperature = temperature;this.humidity = humidity;this.status = status;}public long getTimestamp() { return timestamp; }public void setTimestamp(long timestamp) { this.timestamp = timestamp; }public String getDeviceId() { return deviceId; }public void setDeviceId(String deviceId) { this.deviceId = deviceId; }public double getTemperature() { return temperature; }public void setTemperature(double temperature) { this.temperature = temperature; }public double getHumidity() { return humidity; }public void setHumidity(double humidity) { this.humidity = humidity; }public boolean isStatus() { return status; }public void setStatus(boolean status) { this.status = status; }/*** 转换为测量值列表*/public List<String> getMeasurements() {List<String> measurements = new ArrayList<>();measurements.add("temperature");measurements.add("humidity");measurements.add("status");return measurements;}/*** 转换为值列表*/public List<String> getValues() {List<String> values = new ArrayList<>();values.add(String.valueOf(temperature));values.add(String.valueOf(humidity));values.add(String.valueOf(status));return values;}@Overridepublic String toString() {return String.format("DeviceData{timestamp=%d, deviceId='%s', temperature=%.2f, humidity=%.2f, status=%s}",timestamp, deviceId, temperature, humidity, status);}
}
4.2.5 添加操作iotdb的工具类
实际开发中,该工具类可以作为通用的业务工具类全局使用,根据自己的实际需求进行封装
package com.congge.config;import jakarta.annotation.Resource;
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class IotDBService {@Resourceprivate Session iotSession;/*** 创建存储组*/public void createStorageGroup(String groupName) throws IoTDBConnectionException, StatementExecutionException {try {iotSession.setStorageGroup(groupName);System.out.println("存储组创建成功: " + groupName);} catch (StatementExecutionException e) {if (e.getMessage().contains("already exists")) {System.out.println("存储组已存在: " + groupName);} else {throw e;}}}/*** 创建时间序列*/public void createTimeSeries(String path, TSDataType dataType, TSEncoding encoding)throws IoTDBConnectionException, StatementExecutionException {try {iotSession.createTimeseries(path, dataType, encoding, CompressionType.SNAPPY);System.out.println("时间序列创建成功: " + path);} catch (StatementExecutionException e) {if (e.getMessage().contains("already exists")) {System.out.println("时间序列已存在: " + path);} else {throw e;}}}/*** 插入单条记录*/public void insertRecord(DeviceData data) throws IoTDBConnectionException, StatementExecutionException {String deviceId = "root.test2." + data.getDeviceId();iotSession.insertRecord(deviceId, data.getTimestamp(),data.getMeasurements(), data.getValues());System.out.println("数据插入成功: " + data);}/*** 批量插入记录 - 性能更优*/public void insertRecords(List<DeviceData> dataList) throws IoTDBConnectionException, StatementExecutionException {List<String> deviceIds = new ArrayList<>();List<Long> timestamps = new ArrayList<>();List<List<String>> measurementsList = new ArrayList<>();List<List<String>> valuesList = new ArrayList<>();for (DeviceData data : dataList) {deviceIds.add("root.test2." + data.getDeviceId());timestamps.add(data.getTimestamp());measurementsList.add(data.getMeasurements());valuesList.add(data.getValues());}iotSession.insertRecords(deviceIds, timestamps, measurementsList, valuesList);System.out.println("批量插入成功,共 " + dataList.size() + " 条记录");}/*** 执行查询*/public List<DeviceData> executeQuery(String sql) throws IoTDBConnectionException, StatementExecutionException {List<DeviceData> result = new ArrayList<>();SessionDataSet dataSet = iotSession.executeQueryStatement(sql);try {SessionDataSet.DataIterator iterator = dataSet.iterator();while (iterator.next()) {DeviceData data = new DeviceData();data.setTimestamp(Long.parseLong(iterator.getString("Time")));// 根据实际查询的字段调整if (iterator.findColumn("root.test2.device2.temperature") != -1) {data.setTemperature(Double.parseDouble(iterator.getString("root.test2.device2.temperature")));}if (iterator.findColumn("root.test2.device2.humidity") != -1) {data.setHumidity(Double.parseDouble(iterator.getString("root.test2.device2.humidity")));}if (iterator.findColumn("root.test2.device2.status") != -1) {data.setStatus(Boolean.parseBoolean(iterator.getString("root.test2.device2.status")));}result.add(data);}} finally {dataSet.close();}return result;}/*** 清理测试数据*/public void cleanupTestData() throws IoTDBConnectionException, StatementExecutionException {try {iotSession.deleteStorageGroup("root.test");System.out.println("测试数据清理完成");} catch (StatementExecutionException e) {System.out.println("无需清理测试数据: " + e.getMessage());}}/*** 检查连接状态*/public boolean checkConnection() {try {iotSession.executeQueryStatement("SHOW DATABASES").close();return true;} catch (Exception e) {return false;}}
}
4.3 基于iotdb-session的整合测试
接下来,通过测试代码分别测试下工具类中的核心方法。
4.3.1 提供完整测试代码
参考下面的测试代码
import com.congge.BootApp;
import com.congge.config.DeviceData;
import com.congge.config.IotDBService;
import jakarta.annotation.Resource;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.util.ArrayList;
import java.util.List;@SpringBootTest(classes = BootApp.class)
public class IoDbTest {private static final String TEST_STORAGE_GROUP = "root.test2";private static final String TEST_DEVICE = "device2";@Resourceprivate IotDBService iotDBService;@Test@DisplayName("测试数据库连接")void testConnection() {iotDBService.checkConnection();System.out.println("✅ 数据库连接测试通过");}@Test@DisplayName("测试创建存储组/数据库")void testCreateStorageGroup() {try {iotDBService.createStorageGroup(TEST_STORAGE_GROUP);System.out.println("✅ 存储组创建测试通过");} catch (Exception e) {System.out.println("❌ 创建存储组失败 : " + e.getMessage());}}@Test@DisplayName("测试创建时间序列")void testCreateTimeSeries() {try {iotDBService.createTimeSeries("root.test2.device2.temperature", TSDataType.FLOAT, TSEncoding.PLAIN);iotDBService.createTimeSeries("root.test2.device2.humidity", TSDataType.FLOAT, TSEncoding.PLAIN);iotDBService.createTimeSeries("root.test2.device2.status", TSDataType.BOOLEAN, TSEncoding.PLAIN);System.out.println("✅ 时间序列创建测试通过");} catch (Exception e) {System.out.println("❌ 创建时间序列失败 : " + e.getMessage());}}@Test@DisplayName("测试插入单条记录")void testInsertSingleRecord() {try {DeviceData data = new DeviceData(System.currentTimeMillis(),TEST_DEVICE,25.5,60.2,true);iotDBService.insertRecord(data);System.out.println("✅ 单条记录插入测试通过");} catch (Exception e) {System.out.println("❌ 插入单条记录失败 : " + e.getMessage());}}@Test@DisplayName("测试批量插入记录")void testBatchInsert() {try {List<DeviceData> dataList = new ArrayList<>();long baseTime = System.currentTimeMillis();for (int i = 0; i < 10; i++) {DeviceData data = new DeviceData(baseTime + (i * 1000), // 每秒一条数据TEST_DEVICE,20.0 + i * 0.5,50.0 + i * 2,i % 2 == 0);dataList.add(data);}iotDBService.insertRecords(dataList);System.out.println("✅ 批量插入测试通过,插入了 " + dataList.size() + " 条记录");} catch (Exception e) {System.out.println("❌ 批量插入失败 : " + e.getMessage());}}@Test@DisplayName("测试数据查询")void testDataQuery() {try {// 先插入一些测试数据DeviceData testData = new DeviceData(System.currentTimeMillis() - 5000,TEST_DEVICE,23.5,55.5,true);iotDBService.insertRecord(testData);// 查询数据String sql = "SELECT * FROM root.test.device1 WHERE time > " + (System.currentTimeMillis() - 10000);List<DeviceData> results = iotDBService.executeQuery(sql);System.out.println("✅ 数据查询测试通过,查询到 " + results.size() + " 条记录");results.forEach(data -> System.out.println(" - " + data));} catch (Exception e) {System.out.println("❌ 数据查询失败 : " + e.getMessage());}}@Test@DisplayName("测试条件查询")void testConditionalQuery() {try {String sql = "SELECT temperature, humidity FROM root.test.device1 WHERE temperature > 20.0";List<DeviceData> results = iotDBService.executeQuery(sql);System.out.println("✅ 条件查询测试通过,查询到 " + results.size() + " 条温度>20.0的记录");} catch (Exception e) {System.out.println("❌ 条件查询失败 : " + e.getMessage());}}}
4.3.2 核心用例测试
1)测试数据库连接
运行测试代码,效果如下:

2)创建存储组测试
运行测试代码,效果如下:

通过cli命令可以看到创建成功

3)创建时间序列测试
运行测试代码,效果如下:

4)批量插入数据测试
运行测试代码,效果如下:

使用cli 命令查询下数据,可以看到数据插入成功了

5)查询数据测试
运行测试代码,效果如下:

6)指定条件查询测试
运行测试代码,效果如下:

4.4 基于JDBC 方式整合过程
下面再提供基于JDBC 的方式的整合过程,也是开发中比较常用的一种,参考下面的操作过程。
4.4.1 导入核心依赖
pom文件中导入下面的核心依赖
<!-- jdbc 的方式 -->
<dependency><groupId>org.apache.iotdb</groupId><artifactId>iotdb-jdbc</artifactId><version>1.2.1</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
4.4.2 添加配置文件
在工程的yml配置文件中添加下面的配置信息
server:port: 8081logging:level:root: infospring:datasource:# JDBC URL格式:jdbc:iotdb://{ip}:{port}/url: jdbc:iotdb://你的IP:6667/username: rootpassword: root# 指定IoTDB的JDBC驱动类driver-class-name: org.apache.iotdb.jdbc.IoTDBDriver# HikariCP连接池配置(可选)hikari:maximum-pool-size: 10minimum-idle: 2connection-timeout: 30000idle-timeout: 600000max-lifetime: 1800000# 自定义IoTDB配置项
iotdb:# 查询默认获取批次大小fetch-size: 10000
4.4.3 增加数据库连接配置
该配置类用于初始化与数据库的连接
package com.congge.config.jdbc;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;@Configuration
public class IotDBConfig {@Beanpublic JdbcTemplate iotdbJdbcTemplate(javax.sql.DataSource dataSource) {return new JdbcTemplate(dataSource);}
}
4.4.4 增加实体值映射对象
对象与数据库的表字段进行对应
-
特别注意:实体类的第一个字段必须是Time(long类型),后续字段顺序需与查询结果严格对应。
package com.congge.config.jdbc;import lombok.Data;@Data
public class DeviceData {// 必须第一个字段是Time,存储时间戳:cite[10]private Long time;// 对应时间序列的字段,顺序需与SQL查询字段顺序一致private String deviceId;private Double temperature;private Double humidity;private Boolean status;// 全参构造器public DeviceData(Long time, String deviceId, Double temperature, Double humidity, Boolean status) {this.time = time;this.deviceId = deviceId;this.temperature = temperature;this.humidity = humidity;this.status = status;}// 无参构造器public DeviceData() {}
}
4.4.5 增加操作数据库的jpa类型
创建Repository类来封装IoTDB的CRUD操作
package com.congge.config.jdbc;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;@Repository
public class IotDBRepository {@Autowiredprivate JdbcTemplate jdbcTemplate;/*** 创建存储组*/public void createStorageGroup(String storageGroup) {String sql = "SET STORAGE GROUP TO ?";jdbcTemplate.update(sql, storageGroup);}/*** 创建时间序列*/public void createTimeSeries(String path, String dataType, String encoding) {String sql = "CREATE TIMESERIES ? WITH DATATYPE=?, ENCODING=?";jdbcTemplate.update(sql, path, dataType, encoding);}/*** 插入单条设备数据*/public void insertDeviceData(DeviceData data) {// 建议使用参数化查询,避免SQL注入String sql = "INSERT INTO root.test3.device3(timestamp, temperature, humidity, status) VALUES(?, ?, ?, ?)";jdbcTemplate.update(sql,data.getTime(),data.getTemperature(),data.getHumidity(),data.getStatus());}/*** 批量插入设备数据 - 高性能写入*/public void batchInsertDeviceData(List<DeviceData> dataList) {String sql = "INSERT INTO root.test3.device3(timestamp, temperature, humidity, status) VALUES(?, ?, ?, ?)";jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {@Overridepublic void setValues(PreparedStatement ps, int i) throws SQLException {DeviceData data = dataList.get(i);ps.setLong(1, data.getTime());ps.setDouble(2, data.getTemperature());ps.setDouble(3, data.getHumidity());ps.setBoolean(4, data.getStatus());}@Overridepublic int getBatchSize() {return dataList.size();}});}/*** 查询设备数据 - 注意字段顺序必须与实体类定义一致:cite[10]*/public List<DeviceData> queryDeviceData(Long startTime, Long endTime) {// 明确指定查询字段及其顺序,避免使用 SELECT *:cite[10]String sql = "SELECT Time, device3.temperature, device3.humidity, device3.status " +"FROM root.test3.device3 " +"WHERE time >= ? AND time <= ? " +"ORDER BY time DESC";return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(DeviceData.class),startTime, endTime);}/*** 条件查询 - 按温度阈值筛选*/public List<DeviceData> queryByTemperatureThreshold(Double tempThreshold) {String sql = "SELECT Time, device3.temperature, device3.humidity, device3.status " +"FROM root.test3.device3 " +"WHERE device3.temperature > ? " +"ORDER BY time DESC";return jdbcTemplate.query(sql,new BeanPropertyRowMapper<>(DeviceData.class),tempThreshold);}/*** 删除数据*/public void deleteData(Long endTime) {String sql = "DELETE FROM root.test3.device3 WHERE time <= ?";jdbcTemplate.update(sql, endTime);}
}
4.4.6 自定义业务层的service类
自定义一个Service类来处理与实际业务相关的逻辑
package com.congge.config.jdbc;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;@Service
public class DeviceDataService {@Autowiredprivate IotDBRepository iotDBRepository;/*** 初始化IoTDB模式(存储组和时间序列)*/public void initializeSchema() {try {// 创建存储组iotDBRepository.createStorageGroup("root.test3");// 创建时间序列 - 实际使用中可能需要根据IoTDB版本调整语法// iotDBRepository.createTimeSeries("root.test.device1.temperature", "FLOAT", "PLAIN");// iotDBRepository.createTimeSeries("root.test.device1.humidity", "FLOAT", "PLAIN");// iotDBRepository.createTimeSeries("root.test.device1.status", "BOOLEAN", "PLAIN");} catch (Exception e) {System.err.println("初始化模式失败(可能已存在): " + e.getMessage());}}/*** 生成并插入测试数据*/public void generateAndInsertTestData() {List<DeviceData> testData = new ArrayList<>();long baseTime = System.currentTimeMillis();// 生成10条测试数据for (int i = 0; i < 10; i++) {DeviceData data = new DeviceData(baseTime + (i * 1000), // 时间戳递增"device3",20.0 + i * 0.5, // 温度递增50.0 + i * 2, // 湿度递增i % 2 == 0 // 状态交替);testData.add(data);}// 批量插入iotDBRepository.batchInsertDeviceData(testData);System.out.println("成功插入 " + testData.size() + " 条测试数据");}/*** 获取最近N小时的数据*/public List<DeviceData> getRecentData(int hours) {long endTime = System.currentTimeMillis();long startTime = endTime - (hours * 60 * 60 * 1000L);return iotDBRepository.queryDeviceData(startTime, endTime);}/*** 根据温度阈值查询数据*/public List<DeviceData> getDataByTemperature(Double threshold) {return iotDBRepository.queryByTemperatureThreshold(threshold);}
}
4.4.7 自定义接口类
为方便效果测试,添加一个接口类,参考下面的代码
package com.congge.config.jdbc;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/api/device")
public class DeviceDataController {@Autowiredprivate DeviceDataService deviceDataService;/*** 初始化数据库模式* localhost:8081/api/device/init*/@GetMapping("/init")public String initializeDatabase() {try {deviceDataService.initializeSchema();return "数据库初始化成功";} catch (Exception e) {return "数据库初始化失败: " + e.getMessage();}}/*** 插入测试数据* localhost:8081/api/device/test-data*/@GetMapping("/test-data")public String insertTestData() {try {deviceDataService.generateAndInsertTestData();return "测试数据插入成功";} catch (Exception e) {return "测试数据插入失败: " + e.getMessage();}}/*** 查询最近数据* localhost:8081/api/device/recent*/@GetMapping("/recent")public List<DeviceData> getRecentData(@RequestParam(defaultValue = "1") int hours) {return deviceDataService.getRecentData(hours);}/*** 按温度查询* localhost:8081/api/device/by-temperature*/@GetMapping("/by-temperature")public List<DeviceData> getByTemperature(@RequestParam Double threshold) {return deviceDataService.getDataByTemperature(threshold);}
}
4.4.8 效果测试
启动工程后,对上面的接口进行测试。
1)测试数据初始化
调用一下接口

接口执行成功后,通过cli 命令可以看到数据库初始化成功了

2)测试插入数据
执行接口

接口执行成功后,通过cli 命令可以看到数据插入成功了

五、写在文末
本文通过较大的篇幅详细介绍了新一代时序数据库Apache IoTDB的使用,从服务的部署到与springboot的整合完整过程,最后通过实际案例代码演示了具体的使用,更多的细节有兴趣的同学还可以基于此继续完善,希望对看到的同学有用,本篇到此结束,感谢观看。
