概要
通过MybatisPlus实现Tdengine增删改查功能
简介
官方给出MybatisPlus-demo中所有操作通过mapper实现,添加多个实体时所有实体需要重复编写,本方案通过继承MybatisPlus接口实现增删改查,实现通用接口,无需重复编写
动态数据源配置
spring:
boot:
datasource:
type: com.zaxxer.hikari.HikariDataSource
dynamic:
datasource:
master:
url: jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# TDengine 配置信息(驱动程序,jdbc连接)
tdengine:
driver-class-name: com.taosdata.jdbc.rs.RestfulDriver
url: jdbc:TAOS-RS://127.0.0.1:6041
username: root
password: 123456
配置文件不在本次重点,按照常规配置即可
实现Model
1.首先继承MP的model类,实现一个我们自己的model
@EqualsAndHashCode(callSuper = true)
@Data
public class BaseTaosModel<T extends Model<T>> extends Model<T> implements TaosBaseInterface {
private static final long serialVersionUID = 2537647301574172972L;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty("时间戳")
private Timestamp ts;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("数据库名")
private String databaseName;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("超级表名")
private String stableName;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("表名")
private String tableName;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("insertValue相关语句")
private String insertValue;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("insertTag相关语句")
private String insertTag;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("建表相关语句")
private String createValues;
@JsonIgnore
@TableField(exist = false)
@ApiModelProperty("批量新增语句")
private String batchSql;
/**
* 时间戳构造方法
*
* @param ts 时间戳
*/
public void setTs(Timestamp ts) {
this.ts = ts;
}
/**
* 时间戳构造方法
*
* @param ts 时间戳
*/
public void setTs(Long ts) {
this.ts = new Timestamp(ts);
}
/**
* 时间戳构造方法
*
* @param ts 时间戳
*/
public void setTs(LocalDateTime ts) {
this.ts = Timestamp.valueOf(ts);
}
/**
* 获取时间戳
*
* @return 时间戳
*/
public Long getTsLong(){
if (ObjectUtils.isNotEmpty(ts)) {
return ts.getTime();
}
return null;
}
/**
* 获取时间戳
*
* @return 时间戳
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public LocalDateTime getTsLocalDateTime() {
if (ObjectUtils.isNotEmpty(ts)) {
return ts.toLocalDateTime();
}
return null;
}
/**
* 初始化相关语句方法
*
* @param baseTaosModel taos基础实体类
*/
public void init(BaseTaosModel<?> baseTaosModel) {
// 如果时间戳为空,默认当前时间
if(ObjectUtils.isEmpty(this.ts)){
this.ts = new Timestamp(System.currentTimeMillis());
}
// 如果数据库或超级表为空,默认从@TableName获取
if (StringUtils.isEmpty(this.stableName)) {
this.databaseName = getDatabaseName(baseTaosModel);
}
if (StringUtils.isEmpty(this.stableName)) {
this.stableName = getSTableName(baseTaosModel);
}
// 获取value和tag语句
this.insertValue = getInsertValue(baseTaosModel);
this.insertTag = getInsertTag(baseTaosModel);
this.createValues = getCreateSql();
}
/**
* 重写构造方法,初始化成员变量,减少taos的null值存储
*/
public BaseTaosModel() {
setStringFieldsToEmpty(this);
}
}
在其中规定了一个字段ts,用于默认的主键,同时继承了接口TaosBaseInterface,用以实现反射拼接所有实体类的基础语句
public interface TaosBaseInterface {
default String getDatabaseName(BaseTaosModel<?> baseTaosModel){
TableName tableName = baseTaosModel.getClass().getAnnotation(TableName.class);
if(StringUtils.isNotBlank(tableName.value())){
// 如果格式为DatabaseName.STableName则返回DatabaseName
String[] split = tableName.value().split("\\.");
if(StringUtils.isNotBlank(split[0])){
return split[0];
}
}
return null;
}
default String getSTableName(BaseTaosModel<?> baseTaosModel){
TableName tableName = baseTaosModel.getClass().getAnnotation(TableName.class);
if(StringUtils.isNotBlank(tableName.value())){
// 如果格式为DatabaseName.STableName则返回DatabaseName
String[] split = tableName.value().split("\\.");
if(StringUtils.isNotBlank(split[1])){
return split[1];
}else {
return tableName.value();
}
}
return null;
}
/**
* 根据实体类动态创建超级表语句
* @return 建表属性语句
*/
@JsonIgnore
default String getCreateSql(){
Field[] fields = this.getClass().getDeclaredFields();
// 获取对应字段列表
List<Field> valueFields = getTagsFields(fields, false);
List<Field> tagFields = getTagsFields(fields, true);
StringJoiner values = new StringJoiner(",", "(", ")");
StringJoiner tags = new StringJoiner(",", "(", ")");
// 添加默认时间戳属性
values.add("ts timestamp");
// 拼接values
for (Field field : valueFields) {
try {
// 获取字段名和状态名
String name = field.getName();
String typeName = field.getType().getSimpleName();
values.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name)+" "+typeName);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 拼接tags
for (Field field : tagFields) {
try {
// 获取字段名和状态名
String name = field.getName();
String typeName = field.getType().getSimpleName();
tags.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name)+" "+typeName);
} catch (Exception ex) {
ex.printStackTrace();
}
}
// 拼接建表属性相关语句,工具类替换优化性能 | 替换string类型为nchar(32) | 替换boolean为bool
return StringUtils.replaceEach(values + " tags " + tags,
new String[]{"String", "boolean", "Boolean","Long"},
new String[]{"nchar(32)", "bool", "bool","bigint unsigned"});
}
/**
* 通过反射拼接所有values
*
* @return values 所有taos属性value字符串
*/
default String getInsertValue(BaseTaosModel<?> baseTaosModel) {
return getValues(baseTaosModel,true) + " values " + getValues(baseTaosModel,false);
}
default String getInsertTag(BaseTaosModel<?> baseTaosModel) {
return getTags(baseTaosModel,true) + " tags " + getTags(baseTaosModel,false);
}
/**
* 通过反射拼接所有values
*
* @param baseTaosModel taos基础类
* @param isColumn 返回字段还是value值(true:返回字段 | false:返回value)
* @return values 所有taos属性value字符串
*/
default String getValues(BaseTaosModel<?> baseTaosModel,boolean isColumn) {
Field[] fields = this.getClass().getDeclaredFields();
List<Field> orderedField = getTagsFields(fields, false);
StringJoiner values = new StringJoiner(",", "(", ")");
StringJoiner keys = new StringJoiner(",", "(", ")");
keys.add("ts");
values.add(Long.toString(baseTaosModel.getTs().getTime()));
for (Field field : orderedField) {
boolean annotationPresent = field.isAnnotationPresent(TableField.class);
if(annotationPresent){
//有此注解
TableField annotation = field.getAnnotation(TableField.class);
boolean exist = annotation.exist();
if(!exist){
//无视其存在,不参与语句拼接
continue;
}
}
try {
// 添加字段名
String name = field.getName();
keys.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name));
// 添加字段值
field.setAccessible(true);
Object o = field.get(baseTaosModel);
List<String> valueList = StringUtil.change2String(o);
values.add(valueList.get(0));
} catch (Exception ex) {
ex.printStackTrace();
}
}
if(isColumn){
return keys.toString();
}
return values.toString();
}
/**
* 通过反射拼接所有tags
*
* @param baseTaosModel taos基础类
* @param isColumn 返回字段还是tags值(true:返回字段 | false:返回tags)
* @return values 所有taos属性tags字符串
*/
default String getTags(BaseTaosModel<?> baseTaosModel,boolean isColumn) {
Field[] fields = this.getClass().getDeclaredFields();
List<Field> orderedField = getTagsFields(fields, true);
StringJoiner values = new StringJoiner(",", "(", ")");
StringJoiner keys = new StringJoiner(",", "(", ")");
for (Field field : orderedField) {
try {
// 添加字段名
String name = field.getName();
keys.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name));
// 添加字段值
field.setAccessible(true);
Object o = field.get(baseTaosModel);
List<String> valueList = StringUtil.change2String(o);
values.add(valueList.get(0));
} catch (Exception ex) {
ex.printStackTrace();
}
}
if(isColumn){
return keys.toString();
}
return values.toString();
}
/**
* 获取values或tags对应的字段
*
* @param fields 反射获取的Field数组
* @param isTags 是否时tags
* @return 排序后Field列表
*/
default List<Field> getTagsFields(Field[] fields, boolean isTags) {
// 用来存放所有的属性域
List<Field> values = new ArrayList<>();
List<Field> tags = new ArrayList<>();
// 判断是否是tags字段
for (Field f : fields) {
if (f.getAnnotation(Tags.class) != null) {
tags.add(f);
} else {
values.add(f);
}
}
if (isTags) {
return tags;
}
return values;
}
default void setStringFieldsToEmpty(Object obj) {
Field[] fields = this.getClass().getDeclaredFields();
// tag不能为空字符串
List<Field> tagsFields = getTagsFields(fields, false);
for (Field field : tagsFields) {
if (field.getType() == String.class) {
try {
field.setAccessible(true);
field.set(obj, "");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
接口的getDatabaseName方法用于判断@TableName注解,因为taos有超级表概念,经常要跨库查询数据,所以要使用"库名.表名"查询具体表数据,其余方法反射拼接语句
实现Mapper
1.继承MP的BaseMapper接口
public interface BaseTaosMapper<T extends BaseTaosModel<T>> extends BaseMapper<T> {
/**
* 创建默认数据库
* @param baseTaosModel taos实体
*/
@Update("create database if not exists ${databaseName}")
void createDatabase(T baseTaosModel);
/**
* 创建具有过期时间的数据库
* @param baseTaosModel taos基础实体
* @param duration 过期间隔时间
* @param keep 保留数据时间
*/
@Update("create database if not exists ${baseTaosModel.databaseName} duration ${duration} keep ${keep}")
void createDatabaseDuration(T baseTaosModel,
@Param("duration")String duration,
@Param("keep")String keep);
/**
* 创建超级表
* @param baseTaosModel taos实体
*/
@Update("create stable if not exists ${databaseName}.${stableName} ${createValues}")
void createSTable(T baseTaosModel);
/**
* 删除超级表
* @param baseTaosModel taos基础类
*/
@Update("drop stable if ${databaseName}.${stableName}")
void dropSuperTable(T baseTaosModel);
/**
* 删除表
* @param baseTaosModel taos基础类
*/
@Update("drop table if exists ${databaseName}.${tableName}")
void dropTable(T baseTaosModel);
/**
* 新增数据
* @param baseTaosModel taos基础类
* @return 影响行数
*/
@Insert("insert into ${databaseName}.${tableName} using ${databaseName}.${stableName} ${insertTag} ${insertValue}")
int insert(T baseTaosModel);
@Insert("insert into ${baseTaosModel.databaseName}.${baseTaosModel.tableName} using ${baseTaosModel.databaseName}.${baseTaosModel.stableName} ${insertSql}")
int insertBatch(T baseTaosModel,@Param("insertSql") String insertSql);
/**
* 获取taos所有数据库名方法
* @return 数据库名list
*/
@Select("show databases")
List<String> showDatabases();
/**
* 获取实体类对应数据库下所有超级表名方法
* @param baseTaosModel taos实体
* @return 数据库下所有超级表list
*/
@Select("show ${databaseName}.stables")
List<String> showSTables(T baseTaosModel);
/**
* 获取实体类对应数据库下所有表名方法
* @param baseTaosModel taos实体
* @return 数据库下所有表list
*/
@Select("show ${databaseName}.tables")
List<String> showTables(T baseTaosModel);
/**
* 切换数据库
* @param baseTaosModel taos实体
*/
@Update("use ${databaseName}")
void useDatabase(T baseTaosModel);
/**
* 创建数据流
* @param streamName 流名称
* @param streamOptions 流参数
* @param stbName 超级表名称
* @param subquery 查询语句
*/
@Update("create stream if not exists ${streamName} ${streamOptions} INTO ${stbName} AS ${subquery}")
void createStream(@Param("streamName")String streamName,@Param("streamOptions")String streamOptions,
@Param("stbName")String stbName,@Param("subquery")String subquery);
}
该接口中定义了一些taos中的常用方法,通过注解实现,因为满足JDBC,所以只需实现新增等操作即可,也可以自己加入一些通用的方法,例如创建数据流,这样子类就无需多次实现
实现Service和Impl
1.继承MP的IService接口
public interface BaseTaosService<T extends BaseTaosModel<T>> extends IService<T> {
/**
* 创建默认数据库
* 重点:最好手动在taos中创建数据库 | 本方法使用于taos初始化默认创建
*
* @param baseTaosModel taos基础实体
*/
void createDatabase(T baseTaosModel);
/**
* 创建具有过期时间的数据库
* 重点:最好手动在taos中创建数据库 | 本方法使用于taos初始化默认创建
*
* @param baseTaosModel taos基础实体
* @param duration 过期间隔时间
* @param keep 保留数据时间
*/
void createDatabaseDuration(T baseTaosModel, String duration, String keep);
/**
* 创建超级表
* 重点:最好手动在taos中创建超级表 | 本方法使用于taos初始化默认创建
* 重点:如需使用,请了解@TableName规则--
* --多数据库同结构超级表请手动设置数据库
*
* @param baseTaosModel taos实体
*/
void createSTable(T baseTaosModel);
/**
* 删除超级表
*
* @param baseTaosModel taos基础类
*/
void dropSuperTable(T baseTaosModel);
/**
* 删除表
*
* @param baseTaosModel taos基础类
*/
void dropTable(T baseTaosModel);
/**
* 新增数据
*
* @param baseTaosModel taos基础类
* @return 影响行数
*/
int insert(T baseTaosModel);
/**
* 批量新增方法
* @param baseTaosModels taos基础实体类列表
* @param count 批量数据上限 需自己预估 留好容错空间,默认1000行
* @return 影响行数
*/
int insertBatch(List<T> baseTaosModels, int count);
/**
* 批量新增方法
* @param baseTaosModels taos基础实体类列表
*/
int insertBatch(List<T> baseTaosModels);
/**
* 获取taos所有数据库名方法
*
* @return 数据库名list
*/
List<String> showDatabases();
/**
* 获取实体类对应数据库下所有超级表名方法
*
* @param baseTaosModel taos实体
* @return 数据库下所有超级表list
*/
List<String> showSTables(T baseTaosModel);
/**
* 获取实体类对应数据库下所有表名方法
*
* @param baseTaosModel taos实体
* @return 数据库下所有表list
*/
List<String> showTables(T baseTaosModel);
/**
* 切换数据库
* 重点 : 当前使用restFul连接,无法切换数据库 使用前确认连接方式
*
* @param baseTaosModel taos实体
*/
void useDatabase(T baseTaosModel);
/**
* 创建流式计算方法
*
* @param streamName 流名称
* @param streamOptions 流参数
* @param stbName 表名
* @param subquery 查询语句
*/
void createStream(String streamName, String streamOptions, String stbName, String subquery);
/**
* 初始化流式计算
*/
void initStream();
}
该接口定义taos相关所需基础方法,其中建库建超级表最好手动完成,虽然测试用方法创建没有问题,但是涉及到taos的性能规划,可能有很多问题,最好根据服务器容量计算后手动创建
2.实现Impl类,继承自定义Service
@Slf4j
@DS("tdengine")
public class BaseTaosServiceImpl<M extends BaseTaosMapper<T>, T extends BaseTaosModel<T>> extends ServiceImpl<M, T> implements BaseTaosService<T> {
@Override
protected Class<T> currentMapperClass() {
return (Class<T>) this.getResolvableType().as(BaseTaosServiceImpl.class).getGeneric(0).getType();
}
@Override
protected Class<T> currentModelClass() {
return (Class<T>) this.getResolvableType().as(BaseTaosServiceImpl.class).getGeneric(1).getType();
}
@Override
public void createDatabase(T baseTaosModel) {
baseTaosModel.init(baseTaosModel);
baseMapper.createDatabase(baseTaosModel);
}
@Override
public void createDatabaseDuration(T baseTaosModel, String duration, String keep) {
baseTaosModel.init(baseTaosModel);
baseMapper.createDatabaseDuration(baseTaosModel, duration, keep);
}
@Override
public void createSTable(T baseTaosModel) {
baseTaosModel.init(baseTaosModel);
baseMapper.createDatabase(baseTaosModel);
baseMapper.createSTable(baseTaosModel);
}
@Override
public void dropSuperTable(T baseTaosModel) {
baseTaosModel.init(baseTaosModel);
baseMapper.dropSuperTable(baseTaosModel);
}
@Override
public void dropTable(T baseTaosModel) {
baseTaosModel.init(baseTaosModel);
baseMapper.dropTable(baseTaosModel);
}
@Override
public int insert(T baseTaosModel) {
baseTaosModel.init(baseTaosModel);
return baseMapper.insert(baseTaosModel);
}
@Override
public int insertBatch(List<T> list, int count) {
// 默认值设为1000
if (count == 0) {
count = 1000;
}
// 根据表名转换map
Map<String, List<T>> baseModelMap = list.stream()
.filter(baseTaosModel -> ObjectUtils.isNotEmpty(baseTaosModel.getTableName()))
.collect(Collectors.groupingBy(BaseTaosModel::getTableName));
Set<String> strings = baseModelMap.keySet();
// 不同表遍历新增
int finalCount = count;
strings.forEach(tableName -> {
List<T> baseTaosModelList = baseModelMap.get(tableName);
if (!baseTaosModelList.isEmpty()) {
// sql字段标志位
AtomicInteger i = new AtomicInteger(0);
// StringJoiner无法清除字符,所以采用StringBuilder拼接空格
StringBuilder tags = new StringBuilder();
StringBuilder values = new StringBuilder();
baseTaosModelList.forEach(baseTaosModel -> {
// 如果超过传入次数
if (i.get() > finalCount) {
String insertSql = tags.append(values).toString();
baseTaosModel.init(baseTaosModel);
baseTaosModel.setBatchSql(insertSql);
baseMapper.insertBatch(baseTaosModel, insertSql);
// i重新设施为0 | tags和values置空
i.set(0);
tags.delete(0, tags.length());
values.delete(0, values.length());
}
// 拼接新增语句
if (i.getAndIncrement() == 0) {
baseTaosModel.init(baseTaosModel);
tags.append(baseTaosModel.getInsertTag()).append(" ");
values.append(baseTaosModel.getInsertValue()).append(" ");
} else {
values.append(baseTaosModel.getValues(baseTaosModel, false)).append(" ");
}
});
String insertSql = tags.append(values).toString();
T baseTaosModel = baseTaosModelList.get(0);
baseTaosModel.init(baseTaosModel);
baseTaosModel.setBatchSql(insertSql);
baseMapper.insertBatch(baseTaosModel, insertSql);
}
});
return 0;
}
@Override
public int insertBatch(List<T> list) {
// 根据表名转换map
Map<String, List<T>> baseModelMap = list.stream()
.filter(baseTaosModel -> ObjectUtils.isNotEmpty(baseTaosModel.getTableName()))
.collect(Collectors.groupingBy(BaseTaosModel::getTableName));
Set<String> strings = baseModelMap.keySet();
// 不同表遍历新增
strings.forEach(tableName -> {
List<T> baseTaosModelList = baseModelMap.get(tableName);
if (!baseTaosModelList.isEmpty()) {
// sql字段标志位
AtomicInteger i = new AtomicInteger(0);
// 拼接字段
StringJoiner tags = new StringJoiner(" ");
StringJoiner values = new StringJoiner(" ");
baseTaosModelList.forEach(baseTaosModel -> {
// 最大字节长度
int maxLength = 1000000;
// 预测长度
if (values.length() * 3 > maxLength) {
String insertSql = tags.merge(values).toString();
baseTaosModel.init(baseTaosModel);
baseTaosModel.setBatchSql(insertSql);
baseMapper.insertBatch(baseTaosModel, insertSql);
// i重新设施为0 | tags和values置空
i.set(0);
tags.setEmptyValue("");
values.setEmptyValue("");
}
// 拼接新增语句
if (i.getAndIncrement() == 0) {
baseTaosModel.init(baseTaosModel);
tags.add(baseTaosModel.getInsertTag());
values.add(baseTaosModel.getInsertValue());
} else {
values.add(baseTaosModel.getValues(baseTaosModel, false));
}
});
String insertSql = tags.merge(values).toString();
T baseTaosModel = baseTaosModelList.get(0);
baseTaosModel.init(baseTaosModel);
baseTaosModel.setBatchSql(insertSql);
baseMapper.insertBatch(baseTaosModel, insertSql);
}
});
return 0;
}
@Override
public List<String> showDatabases() {
return baseMapper.showDatabases();
}
@Override
public List<String> showSTables(T baseTaosModel) {
return baseMapper.showSTables(baseTaosModel);
}
@Override
public List<String> showTables(T baseTaosModel) {
return baseMapper.showTables(baseTaosModel);
}
@Override
public void useDatabase(T baseTaosModel) {
baseMapper.useDatabase(baseTaosModel);
}
@Override
public void createStream(String streamName, String streamOptions, String stbName, String subquery) {
baseMapper.createStream(streamName, streamOptions, stbName, subquery);
}
@Override
public void initStream() {
//原始数据数据库名
String originSource = TDengineDatabaseParamEnums.MONTH_THREE.getDatabaseName() + "." + TDengineConstants.TABLE_NUMERICAL_NAME;
TDengineDatabaseParamEnums[] values = TDengineDatabaseParamEnums.values();
for (TDengineDatabaseParamEnums value : values) {
String databaseName = value.getDatabaseName();
if (databaseName.equals(TDengineDatabaseParamEnums.MONTH_THREE.getDatabaseName())) {
continue;
}
//原始数据源
List<String> aggregateTimeList = StringUtil.getAggregateTimeByDatabaseName(databaseName);
aggregateTimeList.forEach(aggregateTime -> {
String streamName = TDengineConstants.STREAM_NAME_PREFIX + aggregateTime;
String stbName = TDengineConstants.STREAM_TABLE_PREFIX + aggregateTime;
//查询内容
String subquery = StrUtil.format(TDengineSqlConstants.STREAM_SUBQUERY, originSource, aggregateTime);
createStream(streamName, null, stbName, subquery);
});
}
}
}
该方法实现了taos的增删改等操作,其中如果要使用自定义方法需要先调用init获取库名表名等字段,然后执行,至此整个Taos的MP操作已经实现完毕
注意,需要重构currentMapperClass和currentModelClass用以返回当前的mapper接口和自定义的model,否则会获取上一级的model,将自定义的实体转为字符
使用示例
实现后整体流程和Mysql使用MybatisPlus基本一致,只是将继承接口换为我们自己实现的
1.创建一个实体类
@EqualsAndHashCode(callSuper = true)
@Data
@TableName(value = "test.test1")
@AllArgsConstructor
@NoArgsConstructor
public class Test extends BaseTaosModel<Test> {
@ApiModelProperty("int值")
Integer intValue;
@ApiModelProperty("String值")
String strValue;
@Tags
@ApiModelProperty("tag的id")
String eqpId;
}
这里模拟的是设备的数据采集表,通过采集软件获取数据后存储,tag通过设备id绑定
其中加入@Tags注解后会自动把eqpId转为Tag列,每个子表Tag列不可修改,慎重
2.创建mapper
@DS("tdengine")
public interface TestTaosMapper extends BaseTaosMapper<Test> {
}
注意使用@DS实现动态数据源切换
3.创建service接口
public interface TestTaosService extends BaseTaosService<Test> {
}
4.创建impl实现类
@Service
public class TestTaosServiceImpl extends BaseTaosServiceImpl<TestTaosMapper,Test> implements TestTaosService{
}
5.调用方法
@Slf4j
@Component
public class TestDemo {
@Resource
private TestTaosServiceImpl testTaosService;
@Bean
public void test(){
// 创建实体
Test test = new Test();
test.setIntValue(123);
test.setStrValue("123");
test.setEqpId("112233445566");
// 设置子表名
test.setTableName("test1_112233445566");
testTaosService.insert(test);
List<Test> list = testTaosService.lambdaQuery()
.eq(Test::getEqpId, "112233445566")
.list();
list.forEach(item->{
log.info("数据值:{}",item.getIntValue());
log.info("字符值:{}",item.getStrValue());
});
}
}
到这即可成功添加数据,查询数据可以直接使用lambdaQuery或其他Mybatis查询
注意,这里查询是查询的超级表,建议使用3.2.0或更高版本,否则查询速度很慢
批量新增等其他可以自行测试
查询速度优化
文章中的基础查询主要使用于高版本taos中(3.2.0及以上),高版本相较于低版本查询速度有很快优化,3.2.0测试单超级表300万数据通过tag条件查询1秒内查出一个子表所有数据,因此可以直接使用lambdaQuery等方式直接查询,添加条件即可,如果有更高的性能要求可以自己实现实体下mapper语句,优化示例
@Mapper
@DS("tdengine")
public interface ElmStatusDurationMapper extends BaseTaosMapper<StatusDuration> {
@Select("SELECT * FROM equipment_status.equipment_status_duration WHERE tenant_id = #{tenantId} and ( ts >= #{startTime} and ts <= #{endTime} ) or ( end_time >= #{startTime} and end_time <= #{endTime} ) partition by eqp_id")
List<StatusDuration> getStatus(String tenantId,Long startTime,Long endTime);
}
这里通过自己给这个实体单独创建一个mapper方法优化速度,orderby会极大影响查询速度,所以用partition by优化,有其余需求可以自己实现,注解或xml都可
总结
整个代码是去年实际项目中用到taos批量新增,所以决定整合MP框架实现的
git地址:https://github.com/Andlzz/Tdengine-demo