Skip to content

Repository files navigation

介绍

English | 中文

Maven Central License: MIT GitHub stars

tdengine-orm-boot-starter 是一个基于 SpringBootJdbc 的半 ORM 框架,用于便捷操作 TDengine 数据,其设计参考了 MyBatisPlus

项目结构

本项目是一个 Maven 多模块项目,包含以下模块:

模块 说明 使用场景
tdengine-orm-annotation 轻量级注解模块 仅定义实体类的项目(无需 Spring)
tdengine-orm-boot-starter 完整的 Spring Boot Starter Spring Boot 应用

运行 Demo(子模块)

仓库包含演示子模块 tdengine-orm-demo(以 Git submodule 方式引入)。如果需要本地跑 demo 或演示测试:

  1. 获取子模块代码:git submodule update --init --recursive(或在已有仓库中执行同样指令同步最新代码)。
  2. 进入子模块运行:cd tdengine-orm-demo && mvn clean package(或 mvn test)。
  3. 使用 IntelliJ IDEA 打开主仓库时,如未自动识别 demo,需要手动 Import 该 Maven 项目(tdengine-orm-demo/pom.xml)才能看到源码与测试。

技术栈

  • Spring Boot AutoConfigure 2.x:直接依赖 spring-boot-autoconfigure,复用条件装配、配置绑定等自动化能力(兼容 Spring Boot 2.7+)
  • Spring Boot Starter Data JDBC 2.x:引入 spring-boot-starter-data-jdbc(内部包含 spring-jdbc),框架主要基于 JdbcTemplate
  • 自研模块:tdengine-orm-annotation 提供实体注解模型,tdengine-orm-boot-starter 负责自动配置与模板能力

快速开始

1. 添加依赖

完整 ORM 功能(Spring Boot 项目)

Maven - 在 pom.xml 中添加:

<!-- TDengine ORM Boot Starter -->
<dependency>
    <groupId>io.github.zephyrcicd</groupId>
    <artifactId>tdengine-orm-boot-starter</artifactId>
    <version>${tdengine-orm.version}</version>  <!-- 请查看最新版本 -->
</dependency>

<!-- TDengine JDBC 驱动(必需) -->
<dependency>
    <groupId>com.taosdata.jdbc</groupId>
    <artifactId>taos-jdbcdriver</artifactId>
    <version>${taos-jdbcdriver.version}</version>  <!-- 请根据您的 TDengine 版本选择合适的驱动版本 -->
</dependency>

Gradle Kotlin DSL - 在 build.gradle.kts 中添加:

dependencies {
    // TDengine ORM Boot Starter
    implementation("io.github.zephyrcicd:tdengine-orm-boot-starter:${tdengineOrmVersion}")  // 请查看最新版本

    // TDengine JDBC 驱动(必需)
    implementation("com.taosdata.jdbc:taos-jdbcdriver:${taosJdbcdriverVersion}")  // 请根据您的 TDengine 版本选择
}

Gradle Groovy DSL - 在 build.gradle 中添加:

dependencies {
    // TDengine ORM Boot Starter
    implementation "io.github.zephyrcicd:tdengine-orm-boot-starter:${tdengineOrmVersion}"  // 请查看最新版本

    // TDengine JDBC 驱动(必需)
    implementation "com.taosdata.jdbc:taos-jdbcdriver:${taosJdbcdriverVersion}"  // 请根据您的 TDengine 版本选择
}

仅注解(实体类项目)

如果您的项目只需要定义实体类(如独立的 API 模块),可以只引入轻量级的注解模块:

Maven

<dependency>
    <groupId>io.github.zephyrcicd</groupId>
    <artifactId>tdengine-orm-annotation</artifactId>
    <version>${tdengine-orm.version}</version>
</dependency>

Gradle

implementation("io.github.zephyrcicd:tdengine-orm-annotation:${tdengineOrmVersion}")

💡 最新版本:请访问 Maven CentralGitHub Releases 查看最新版本 💡 TDengine JDBC 驱动:请参考 Maven Central - taos-jdbcdriver 选择与您的 TDengine 服务器版本兼容的驱动版本(如 3.2.5、3.6.3 等)

2. 配置数据源

本框架不负责创建数据源,需要用户自行配置。推荐使用 Spring Boot 标准方式配置:

spring:
  datasource:
    url: jdbc:TAOS://localhost:6030/test
    username: root
    password: taosdata
    driver-class-name: com.taosdata.jdbc.TSDBDriver

td-orm:
  enabled: true
  log-level: ERROR
  page-size: 500  # 批量操作分页大小,默认500

💡 注意:从 2.x 版本开始,框架专注于 ORM 功能,数据源管理由用户或专门的数据源 starter 负责。

3. 创建实体类

使用 @TdTable@TdTag 注解定义实体:

@TdTable("sensor_data")
public class SensorData {
    @TdTag
    private String deviceId;

    private Double temperature;
    private Long ts;
    // getter/setter...
}

4. 开始使用

在服务类中注入 TdTemplate 即可使用:

@Service
public class IoTDataService {
    @Autowired
    private TdTemplate tdTemplate;

    public void saveData(SensorData data) {
        tdTemplate.insert(data);
    }
}

升级指南

v1.5.6 破坏性变更

DefaultTagNameStrategy 重构为 Spring Bean

DefaultTagNameStrategy 现在需要通过 Spring 依赖注入使用,不再支持直接 new 实例化。

变更原因: 新增 Tag 顺序自动对齐 DDL 定义功能,生成子表名时 tag 值顺序与 TDengine DDL 定义保持一致。

迁移方式:

// 旧用法 (不再支持)
DefaultTagNameStrategy<Entity> strategy = new DefaultTagNameStrategy<>();
tdTemplate.insert(strategy, entity);

// 新用法 - 通过 Spring DI 注入
@Autowired
private DefaultTagNameStrategy defaultTagNameStrategy;

public void save(Entity entity) {
    tdTemplate.insert(defaultTagNameStrategy, entity);
}

新增功能:

  • TagOrderCacheManager:缓存超级表的 tag 定义顺序,避免重复查询
  • TdOrmConfig.getDatabaseName():从 JDBC URL 自动提取数据库名称
  • Tag 顺序自动与 TDengine DDL 定义对齐,确保子表名生成一致性

详细使用指南

数据源配置

从 2.x 版本开始,本框架不再自动创建数据源,而是专注于 ORM 功能。用户需要自行配置 TDengine 数据源。

方式一:使用 Spring Boot 自动配置(推荐)

最简单的方式是使用 Spring Boot 的标准数据源配置:

application.yml 示例
spring:
  datasource:
    url: jdbc:TAOS://localhost:6030/test
    username: root
    password: taosdata
    driver-class-name: com.taosdata.jdbc.TSDBDriver

td-orm:
  enabled: true  # 可选,默认为 true
  log-level: ERROR  # 日志级别:ERROR, WARN, INFO, DEBUG
  page-size: 500  # 批量操作分页大小,默认 500
  enable-ts-auto-fill: true  # 是否启用 ts 字段自动填充,默认 true
application.properties 示例
spring.datasource.url=jdbc:TAOS://localhost:6030/test
spring.datasource.username=root
spring.datasource.password=taosdata
spring.datasource.driver-class-name=com.taosdata.jdbc.TSDBDriver

td-orm.enabled=true
td-orm.log-level=ERROR
td-orm.page-size=500

方式二:自定义 DataSource Bean

如果需要更精细的连接池控制,可以自定义 DataSource Bean:

使用 HikariCP
@Configuration
public class TdengineDataSourceConfig {

    @Bean
    @Primary
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:TAOS://localhost:6030/test");
        config.setUsername("root");
        config.setPassword("taosdata");
        config.setDriverClassName("com.taosdata.jdbc.TSDBDriver");

        // 自定义连接池配置
        config.setMaximumPoolSize(30);
        config.setMinimumIdle(10);
        config.setConnectionTimeout(30000);
        config.setIdleTimeout(600000);
        config.setMaxLifetime(1800000);

        return new HikariDataSource(config);
    }
}
使用 Druid
@Configuration
public class TdengineDataSourceConfig {

    @Bean
    @Primary
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:TAOS://localhost:6030/test");
        dataSource.setUsername("root");
        dataSource.setPassword("taosdata");
        dataSource.setDriverClassName("com.taosdata.jdbc.TSDBDriver");

        // 自定义连接池配置
        dataSource.setInitialSize(10);
        dataSource.setMaxActive(50);
        dataSource.setMinIdle(10);
        dataSource.setMaxWait(30000);
        dataSource.setValidationQuery("SELECT 1");
        dataSource.setTestWhileIdle(true);

        return dataSource;
    }
}

使用 TdTemplate

在你的服务类中注入和使用 TdTemplate

@Service
public class IoTDataService {

    @Autowired
    private TdTemplate tdTemplate;

    public void saveData(SensorData data) {
        // 插入单条数据
        tdTemplate.insert(data);
    }

    public List<SensorData> findData() {
        // 查询数据
        TdQueryWrapper<SensorData> wrapper = TdWrappers.queryWrapper(SensorData.class)
                .selectAll()
                .orderByDesc("ts")
                .limit(100);
        return tdTemplate.list(wrapper);
    }
}

4. 完整示例项目

如果您想查看完整的、可运行的使用案例,请参考我们的 Demo 项目:

📦 tdengine-orm-demo

Demo 项目特点:

  • ✅ 15个完整的测试用例,覆盖所有核心功能
  • ✅ 包含性能统计和吞吐量测试
  • ✅ 演示 PARTITION BY 分区查询、时间窗口等高级功能
  • ✅ 开箱即用,配置数据库连接后即可运行
  • ✅ 代码简洁清晰,适合学习参考

通过运行 Demo 项目的测试用例,您可以快速了解 TdTemplate 的各种使用方式。

5. 注解说明

该框架提供三个核心注解来定义 TDengine 实体类:

@TdTable

用于映射实体类到 TDengine 表或超级表:

@TdTable("sensor_data")  // 指定表名
public class SensorData {
    // ...
}
@TdTag

标记 TAG 字段(TDengine 的元数据列),用于子表分组和过滤:

@TdTag
private String deviceId;  // TAG 字段
@TdColumn

字段列映射注解,支持多种配置:

@TdColumn(value = "temp", type = TdFieldTypeEnum.DOUBLE, length = 8)
private Double temperature;

@TdColumn(exist = false)
private String internalField;  // 不参与 SQL 生成的内部字段

@TdColumn 主要属性:

  • value:自定义列名(默认使用字段的下划线形式)
  • type:指定 TDengine 字段类型(默认自动推断)
  • length:字段长度,适用于 NCHAR、BINARY、VARCHAR 等类型
  • exist:控制字段是否参与 SQL 生成(默认 true)
  • comment:字段注释
  • nullable:是否允许为空
  • compositeKey:是否为复合主键(仅 TDengine 3.3+ 支持)

6. 实体类定义示例

@TdTable("sensor_data")
public class SensorData {

    @TdTag
    private String deviceId;

    @TdTag
    @TdColumn(value = "location", length = 100)
    private String location;

    @TdColumn(value = "temp", type = TdFieldTypeEnum.DOUBLE)
    private Double temperature;

    private Double humidity;
    private Long ts;

    // getter/setter 方法...
}

自动填充功能

框架提供自动填充功能,默认会自动填充名为 ts 的时间戳字段。该功能默认开启,可以通过配置进行关闭。

配置选项

td-orm:
  enabled: true
  log-level: ERROR
  enable-ts-auto-fill: true  # 是否启用ts字段自动填充,默认为true

支持的数据类型

自动填充功能支持多种时间类型:

  • Long/long - 毫秒时间戳
  • Date - Java日期类型
  • LocalDateTime - Java 8日期时间类型
  • LocalDate - Java 8日期类型
  • Instant - Java 8时间戳类型

使用示例

实体类中只需定义名为 ts 的字段,框架会在插入数据时自动填充:

@TdTable("sensor_data")
public class SensorData {
    private Long ts;  // 会自动填充为当前时间戳
    
    @TdTag
    private String deviceId;
    
    private Double temperature;
    private Double humidity;
    
    // getters and setters
}

自定义填充逻辑

如果需要自定义填充逻辑,可以实现 MetaObjectHandler 接口:

@Component
public class CustomMetaObjectHandler implements MetaObjectHandler {
    @Override
    public <T> void insertFill(T object) {
        // 自定义填充逻辑
    }
}

SQL 拦截器

框架提供了灵活的 SQL 拦截器机制,允许用户在 SQL 执行前后添加自定义逻辑,如日志记录、性能监控、审计等。

内置日志拦截器

框架内置了 LoggingSqlInterceptor,会根据配置的日志级别自动记录 SQL 执行日志:

td-orm:
  log-level: DEBUG  # DEBUG/INFO 级别会输出 SQL 日志
  enable-sql-interceptor: true  # 是否启用 SQL 拦截器,默认 true

自定义拦截器

实现 TdSqlInterceptor 接口并注册为 Spring Bean 即可添加自定义拦截逻辑:

@Component
public class AuditSqlInterceptor implements TdSqlInterceptor {

    @Override
    public boolean beforeExecute(TdSqlContext context) {
        // SQL 执行前的逻辑
        log.info("Executing SQL: {}", context.getSql());
        return true;  // 返回 true 继续执行,返回 false 中断执行
    }

    @Override
    public void afterExecute(TdSqlContext context, Object result, Throwable ex) {
        // SQL 执行后的逻辑
        long duration = System.currentTimeMillis() - context.getStartTime();
        log.info("SQL completed in {}ms", duration);
        if (ex != null) {
            log.error("SQL execution failed: {}", ex.getMessage());
        }
    }

    @Override
    public int getOrder() {
        // 拦截器执行顺序,数值越小优先级越高
        return 100;
    }
}

TdSqlContext 上下文

TdSqlContext 提供了 SQL 执行的完整上下文信息:

  • getSql() - 获取 SQL 语句
  • getParams() - 获取 SQL 参数
  • getSqlType() - 获取 SQL 类型(UPDATE/QUERY/QUERY_ONE)
  • getStartTime() - 获取执行开始时间
  • getResultClass() - 获取结果类型(查询时)
  • getAttributes() - 获取自定义属性(可在拦截器间传递数据)

拦截器执行顺序

  • beforeExecute:按 getOrder() 从小到大顺序执行
  • afterExecute:按 getOrder() 从大到小逆序执行(类似栈的 LIFO)

类型处理器 (TypeHandler)

框架提供了灵活的类型处理器机制,用于 Java 类型与数据库类型之间的序列化和反序列化转换,类似于 MyBatis 的 TypeHandler。

内置类型处理器

框架默认注册了常用类型的处理器:

处理器 Java 类型 说明
StringTypeHandler String 字符串类型
IntegerTypeHandler Integer 整数类型
LongTypeHandler Long 长整型
DoubleTypeHandler Double 双精度浮点
FloatTypeHandler Float 单精度浮点
BooleanTypeHandler Boolean 布尔类型
TimestampTypeHandler Timestamp 时间戳类型
ByteArrayTypeHandler byte[] 字节数组
JsonMapTypeHandler Map<String, Object> JSON与Map互转
ObjectTypeHandler Object 智能处理:基础类型直接存储,复杂对象序列化为JSON

高级类型处理器

// JSON 类型处理器 - 将对象序列化为 JSON 存储
JsonTypeHandler<MyPojo> handler = new JsonTypeHandler<>(MyPojo.class);

// 枚举类型处理器 - 按 name 存储
EnumTypeHandler<Status> handler = new EnumTypeHandler<>(Status.class);

// 枚举类型处理器 - 按 ordinal 存储
EnumOrdinalTypeHandler<Status> handler = new EnumOrdinalTypeHandler<>(Status.class);

// List 类型处理器 - 序列化为 JSON 数组
ListTypeHandler<String> handler = new ListTypeHandler<>(String.class);

使用注解指定处理器

@TdTable("sensor_data")
public class SensorData {
    @TdTypeHandler(JsonTypeHandler.class)
    private SensorConfig config;  // 自动序列化为 JSON

    @TdTypeHandler(EnumTypeHandler.class)
    private DeviceStatus status;  // 按枚举名称存储
}

多态反序列化

当需要根据 type 字段动态决定 dataJson 的反序列化类型时:

// 方式1:注解配置
public class Event {
    private String type;
    
    @TdPolymorphic(
        typeField = "type",
        mappings = {
            @TypeMapping(type = "SENSOR", target = SensorData.class),
            @TypeMapping(type = "ALARM", target = AlarmData.class)
        },
        defaultType = BaseData.class
    )
    private Object data;
}

// 方式2:Builder 方式
PolymorphicFieldHandler handler = PolymorphicFieldHandler.builder()
    .typeColumn("type")
    .dataColumn("data_json")
    .register("SENSOR", SensorData.class)
    .register("ALARM", AlarmData.class)
    .defaultType(BaseData.class)
    .build();

复用 MyBatis TypeHandler

如果项目中已有 MyBatis TypeHandler,可以直接复用,无需重复开发:

// 批量注册已有的 MyBatis TypeHandler
TypeHandlerRegistry.getInstance().fromMybatis(
    new MyJsonTypeHandler(),
    new MyEnumTypeHandler(Status.class),
    new MyCustomTypeHandler()
);

// 指定 Java 类型注册
TypeHandlerRegistry.getInstance().fromMybatis(MyPojo.class, new MyPojoTypeHandler());

// 从 Spring 容器批量注册
@Autowired
private List<org.apache.ibatis.type.TypeHandler<?>> mybatisHandlers;

@PostConstruct
public void init() {
    TypeHandlerRegistry.getInstance().fromMybatis(mybatisHandlers);
}

💡 注意:复用 MyBatis TypeHandler 需要添加 MyBatis 依赖(已设为 optional)

自定义类型处理器

继承 BaseTypeHandler<T> 实现自定义类型转换:

public class LocalDateTypeHandler extends BaseTypeHandler<LocalDate> {

    public LocalDateTypeHandler() {
        super(LocalDate.class);
    }

    @Override
    protected void setNonNullParameter(PreparedStatement ps, int index, LocalDate parameter) throws SQLException {
        ps.setDate(index, Date.valueOf(parameter));
    }

    @Override
    protected LocalDate getNullableResult(ResultSet rs, String columnName) throws SQLException {
        Date date = rs.getDate(columnName);
        return date != null ? date.toLocalDate() : null;
    }

    @Override
    protected LocalDate getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        Date date = rs.getDate(columnIndex);
        return date != null ? date.toLocalDate() : null;
    }

    @Override
    protected LocalDate convertFromSqlValue(Object sqlValue) {
        if (sqlValue instanceof Date) {
            return ((Date) sqlValue).toLocalDate();
        }
        return null;
    }
}

// 注册自定义处理器
TypeHandlerRegistry.getInstance().register(new LocalDateTypeHandler());

自动配置详情

Bean 创建

该 starter 会自动创建以下 Bean(基于用户提供的 DataSource):

  • tdengineJdbcTemplate - TDengine 专用的 JdbcTemplate
  • tdengineNamedParameterJdbcTemplate - TDengine 专用的 NamedParameterJdbcTemplate
  • tdTemplate - TDengine 数据访问模板类

💡 注意:从 2.x 版本开始,框架不再自动创建 DataSource,需要用户自行配置数据源。

禁用自动配置

如果需要禁用 TDengine ORM 的自动配置,可以在配置文件中设置:

td-orm:
  enabled: false

或者在启动类上排除自动配置:

@SpringBootApplication(exclude = {TdOrmAutoConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

注意事项

  1. 确保 TDengine 服务正在运行并且数据源配置正确
  2. 框架依赖用户提供的 DataSource,请确保已正确配置数据源
  3. 该 starter 与 Spring Boot 的自动配置兼容,不会冲突

构建说明

本项目是一个 Maven 多模块项目,使用 Maven 进行构建与发布,常用命令如下:

# 编译所有模块
mvn clean compile

# 打包所有模块(跳过测试,测试需要 TDengine 数据库)
mvn clean package -DskipTests

# 安装到本地 Maven 仓库(本地开发需使用 skip-gpg profile 跳过 GPG 签名)
mvn clean install -DskipTests -Pskip-gpg

# 编译指定模块
mvn clean compile -pl tdengine-orm-annotation
mvn clean compile -pl tdengine-orm-boot-starter

# 查看依赖树
mvn dependency:tree

💡 注意:本地开发安装时必须使用 -Pskip-gpg 参数跳过 GPG 签名,否则会因缺少 GPG 密钥而失败。

贡献与支持

欢迎贡献

我们非常欢迎开发者为 TDengine ORM Boot Starter 贡献代码!无论是:

  • 🐛 报告问题 - 发现 Bug 请在 Issues 中提交
  • 💡 功能建议 - 有好的想法欢迎在 Issues 中讨论
  • 🔧 提交代码 - 欢迎提交 Pull Request 改进项目
  • 📖 完善文档 - 帮助我们改进文档和示例

给个 Star ⭐

如果这个项目对您有帮助,欢迎给个 Star 支持一下!您的支持是我们持续改进的动力。 GitHub stars

Star History Chart

About

便捷操作TDengine半ORM框架

Resources

Stars

9 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages