added support batch telemetry
This commit is contained in:
parent
0b6a68ad30
commit
00ff95bccf
@ -204,6 +204,18 @@ sql:
|
|||||||
batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}"
|
batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}"
|
||||||
batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}"
|
batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}"
|
||||||
stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}"
|
stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}"
|
||||||
|
ts:
|
||||||
|
batch_size: "${SQL_TS_BATCH_SIZE:10000}"
|
||||||
|
batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}"
|
||||||
|
stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}"
|
||||||
|
ts_latest:
|
||||||
|
batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}"
|
||||||
|
batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}"
|
||||||
|
stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}"
|
||||||
|
ts_timescale:
|
||||||
|
batch_size: "${SQL_TS_TIMESCALE_BATCH_SIZE:10000}"
|
||||||
|
batch_max_delay: "${SQL_TS_TIMESCALE_BATCH_MAX_DELAY_MS:100}"
|
||||||
|
stats_print_interval_ms: "${SQL_TS_TIMESCALE_BATCH_STATS_PRINT_MS:10000}"
|
||||||
# Specify whether to remove null characters from strValue of attributes and timeseries before insert
|
# Specify whether to remove null characters from strValue of attributes and timeseries before insert
|
||||||
remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}"
|
remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}"
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.STRING_VALUE_COLUM
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public abstract class AbsractTsKvEntity {
|
public abstract class AbstractTsKvEntity {
|
||||||
|
|
||||||
protected static final String SUM = "SUM";
|
protected static final String SUM = "SUM";
|
||||||
protected static final String AVG = "AVG";
|
protected static final String AVG = "AVG";
|
||||||
@ -80,7 +80,7 @@ public abstract class AbsractTsKvEntity {
|
|||||||
|
|
||||||
protected static boolean isAllNull(Object... args) {
|
protected static boolean isAllNull(Object... args) {
|
||||||
for (Object arg : args) {
|
for (Object arg : args) {
|
||||||
if(arg != null) {
|
if (arg != null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ import org.springframework.util.StringUtils;
|
|||||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||||
import org.thingsboard.server.dao.model.ToData;
|
import org.thingsboard.server.dao.model.ToData;
|
||||||
import org.thingsboard.server.dao.model.sql.AbsractTsKvEntity;
|
import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.ColumnResult;
|
import javax.persistence.ColumnResult;
|
||||||
@ -115,7 +115,7 @@ import static org.thingsboard.server.dao.sqlts.timescale.AggregationRepository.F
|
|||||||
resultSetMapping = "timescaleCountMapping"
|
resultSetMapping = "timescaleCountMapping"
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
public final class TimescaleTsKvEntity extends AbsractTsKvEntity implements ToData<TsKvEntry> {
|
public final class TimescaleTsKvEntity extends AbstractTsKvEntity implements ToData<TsKvEntry> {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Column(name = TENANT_ID_COLUMN)
|
@Column(name = TENANT_ID_COLUMN)
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.EntityType;
|
|||||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||||
import org.thingsboard.server.dao.model.ToData;
|
import org.thingsboard.server.dao.model.ToData;
|
||||||
import org.thingsboard.server.dao.model.sql.AbsractTsKvEntity;
|
import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
@ -37,7 +37,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN;
|
|||||||
@Entity
|
@Entity
|
||||||
@Table(name = "ts_kv")
|
@Table(name = "ts_kv")
|
||||||
@IdClass(TsKvCompositeKey.class)
|
@IdClass(TsKvCompositeKey.class)
|
||||||
public final class TsKvEntity extends AbsractTsKvEntity implements ToData<TsKvEntry> {
|
public final class TsKvEntity extends AbstractTsKvEntity implements ToData<TsKvEntry> {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
|
|||||||
@ -20,7 +20,7 @@ import org.thingsboard.server.common.data.EntityType;
|
|||||||
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
|
||||||
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
import org.thingsboard.server.common.data.kv.TsKvEntry;
|
||||||
import org.thingsboard.server.dao.model.ToData;
|
import org.thingsboard.server.dao.model.ToData;
|
||||||
import org.thingsboard.server.dao.model.sql.AbsractTsKvEntity;
|
import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
@ -37,7 +37,7 @@ import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN;
|
|||||||
@Entity
|
@Entity
|
||||||
@Table(name = "ts_kv_latest")
|
@Table(name = "ts_kv_latest")
|
||||||
@IdClass(TsKvLatestCompositeKey.class)
|
@IdClass(TsKvLatestCompositeKey.class)
|
||||||
public final class TsKvLatestEntity extends AbsractTsKvEntity implements ToData<TsKvEntry> {
|
public final class TsKvLatestEntity extends AbstractTsKvEntity implements ToData<TsKvEntry> {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
|
|||||||
@ -92,8 +92,8 @@ public class TbSqlBlockingQueue<E> implements TbSqlQueue<E> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
logExecutor.scheduleAtFixedRate(() -> {
|
logExecutor.scheduleAtFixedRate(() -> {
|
||||||
log.info("Attributes queueSize [{}] totalAdded [{}] totalSaved [{}] totalFailed [{}]",
|
log.info("[{}] queueSize [{}] totalAdded [{}] totalSaved [{}] totalFailed [{}]",
|
||||||
queue.size(), addedCount.getAndSet(0), savedCount.getAndSet(0), failedCount.getAndSet(0));
|
params.getLogName(), queue.size(), addedCount.getAndSet(0), savedCount.getAndSet(0), failedCount.getAndSet(0));
|
||||||
}, params.getStatsPrintIntervalMs(), params.getStatsPrintIntervalMs(), TimeUnit.MILLISECONDS);
|
}, params.getStatsPrintIntervalMs(), params.getStatsPrintIntervalMs(), TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,8 +15,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.sqlts;
|
package org.thingsboard.server.dao.sqlts;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
@ -57,6 +60,12 @@ public abstract class AbstractInsertRepository {
|
|||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
protected EntityManager entityManager;
|
protected EntityManager entityManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
protected TransactionTemplate transactionTemplate;
|
||||||
|
|
||||||
protected static String getInsertOrUpdateStringHsql(String tableName, String constraint, String value, String nullValues) {
|
protected static String getInsertOrUpdateStringHsql(String tableName, String constraint, String value, String nullValues) {
|
||||||
return "MERGE INTO " + tableName + " USING(VALUES :entity_type, :entity_id, :key, :ts, :" + value + ") A (entity_type, entity_id, key, ts, " + value + ") ON " + constraint + " WHEN MATCHED THEN UPDATE SET " + tableName + "." + value + " = A." + value + ", " + tableName + ".ts = A.ts," + nullValues + "WHEN NOT MATCHED THEN INSERT (entity_type, entity_id, key, ts, " + value + ") VALUES (A.entity_type, A.entity_id, A.key, A.ts, A." + value + ")";
|
return "MERGE INTO " + tableName + " USING(VALUES :entity_type, :entity_id, :key, :ts, :" + value + ") A (entity_type, entity_id, key, ts, " + value + ") ON " + constraint + " WHEN MATCHED THEN UPDATE SET " + tableName + "." + value + " = A." + value + ", " + tableName + ".ts = A.ts," + nullValues + "WHEN NOT MATCHED THEN INSERT (entity_type, entity_id, key, ts, " + value + ") VALUES (A.entity_type, A.entity_id, A.key, A.ts, A." + value + ")";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,11 +19,15 @@ import org.springframework.data.jpa.repository.Modifying;
|
|||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestEntity;
|
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public abstract class AbstractLatestInsertRepository extends AbstractInsertRepository {
|
public abstract class AbstractLatestInsertRepository extends AbstractInsertRepository {
|
||||||
|
|
||||||
public abstract void saveOrUpdate(TsKvLatestEntity entity);
|
public abstract void saveOrUpdate(TsKvLatestEntity entity);
|
||||||
|
|
||||||
|
public abstract void saveOrUpdate(List<TsKvLatestEntity> entities);
|
||||||
|
|
||||||
protected void processSaveOrUpdate(TsKvLatestEntity entity, String requestBoolValue, String requestStrValue, String requestLongValue, String requestDblValue) {
|
protected void processSaveOrUpdate(TsKvLatestEntity entity, String requestBoolValue, String requestStrValue, String requestLongValue, String requestDblValue) {
|
||||||
if (entity.getBooleanValue() != null) {
|
if (entity.getBooleanValue() != null) {
|
||||||
saveOrUpdateBoolean(entity, requestBoolValue);
|
saveOrUpdateBoolean(entity, requestBoolValue);
|
||||||
|
|||||||
@ -17,13 +17,17 @@ package org.thingsboard.server.dao.sqlts;
|
|||||||
|
|
||||||
import org.springframework.data.jpa.repository.Modifying;
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.thingsboard.server.dao.model.sql.AbsractTsKvEntity;
|
import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public abstract class AbstractTimeseriesInsertRepository<T extends AbsractTsKvEntity> extends AbstractInsertRepository {
|
public abstract class AbstractTimeseriesInsertRepository<T extends AbstractTsKvEntity> extends AbstractInsertRepository {
|
||||||
|
|
||||||
public abstract void saveOrUpdate(T entity);
|
public abstract void saveOrUpdate(T entity);
|
||||||
|
|
||||||
|
public abstract void saveOrUpdate(List<T> entities);
|
||||||
|
|
||||||
protected void processSaveOrUpdate(T entity, String requestBoolValue, String requestStrValue, String requestLongValue, String requestDblValue) {
|
protected void processSaveOrUpdate(T entity, String requestBoolValue, String requestStrValue, String requestLongValue, String requestDblValue) {
|
||||||
if (entity.getBooleanValue() != null) {
|
if (entity.getBooleanValue() != null) {
|
||||||
saveOrUpdateBoolean(entity, requestBoolValue);
|
saveOrUpdateBoolean(entity, requestBoolValue);
|
||||||
|
|||||||
@ -15,13 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.sqlts.timescale;
|
package org.thingsboard.server.dao.sqlts.timescale;
|
||||||
|
|
||||||
|
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.thingsboard.server.dao.model.sqlts.timescale.TimescaleTsKvEntity;
|
import org.thingsboard.server.dao.model.sqlts.timescale.TimescaleTsKvEntity;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
||||||
import org.thingsboard.server.dao.util.PsqlDao;
|
import org.thingsboard.server.dao.util.PsqlDao;
|
||||||
import org.thingsboard.server.dao.util.TimescaleDBTsDao;
|
import org.thingsboard.server.dao.util.TimescaleDBTsDao;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@TimescaleDBTsDao
|
@TimescaleDBTsDao
|
||||||
@PsqlDao
|
@PsqlDao
|
||||||
@Repository
|
@Repository
|
||||||
@ -30,14 +39,123 @@ public class TimescaleInsertRepository extends AbstractTimeseriesInsertRepositor
|
|||||||
|
|
||||||
private static final String INSERT_OR_UPDATE_BOOL_STATEMENT = getInsertOrUpdateString(BOOL_V, PSQL_ON_BOOL_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_BOOL_STATEMENT = getInsertOrUpdateString(BOOL_V, PSQL_ON_BOOL_VALUE_UPDATE_SET_NULLS);
|
||||||
private static final String INSERT_OR_UPDATE_STR_STATEMENT = getInsertOrUpdateString(STR_V, PSQL_ON_STR_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_STR_STATEMENT = getInsertOrUpdateString(STR_V, PSQL_ON_STR_VALUE_UPDATE_SET_NULLS);
|
||||||
private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateString(LONG_V , PSQL_ON_LONG_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateString(LONG_V, PSQL_ON_LONG_VALUE_UPDATE_SET_NULLS);
|
||||||
private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateString(DBL_V, PSQL_ON_DBL_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateString(DBL_V, PSQL_ON_DBL_VALUE_UPDATE_SET_NULLS);
|
||||||
|
|
||||||
|
private static final String BATCH_UPDATE =
|
||||||
|
"UPDATE tenant_ts_kv SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ? WHERE entity_type = ? AND entity_id = ? and key = ? and ts = ?";
|
||||||
|
|
||||||
|
|
||||||
|
private static final String INSERT_OR_UPDATE =
|
||||||
|
"INSERT INTO tenant_ts_kv (tenant_id, entity_id, key, ts, bool_v, str_v, long_v, dbl_v) VALUES(?, ?, ?, ?, ?, ?, ?, ?) " +
|
||||||
|
"ON CONFLICT (tenant_id, entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?;";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveOrUpdate(TimescaleTsKvEntity entity) {
|
public void saveOrUpdate(TimescaleTsKvEntity entity) {
|
||||||
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOrUpdate(List<TimescaleTsKvEntity> entities) {
|
||||||
|
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
@Override
|
||||||
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
int[] result = jdbcTemplate.batchUpdate(BATCH_UPDATE, new BatchPreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
|
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||||
|
|
||||||
|
if (entities.get(i).getBooleanValue() != null) {
|
||||||
|
ps.setBoolean(1, entities.get(i).getBooleanValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(1, Types.BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(2, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
|
||||||
|
if (entities.get(i).getLongValue() != null) {
|
||||||
|
ps.setLong(3, entities.get(i).getLongValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(3, Types.BIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entities.get(i).getDoubleValue() != null) {
|
||||||
|
ps.setDouble(4, entities.get(i).getDoubleValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(4, Types.DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(5, entities.get(i).getTenantId());
|
||||||
|
ps.setString(6, entities.get(i).getEntityId());
|
||||||
|
ps.setString(7, entities.get(i).getKey());
|
||||||
|
ps.setLong(8, entities.get(i).getTs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatchSize() {
|
||||||
|
return entities.size();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
int updatedCount = 0;
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
if (result[i] == 0) {
|
||||||
|
updatedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TimescaleTsKvEntity> insertEntities = new ArrayList<>(updatedCount);
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
if (result[i] == 0) {
|
||||||
|
insertEntities.add(entities.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
|
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||||
|
ps.setString(1, entities.get(i).getTenantId());
|
||||||
|
ps.setString(2, entities.get(i).getEntityId());
|
||||||
|
ps.setString(3, entities.get(i).getKey());
|
||||||
|
ps.setLong(4, entities.get(i).getTs());
|
||||||
|
|
||||||
|
if (entities.get(i).getBooleanValue() != null) {
|
||||||
|
ps.setBoolean(5, entities.get(i).getBooleanValue());
|
||||||
|
ps.setBoolean(9, entities.get(i).getBooleanValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(5, Types.BOOLEAN);
|
||||||
|
ps.setNull(9, Types.BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(6, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
ps.setString(10, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
|
||||||
|
|
||||||
|
if (entities.get(i).getLongValue() != null) {
|
||||||
|
ps.setLong(7, entities.get(i).getLongValue());
|
||||||
|
ps.setLong(11, entities.get(i).getLongValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(7, Types.BIGINT);
|
||||||
|
ps.setNull(11, Types.BIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entities.get(i).getDoubleValue() != null) {
|
||||||
|
ps.setDouble(8, entities.get(i).getDoubleValue());
|
||||||
|
ps.setDouble(12, entities.get(i).getDoubleValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(8, Types.DOUBLE);
|
||||||
|
ps.setNull(12, Types.DOUBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatchSize() {
|
||||||
|
return insertEntities.size();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void saveOrUpdateBoolean(TimescaleTsKvEntity entity, String query) {
|
protected void saveOrUpdateBoolean(TimescaleTsKvEntity entity, String query) {
|
||||||
entityManager.createNativeQuery(query)
|
entityManager.createNativeQuery(query)
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -36,11 +37,16 @@ import org.thingsboard.server.common.data.kv.TsKvEntry;
|
|||||||
import org.thingsboard.server.common.data.kv.TsKvQuery;
|
import org.thingsboard.server.common.data.kv.TsKvQuery;
|
||||||
import org.thingsboard.server.dao.DaoUtil;
|
import org.thingsboard.server.dao.DaoUtil;
|
||||||
import org.thingsboard.server.dao.model.sqlts.timescale.TimescaleTsKvEntity;
|
import org.thingsboard.server.dao.model.sqlts.timescale.TimescaleTsKvEntity;
|
||||||
|
import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
|
||||||
|
import org.thingsboard.server.dao.sql.TbSqlBlockingQueue;
|
||||||
|
import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractSqlTimeseriesDao;
|
import org.thingsboard.server.dao.sqlts.AbstractSqlTimeseriesDao;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
||||||
import org.thingsboard.server.dao.timeseries.TimeseriesDao;
|
import org.thingsboard.server.dao.timeseries.TimeseriesDao;
|
||||||
import org.thingsboard.server.dao.util.TimescaleDBTsDao;
|
import org.thingsboard.server.dao.util.TimescaleDBTsDao;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -66,6 +72,39 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AbstractTimeseriesInsertRepository insertRepository;
|
private AbstractTimeseriesInsertRepository insertRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ScheduledLogExecutorComponent logExecutor;
|
||||||
|
|
||||||
|
@Value("${sql.ts_timescale.batch_size:1000}")
|
||||||
|
private int batchSize;
|
||||||
|
|
||||||
|
@Value("${sql.ts_timescale.batch_max_delay:100}")
|
||||||
|
private long maxDelay;
|
||||||
|
|
||||||
|
@Value("${sql.ts_timescale.stats_print_interval_ms:1000}")
|
||||||
|
private long statsPrintIntervalMs;
|
||||||
|
|
||||||
|
private TbSqlBlockingQueue<TimescaleTsKvEntity> queue;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
TbSqlBlockingQueueParams params = TbSqlBlockingQueueParams.builder()
|
||||||
|
.logName("TS Timescale")
|
||||||
|
.batchSize(batchSize)
|
||||||
|
.maxDelay(maxDelay)
|
||||||
|
.statsPrintIntervalMs(statsPrintIntervalMs)
|
||||||
|
.build();
|
||||||
|
queue = new TbSqlBlockingQueue<>(params);
|
||||||
|
queue.init(logExecutor, v -> insertRepository.saveOrUpdate(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
private void destroy() {
|
||||||
|
if (queue != null) {
|
||||||
|
queue.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
|
public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
|
||||||
return processFindAllAsync(tenantId, entityId, queries);
|
return processFindAllAsync(tenantId, entityId, queries);
|
||||||
@ -126,11 +165,7 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
|
|||||||
entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
|
entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
|
||||||
entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
|
entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
|
||||||
entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
|
entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
|
||||||
log.trace("Saving entity to timescale db: {}", entity);
|
return queue.add(entity);
|
||||||
return insertService.submit(() -> {
|
|
||||||
insertRepository.saveOrUpdate(entity);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -209,7 +244,7 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements
|
|||||||
if (!CollectionUtils.isEmpty(timescaleTsKvEntities)) {
|
if (!CollectionUtils.isEmpty(timescaleTsKvEntities)) {
|
||||||
List<Optional<TsKvEntry>> result = new ArrayList<>();
|
List<Optional<TsKvEntry>> result = new ArrayList<>();
|
||||||
timescaleTsKvEntities.forEach(entity -> {
|
timescaleTsKvEntities.forEach(entity -> {
|
||||||
if(entity != null && entity.isNotEmpty()) {
|
if (entity != null && entity.isNotEmpty()) {
|
||||||
entity.setEntityId(entityIdStr);
|
entity.setEntityId(entityIdStr);
|
||||||
entity.setTenantId(tenantIdStr);
|
entity.setTenantId(tenantIdStr);
|
||||||
entity.setKey(key);
|
entity.setKey(key);
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import org.thingsboard.server.dao.sqlts.AbstractLatestInsertRepository;
|
|||||||
import org.thingsboard.server.dao.util.HsqlDao;
|
import org.thingsboard.server.dao.util.HsqlDao;
|
||||||
import org.thingsboard.server.dao.util.SqlTsDao;
|
import org.thingsboard.server.dao.util.SqlTsDao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SqlTsDao
|
@SqlTsDao
|
||||||
@HsqlDao
|
@HsqlDao
|
||||||
@Repository
|
@Repository
|
||||||
@ -40,6 +42,11 @@ public class HsqlLatestInsertRepository extends AbstractLatestInsertRepository {
|
|||||||
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOrUpdate(List<TsKvLatestEntity> entities) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void saveOrUpdateBoolean(TsKvLatestEntity entity, String query) {
|
protected void saveOrUpdateBoolean(TsKvLatestEntity entity, String query) {
|
||||||
entityManager.createNativeQuery(query)
|
entityManager.createNativeQuery(query)
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
|||||||
import org.thingsboard.server.dao.util.HsqlDao;
|
import org.thingsboard.server.dao.util.HsqlDao;
|
||||||
import org.thingsboard.server.dao.util.SqlTsDao;
|
import org.thingsboard.server.dao.util.SqlTsDao;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SqlTsDao
|
@SqlTsDao
|
||||||
@HsqlDao
|
@HsqlDao
|
||||||
@Repository
|
@Repository
|
||||||
@ -40,6 +42,11 @@ public class HsqlTimeseriesInsertRepository extends AbstractTimeseriesInsertRepo
|
|||||||
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOrUpdate(List<TsKvEntity> entities) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void saveOrUpdateBoolean(TsKvEntity entity, String query) {
|
protected void saveOrUpdateBoolean(TsKvEntity entity, String query) {
|
||||||
entityManager.createNativeQuery(query)
|
entityManager.createNativeQuery(query)
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ListenableFuture;
|
|||||||
import com.google.common.util.concurrent.SettableFuture;
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -38,6 +39,9 @@ import org.thingsboard.server.dao.DaoUtil;
|
|||||||
import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
|
import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
|
||||||
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestCompositeKey;
|
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestCompositeKey;
|
||||||
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestEntity;
|
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestEntity;
|
||||||
|
import org.thingsboard.server.dao.sql.ScheduledLogExecutorComponent;
|
||||||
|
import org.thingsboard.server.dao.sql.TbSqlBlockingQueue;
|
||||||
|
import org.thingsboard.server.dao.sql.TbSqlBlockingQueueParams;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractLatestInsertRepository;
|
import org.thingsboard.server.dao.sqlts.AbstractLatestInsertRepository;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractSqlTimeseriesDao;
|
import org.thingsboard.server.dao.sqlts.AbstractSqlTimeseriesDao;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
||||||
@ -46,6 +50,8 @@ import org.thingsboard.server.dao.timeseries.TimeseriesDao;
|
|||||||
import org.thingsboard.server.dao.util.SqlTsDao;
|
import org.thingsboard.server.dao.util.SqlTsDao;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -73,6 +79,63 @@ public class JpaTimeseriesDao extends AbstractSqlTimeseriesDao implements Timese
|
|||||||
@Autowired
|
@Autowired
|
||||||
private AbstractLatestInsertRepository insertLatestRepository;
|
private AbstractLatestInsertRepository insertLatestRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ScheduledLogExecutorComponent logExecutor;
|
||||||
|
|
||||||
|
@Value("${sql.ts.batch_size:1000}")
|
||||||
|
private int tsBatchSize;
|
||||||
|
|
||||||
|
@Value("${sql.ts.batch_max_delay:100}")
|
||||||
|
private long tsMaxDelay;
|
||||||
|
|
||||||
|
@Value("${sql.ts.stats_print_interval_ms:1000}")
|
||||||
|
private long tsStatsPrintIntervalMs;
|
||||||
|
|
||||||
|
@Value("${sql.ts_latest.batch_size:1000}")
|
||||||
|
private int tsLatestBatchSize;
|
||||||
|
|
||||||
|
@Value("${sql.ts_latest.batch_max_delay:100}")
|
||||||
|
private long tsLatestMaxDelay;
|
||||||
|
|
||||||
|
@Value("${sql.ts_latest.stats_print_interval_ms:1000}")
|
||||||
|
private long tsLatestStatsPrintIntervalMs;
|
||||||
|
|
||||||
|
private TbSqlBlockingQueue<TsKvEntity> tsQueue;
|
||||||
|
private TbSqlBlockingQueue<TsKvLatestEntity> tsLatestQueue;
|
||||||
|
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
private void init() {
|
||||||
|
TbSqlBlockingQueueParams tsParams = TbSqlBlockingQueueParams.builder()
|
||||||
|
.logName("TS")
|
||||||
|
.batchSize(tsBatchSize)
|
||||||
|
.maxDelay(tsMaxDelay)
|
||||||
|
.statsPrintIntervalMs(tsStatsPrintIntervalMs)
|
||||||
|
.build();
|
||||||
|
tsQueue = new TbSqlBlockingQueue<>(tsParams);
|
||||||
|
tsQueue.init(logExecutor, v -> insertRepository.saveOrUpdate(v));
|
||||||
|
|
||||||
|
TbSqlBlockingQueueParams tsLatestParams = TbSqlBlockingQueueParams.builder()
|
||||||
|
.logName("TS Latest")
|
||||||
|
.batchSize(tsLatestBatchSize)
|
||||||
|
.maxDelay(tsLatestMaxDelay)
|
||||||
|
.statsPrintIntervalMs(tsLatestStatsPrintIntervalMs)
|
||||||
|
.build();
|
||||||
|
tsLatestQueue = new TbSqlBlockingQueue<>(tsLatestParams);
|
||||||
|
tsLatestQueue.init(logExecutor, v -> insertLatestRepository.saveOrUpdate(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
private void destroy() {
|
||||||
|
if (tsQueue != null) {
|
||||||
|
tsQueue.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tsLatestQueue != null) {
|
||||||
|
tsLatestQueue.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
|
public ListenableFuture<List<TsKvEntry>> findAllAsync(TenantId tenantId, EntityId entityId, List<ReadTsKvQuery> queries) {
|
||||||
return processFindAllAsync(tenantId, entityId, queries);
|
return processFindAllAsync(tenantId, entityId, queries);
|
||||||
@ -266,10 +329,7 @@ public class JpaTimeseriesDao extends AbstractSqlTimeseriesDao implements Timese
|
|||||||
entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
|
entity.setLongValue(tsKvEntry.getLongValue().orElse(null));
|
||||||
entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
|
entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
|
||||||
log.trace("Saving entity: {}", entity);
|
log.trace("Saving entity: {}", entity);
|
||||||
return insertService.submit(() -> {
|
return tsQueue.add(entity);
|
||||||
insertRepository.saveOrUpdate(entity);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -288,10 +348,7 @@ public class JpaTimeseriesDao extends AbstractSqlTimeseriesDao implements Timese
|
|||||||
latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
|
latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null));
|
||||||
latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null));
|
latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null));
|
||||||
latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
|
latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null));
|
||||||
return insertService.submit(() -> {
|
return tsLatestQueue.add(latestEntity);
|
||||||
insertLatestRepository.saveOrUpdate(latestEntity);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -15,13 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.sqlts.ts;
|
package org.thingsboard.server.dao.sqlts.ts;
|
||||||
|
|
||||||
|
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestEntity;
|
import org.thingsboard.server.dao.model.sqlts.ts.TsKvLatestEntity;
|
||||||
import org.thingsboard.server.dao.sqlts.AbstractLatestInsertRepository;
|
import org.thingsboard.server.dao.sqlts.AbstractLatestInsertRepository;
|
||||||
import org.thingsboard.server.dao.util.PsqlDao;
|
import org.thingsboard.server.dao.util.PsqlDao;
|
||||||
import org.thingsboard.server.dao.util.SqlTsDao;
|
import org.thingsboard.server.dao.util.SqlTsDao;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SqlTsDao
|
@SqlTsDao
|
||||||
@PsqlDao
|
@PsqlDao
|
||||||
@Repository
|
@Repository
|
||||||
@ -35,11 +44,121 @@ public class PsqlLatestInsertRepository extends AbstractLatestInsertRepository {
|
|||||||
private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_LATEST_TABLE, TS_KV_LATEST_CONSTRAINT, LONG_V, PSQL_ON_LONG_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_LATEST_TABLE, TS_KV_LATEST_CONSTRAINT, LONG_V, PSQL_ON_LONG_VALUE_UPDATE_SET_NULLS);
|
||||||
private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_LATEST_TABLE, TS_KV_LATEST_CONSTRAINT, DBL_V, PSQL_ON_DBL_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_LATEST_TABLE, TS_KV_LATEST_CONSTRAINT, DBL_V, PSQL_ON_DBL_VALUE_UPDATE_SET_NULLS);
|
||||||
|
|
||||||
|
private static final String BATCH_UPDATE =
|
||||||
|
"UPDATE ts_kv_latest SET ts = ?, bool_v = ?, str_v = ?, long_v = ?, dbl_v = ? WHERE entity_type = ? AND entity_id = ? and key = ?";
|
||||||
|
|
||||||
|
|
||||||
|
private static final String INSERT_OR_UPDATE =
|
||||||
|
"INSERT INTO ts_kv_latest (entity_type, entity_id, key, ts, bool_v, str_v, long_v, dbl_v) VALUES(?, ?, ?, ?, ?, ?, ?, ?) " +
|
||||||
|
"ON CONFLICT (entity_type, entity_id, key) DO UPDATE SET ts = ?, bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?;";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveOrUpdate(TsKvLatestEntity entity) {
|
public void saveOrUpdate(TsKvLatestEntity entity) {
|
||||||
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOrUpdate(List<TsKvLatestEntity> entities) {
|
||||||
|
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||||
|
@Override
|
||||||
|
protected void doInTransactionWithoutResult(TransactionStatus status) {
|
||||||
|
int[] result = jdbcTemplate.batchUpdate(BATCH_UPDATE, new BatchPreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
|
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||||
|
ps.setLong(1, entities.get(i).getTs());
|
||||||
|
|
||||||
|
if (entities.get(i).getBooleanValue() != null) {
|
||||||
|
ps.setBoolean(2, entities.get(i).getBooleanValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(2, Types.BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(3, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
|
||||||
|
if (entities.get(i).getLongValue() != null) {
|
||||||
|
ps.setLong(4, entities.get(i).getLongValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(4, Types.BIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entities.get(i).getDoubleValue() != null) {
|
||||||
|
ps.setDouble(5, entities.get(i).getDoubleValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(5, Types.DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(6, entities.get(i).getEntityType().name());
|
||||||
|
ps.setString(7, entities.get(i).getEntityId());
|
||||||
|
ps.setString(8, entities.get(i).getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatchSize() {
|
||||||
|
return entities.size();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
int updatedCount = 0;
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
if (result[i] == 0) {
|
||||||
|
updatedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TsKvLatestEntity> insertEntities = new ArrayList<>(updatedCount);
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
if (result[i] == 0) {
|
||||||
|
insertEntities.add(entities.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
|
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||||
|
ps.setString(1, insertEntities.get(i).getEntityType().name());
|
||||||
|
ps.setString(2, insertEntities.get(i).getEntityId());
|
||||||
|
ps.setString(3, insertEntities.get(i).getKey());
|
||||||
|
ps.setLong(4, insertEntities.get(i).getTs());
|
||||||
|
ps.setLong(9, insertEntities.get(i).getTs());
|
||||||
|
|
||||||
|
if (insertEntities.get(i).getBooleanValue() != null) {
|
||||||
|
ps.setBoolean(5, insertEntities.get(i).getBooleanValue());
|
||||||
|
ps.setBoolean(10, insertEntities.get(i).getBooleanValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(5, Types.BOOLEAN);
|
||||||
|
ps.setNull(10, Types.BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(6, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
ps.setString(11, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
|
||||||
|
|
||||||
|
if (insertEntities.get(i).getLongValue() != null) {
|
||||||
|
ps.setLong(7, insertEntities.get(i).getLongValue());
|
||||||
|
ps.setLong(12, insertEntities.get(i).getLongValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(7, Types.BIGINT);
|
||||||
|
ps.setNull(12, Types.BIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (insertEntities.get(i).getDoubleValue() != null) {
|
||||||
|
ps.setDouble(8, insertEntities.get(i).getDoubleValue());
|
||||||
|
ps.setDouble(13, insertEntities.get(i).getDoubleValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(8, Types.DOUBLE);
|
||||||
|
ps.setNull(13, Types.DOUBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatchSize() {
|
||||||
|
return insertEntities.size();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void saveOrUpdateBoolean(TsKvLatestEntity entity, String query) {
|
protected void saveOrUpdateBoolean(TsKvLatestEntity entity, String query) {
|
||||||
entityManager.createNativeQuery(query)
|
entityManager.createNativeQuery(query)
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.dao.sqlts.ts;
|
package org.thingsboard.server.dao.sqlts.ts;
|
||||||
|
|
||||||
|
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
|
import org.thingsboard.server.dao.model.sqlts.ts.TsKvEntity;
|
||||||
@ -22,6 +23,11 @@ import org.thingsboard.server.dao.sqlts.AbstractTimeseriesInsertRepository;
|
|||||||
import org.thingsboard.server.dao.util.PsqlDao;
|
import org.thingsboard.server.dao.util.PsqlDao;
|
||||||
import org.thingsboard.server.dao.util.SqlTsDao;
|
import org.thingsboard.server.dao.util.SqlTsDao;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SqlTsDao
|
@SqlTsDao
|
||||||
@PsqlDao
|
@PsqlDao
|
||||||
@Repository
|
@Repository
|
||||||
@ -35,6 +41,10 @@ public class PsqlTimeseriesInsertRepository extends AbstractTimeseriesInsertRepo
|
|||||||
private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_TABLE, TS_KV_CONSTRAINT, LONG_V, PSQL_ON_LONG_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_TABLE, TS_KV_CONSTRAINT, LONG_V, PSQL_ON_LONG_VALUE_UPDATE_SET_NULLS);
|
||||||
private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_TABLE, TS_KV_CONSTRAINT, DBL_V, PSQL_ON_DBL_VALUE_UPDATE_SET_NULLS);
|
private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateStringPsql(TS_KV_TABLE, TS_KV_CONSTRAINT, DBL_V, PSQL_ON_DBL_VALUE_UPDATE_SET_NULLS);
|
||||||
|
|
||||||
|
private static final String INSERT_OR_UPDATE =
|
||||||
|
"INSERT INTO ts_kv (entity_type, entity_id, key, ts, bool_v, str_v, long_v, dbl_v) VALUES(?, ?, ?, ?, ?, ?, ?, ?) " +
|
||||||
|
"ON CONFLICT (entity_type, entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?;";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveOrUpdate(TsKvEntity entity) {
|
public void saveOrUpdate(TsKvEntity entity) {
|
||||||
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT);
|
||||||
@ -83,4 +93,50 @@ public class PsqlTimeseriesInsertRepository extends AbstractTimeseriesInsertRepo
|
|||||||
.setParameter("dbl_v", entity.getDoubleValue())
|
.setParameter("dbl_v", entity.getDoubleValue())
|
||||||
.executeUpdate();
|
.executeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void saveOrUpdate(List<TsKvEntity> entities) {
|
||||||
|
jdbcTemplate.batchUpdate(INSERT_OR_UPDATE, new BatchPreparedStatementSetter() {
|
||||||
|
@Override
|
||||||
|
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||||
|
ps.setString(1, entities.get(i).getEntityType().name());
|
||||||
|
ps.setString(2, entities.get(i).getEntityId());
|
||||||
|
ps.setString(3, entities.get(i).getKey());
|
||||||
|
ps.setLong(4, entities.get(i).getTs());
|
||||||
|
|
||||||
|
if (entities.get(i).getBooleanValue() != null) {
|
||||||
|
ps.setBoolean(5, entities.get(i).getBooleanValue());
|
||||||
|
ps.setBoolean(9, entities.get(i).getBooleanValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(5, Types.BOOLEAN);
|
||||||
|
ps.setNull(9, Types.BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps.setString(6, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
ps.setString(10, replaceNullChars(entities.get(i).getStrValue()));
|
||||||
|
|
||||||
|
|
||||||
|
if (entities.get(i).getLongValue() != null) {
|
||||||
|
ps.setLong(7, entities.get(i).getLongValue());
|
||||||
|
ps.setLong(11, entities.get(i).getLongValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(7, Types.BIGINT);
|
||||||
|
ps.setNull(11, Types.BIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entities.get(i).getDoubleValue() != null) {
|
||||||
|
ps.setDouble(8, entities.get(i).getDoubleValue());
|
||||||
|
ps.setDouble(12, entities.get(i).getDoubleValue());
|
||||||
|
} else {
|
||||||
|
ps.setNull(8, Types.DOUBLE);
|
||||||
|
ps.setNull(12, Types.DOUBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBatchSize() {
|
||||||
|
return entities.size();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user