dd
我用的influxDB 1.8版本高版本我不清楚,因为1.x版本便于写sq语法。
influxDB时序库默认使用 UTC时区,并且无法通过配置来修改这个时区,很多文档说在查询数据的时候加上 tz('Asia/Shanghai')。
而这个在Windows环境下的influxdb会报错:
ERR: error parsing query: unable to find time zone Asia/Shanghai
首先我们来看下infulxdb数据库存储的time数据,我发现是以时间戳来存储的。
但是我们Java查询出来的时间是UTC时间格式
以上是问题描述,以下是解决思路。
pom文件
<!-- 时序库-->
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>2.15</version>
</dependency>
我发现influxdb提供了时间工具类。解决思路先将2023-05-26T08:47:03.6147144Z 这种UTC格式转成 时间戳 再赋值给Date()对象转成CST时区时间;
UTC时间字符串转时间戳
long time = TimeUtil.fromInfluxDBTimeFormat("2023-05-30T02:09:05.3138263Z");
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//这样就得到了 2023-05-30 11:01:23
String timeStr = simpleDateFormat.format(new Date(time));
粘一段获取到influxdb数据后映射给Java对象的代码。
/**
* 查询,返回对象的list集合
*
* @param query
* @return
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public <T> List<T> fetchResults(String query, Class<?> clasz) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List results = new ArrayList<>();
QueryResult queryResult = influxDB.query(new Query(query, Configurations.DATABASE_NAME));
queryResult.getResults().forEach(result -> {
result.getSeries().forEach(serial -> {
List<String> columns = serial.getColumns();
int fieldSize = columns.size();
serial.getValues().forEach(value -> {
Object obj = null;
try {
obj = clasz.newInstance();
for (int i = 0; i < fieldSize; i++) {
String fieldName = columns.get(i);
Field field = clasz.getDeclaredField(fieldName);
field.setAccessible(true);
Class<?> type = field.getType();
if (type == float.class) {
field.set(obj, Float.valueOf(value.get(i).toString()));
} else if (type == Long.class) {
field.set(obj, Long.valueOf(value.get(i).toString()));
} else if (type == Double.class) {
field.set(obj, Double.valueOf(value.get(i).toString()));
} else {
long time = TimeUtil.fromInfluxDBTimeFormat(value.get(i).toString());
if ("time".equals(fieldName)) {
field.set(obj, simpleDateFormat.format(new Date(time)));
} else {
field.set(obj, value.get(i));
}
}
}
} catch (NoSuchFieldException | SecurityException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
results.add(obj);
});
});
});
return results;
}
最后还有个问题,因为influxdb在插入数据的时候是按照纳秒计算的,那么我们转成毫秒后时间会有误差,所以我们在插入数据的时候手动给time字段赋值并设置按毫秒计算。
主要是这一段:
//手动给time字段赋值,并按毫秒进行计算
builder.time(times, TimeUnit.MILLISECONDS);
/**
* 批量新增,方法一
*/
public void insertBatchByRecords(List<?> records) {
long times = System.currentTimeMillis();
List<String> lines = new ArrayList<>();
records.forEach(record -> {
Class<?> clasz = record.getClass();
//获取度量
Measurement measurement = clasz.getAnnotation(Measurement.class);
//构建
Point.Builder builder = Point.measurement(measurement.name());
Field[] fieldArray = clasz.getDeclaredFields();
Column column = null;
for (Field field : fieldArray) {
try {
column = field.getAnnotation(Column.class);
//设置属性可操作
field.setAccessible(true);
if (column.tag()) {
//tag属性只能存储String类型
builder.tag(column.name(), field.get(record).toString());
} else {
//设置field
if (field.get(record) != null) {
Class<?> type = field.getType();
if (type == Long.class) {
builder.addField(column.name(), field.getLong(record));
} else if (type.equals(Double.class)) {
builder.addField(column.name(), Double.valueOf(field.get(record).toString()));
} else if (type == Float.class) {
builder.addField(column.name(), Float.valueOf(field.get(record).toString()));
} else {
builder.addField(column.name(), field.get(record).toString());
}
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
//手动给time字段赋值,并按毫秒进行计算
builder.time(times, TimeUnit.MILLISECONDS);
lines.add(builder.build().lineProtocol());
});
influxDB.write(lines);
}
那么在查询的时候我们也可以通过工具类将从前端拿到的时间参数转成 UTC时间格式的字符串来进行sql查询。
//构建查询语句,返回QueryResult
StringBuilder querySql = new StringBuilder("select * from tracer_angle where 1=1 ");
querySql.append("and time >= '").append(TimeUtil.toInfluxDBTimeFormat(startTime.getTime())).append("' ");
querySql.append("and time <= '").append(TimeUtil.toInfluxDBTimeFormat(endTime.getTime())).append("' ");