Java開發(fā)者必看:IoTDB原生接口SessionPool?的高效使用與避坑指南
做 IoTDB 開發(fā)的小伙伴都知道,原生應(yīng)用程序編程接口(API)里的 Session 是和數(shù)據(jù)庫交互的核心接口。它就像客戶端與服務(wù)器之間建立的一條專用電話線,集成了寫入數(shù)據(jù)、執(zhí)行查詢、管理元數(shù)據(jù)等所有關(guān)鍵功能。一旦實(shí)例化,它就會(huì)與 IoTDB 服務(wù)端建立并維持一條長(zhǎng)連接。然而,這條“電話線”有個(gè)致命缺陷——非線程安全(Thread-Unsafe)。這意味著如果在多線程環(huán)境下,多個(gè)工作線程同時(shí)拿著同一個(gè) Session 對(duì)象打電話(調(diào)用方法),極易發(fā)生數(shù)據(jù)錯(cuò)亂、連接狀態(tài)沖突甚至程序崩潰的問題,這是并發(fā)編程中典型的競(jìng)態(tài)條件(Race Condition)陷阱。
為了解決這個(gè)痛點(diǎn),SessionPool 應(yīng)運(yùn)而生,它充當(dāng)了 Session 的連接池(Connection Pool) 的角色。連接池是一種創(chuàng)建和管理數(shù)據(jù)庫連接復(fù)用的技術(shù),它預(yù)先創(chuàng)建一定數(shù)量的空閑連接存放在“池子”里,當(dāng)業(yè)務(wù)線程需要操作數(shù)據(jù)庫時(shí),直接從池中“借用”一個(gè)空閑連接,用完后“歸還”,從而避免了頻繁創(chuàng)建和銷毀連接所帶來的巨大性能開銷。SessionPool 完美解決了 Session 的線程安全問題,在并發(fā)場(chǎng)景下能夠合理管理連接資源,大幅提升系統(tǒng)吞吐量和資源利用率。正因?yàn)槠浞€(wěn)定與高效,使用 SessionPool 也是 Apache IoTDB 官方推薦的編程方式。
今天,我們就從基礎(chǔ)用法到復(fù)雜實(shí)戰(zhàn)案例,再到一份詳盡的全量接口速查手冊(cè),把 SessionPool 的使用徹底講透。不論你是剛接觸 IoTDB 的開發(fā)者,還是希望優(yōu)化現(xiàn)有代碼架構(gòu)的工程師,閱讀本文后都能直接上手開發(fā)高性能、高可用的數(shù)據(jù)接入應(yīng)用。
一、核心概念與開發(fā)步驟概覽
在動(dòng)手寫代碼之前,讓我們先理清兩個(gè)核心對(duì)象的關(guān)系:
- Session:如前所述,它是 IoTDB 交互的核心接口,集成了寫數(shù)據(jù)、查數(shù)據(jù)、元數(shù)據(jù)操作等所有功能。實(shí)例化后就能建立和服務(wù)端的連接。再次強(qiáng)調(diào):絕對(duì)不能在多線程環(huán)境中同時(shí)調(diào)用同一個(gè) Session 實(shí)例的方法!
- SessionPool:它是 Session 的連接池,專門為多線程并發(fā)設(shè)計(jì)。其內(nèi)部維護(hù)了一組 Session 對(duì)象,通過借用(Borrow)和歸還(Return)的機(jī)制,統(tǒng)一管理多個(gè) Session 實(shí)例的生命周期。這樣做不僅規(guī)避了線程安全問題,更重要的是,它通過連接復(fù)用機(jī)制,極大降低了因頻繁創(chuàng)建和關(guān)閉連接帶來的網(wǎng)絡(luò)握手、認(rèn)證、資源分配等性能損耗。例如,在沒有連接池的情況下,每次寫入一條數(shù)據(jù)可能都需要耗時(shí)幾十毫秒來建立 TCP 連接;而使用連接池后,獲取已有連接的耗時(shí)通??梢越档偷轿⒚爰?jí)別。
使用 SessionPool 開發(fā)的核心步驟簡(jiǎn)單明了,可以概括為三步:
- 創(chuàng)建連接池實(shí)例:初始化 SessionPool 對(duì)象,配置好服務(wù)節(jié)點(diǎn)的地址、用戶名、密碼以及池的大小等核心參數(shù)。
- 執(zhí)行數(shù)據(jù)庫操作:在業(yè)務(wù)代碼中,直接從連接池調(diào)用相應(yīng)的操作方法(如寫入、查詢等)。你完全不需要關(guān)心連接的獲取與釋放,連接池會(huì)在后臺(tái)自動(dòng)處理這一切。
- 關(guān)閉連接池資源:當(dāng)整個(gè)應(yīng)用程序的生命周期結(jié)束,或不再需要與數(shù)據(jù)庫交互時(shí),務(wù)必調(diào)用關(guān)閉方法,優(yōu)雅地釋放連接池所持有的所有 Session 連接和系統(tǒng)資源。
接下來,我們就按部就班地講解具體的開發(fā)流程。文中將重點(diǎn)演示核心參數(shù)和關(guān)鍵接口的使用。如果你想探索更深層次的功能,可以隨時(shí)參考 IoTDB 官方提供的全量接口說明文檔或直接查閱其源代碼。
二、詳細(xì)開發(fā)步驟
2.1 搭建 Maven 項(xiàng)目,引入依賴
首先,創(chuàng)建一個(gè)基礎(chǔ)的 Maven 項(xiàng)目。為了確保兼容性,項(xiàng)目環(huán)境要求 JDK(Java 開發(fā)工具包)版本 ≥ 1.8,以及 Maven 版本 ≥ 3.6。
接下來,在項(xiàng)目的 pom.xml 文件中添加 IoTDB Session 的 Maven 依賴坐標(biāo)。此處有一個(gè)至關(guān)重要的黃金法則:客戶端依賴的版本號(hào)必須與你所連接的 IoTDB 數(shù)據(jù)庫服務(wù)端的版本號(hào)保持完全一致! 版本不一致是導(dǎo)致運(yùn)行時(shí)出現(xiàn)遠(yuǎn)程過程調(diào)用(RPC)協(xié)議不匹配、接口方法找不到等奇怪問題的首要原因。
專家建議:在團(tuán)隊(duì)協(xié)作開發(fā)中,建議將 IoTDB 的版本號(hào)提取為 Maven 的 <properties> 標(biāo)簽內(nèi)的一個(gè)屬性變量,例如 <iotdb.version>1.3.0</iotdb.version>。這樣當(dāng)服務(wù)端版本升級(jí)時(shí),只需修改一處,即可確保所有子模塊的依賴版本統(tǒng)一,降低維護(hù)成本和出錯(cuò)概率。
<dependencies>
<dependency>
<groupId>org.apache.iotdb</groupId>
<artifactId>iotdb-session</artifactId>
<!-- 版本號(hào)與數(shù)據(jù)庫版本號(hào)相同 -->
<version>${project.version}</version>
</dependency>
</dependencies>
2.2 初始化 SessionPool 連接池
創(chuàng)建連接池的核心是通過建造者模式(Builder Pattern)調(diào)用 SessionPool.Builder 來構(gòu)建對(duì)象。你需要配置節(jié)點(diǎn)的互聯(lián)網(wǎng)協(xié)議(IP)地址與端口、認(rèn)證所需的用戶名密碼、連接池的最大連接數(shù)等關(guān)鍵信息。
在這里,強(qiáng)烈推薦你配置多個(gè)節(jié)點(diǎn)的統(tǒng)一資源定位符(URL),形如 "host1:port1,host2:port2"。這樣做可以實(shí)現(xiàn)客戶端高可用(High Availability, HA)。其原理是:當(dāng)客戶端嘗試連接第一個(gè)節(jié)點(diǎn)失敗時(shí)(例如該節(jié)點(diǎn)宕機(jī)或網(wǎng)絡(luò)不通),它會(huì)自動(dòng)、透明地重試列表中的下一個(gè)節(jié)點(diǎn),直到成功建立連接為止。這種機(jī)制對(duì)于保障工業(yè)物聯(lián)網(wǎng)采集系統(tǒng)的不間斷運(yùn)行至關(guān)重要。
拓展知識(shí):故障轉(zhuǎn)移(Failover)機(jī)制詳解
SessionPool 內(nèi)部實(shí)現(xiàn)的是一種輕量級(jí)的客戶端負(fù)載均衡和故障轉(zhuǎn)移策略。它不會(huì)主動(dòng)檢測(cè)后端哪個(gè)節(jié)點(diǎn)的壓力更小,而是采用順序重試的邏輯。因此,在配置多節(jié)點(diǎn) URL 時(shí),可以將性能更好或更穩(wěn)定的節(jié)點(diǎn)放在列表的前面,以獲得更優(yōu)的連接成功率。此外,這種機(jī)制僅針對(duì)連接建立階段。如果連接已經(jīng)建立,后續(xù)在該連接上的操作遇到網(wǎng)絡(luò)中斷,SessionPool 會(huì)嘗試進(jìn)行有限次數(shù)的重連,如果重連失敗,則會(huì)將該 Session 標(biāo)記為不可用并從池中移除,以確保不會(huì)向業(yè)務(wù)層拋出已損壞的連接。
核心代碼示例如下:
import java.util.ArrayList;
import java.util.List;
import org.apache.iotdb.session.pool.SessionPool;
public class IoTDBSessionPoolExample {
private static SessionPool sessionPool;
public static void main(String[] args) {
// 配置數(shù)據(jù)庫節(jié)點(diǎn)URL,支持多節(jié)點(diǎn)容災(zāi)
List<String> nodeUrls = new ArrayList<>();
nodeUrls.add("127.0.0.1:6667");
nodeUrls.add("127.0.0.1:6668");
// 構(gòu)建SessionPool
sessionPool =
new SessionPool.Builder()
.nodeUrls(nodeUrls) // 節(jié)點(diǎn)列表
.user("root") // 用戶名
.password("root") // 密碼
.maxSize(3) // 連接池最大大小
.build();
}
}
2.3 執(zhí)行各類數(shù)據(jù)庫操作
SessionPool 全面支持 IoTDB 的所有核心操作。從功能上主要分為數(shù)據(jù)寫入和結(jié)構(gòu)化查詢語言(SQL)操作兩大類。下面,我們將結(jié)合典型的工業(yè)場(chǎng)景需求,詳細(xì)講解具體的接口用法,并提供可直接運(yùn)行的代碼案例。請(qǐng)記住,所有操作都是直接通過 SessionPool 實(shí)例調(diào)用的,你無需手動(dòng)操作任何 Session 對(duì)象。
2.3.1 數(shù)據(jù)寫入
在工業(yè)物聯(lián)網(wǎng)場(chǎng)景中,數(shù)據(jù)寫入主要分為多行數(shù)據(jù)寫入(可能來自多個(gè)設(shè)備或單個(gè)設(shè)備的多個(gè)時(shí)間戳)和單設(shè)備多行數(shù)據(jù)寫入兩種模式。IoTDB 針對(duì)這兩種場(chǎng)景提供了專門的接口,并進(jìn)行了底層優(yōu)化,以適應(yīng)不同采集網(wǎng)關(guān)的需求。
(1)多行數(shù)據(jù)寫入:insertRecords
此接口支持一次性寫入多行數(shù)據(jù),每行數(shù)據(jù)包含一個(gè)設(shè)備ID、一個(gè)時(shí)間戳以及該時(shí)刻的多個(gè)物理量測(cè)點(diǎn)值。它非常適合以下場(chǎng)景:在一個(gè)數(shù)據(jù)采集周期內(nèi),需要將來自不同設(shè)備(例如不同車間的風(fēng)機(jī)、泵機(jī))的最新數(shù)據(jù)點(diǎn)進(jìn)行匯聚,然后批量寫入數(shù)據(jù)庫。批量寫入能夠大幅降低網(wǎng)絡(luò)往返次數(shù)(RTT),從而顯著提升寫入效率。
性能對(duì)比:假設(shè)網(wǎng)絡(luò)延遲為 1ms,單條循環(huán)寫入 1000 條數(shù)據(jù)僅網(wǎng)絡(luò)等待時(shí)間就需 1 秒。而使用 insertRecords 批量寫入,僅需 1 次網(wǎng)絡(luò)交互,耗時(shí)約 1ms,性能差距高達(dá) 1000 倍。
完整代碼案例:
import java.util.ArrayList;
import java.util.List;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.pool.SessionPool;
import org.apache.tsfile.enums.TSDataType;
public class SessionPoolExample {
private static SessionPool sessionPool;
public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException {
// 1. 初始化連接池
constructSessionPool();
// 2. 執(zhí)行批量插入
insertRecordsExample();
// 3. 關(guān)閉連接池
closeSessionPool();
}
// 構(gòu)建連接池
private static void constructSessionPool() {
List<String> nodeUrls = new ArrayList<>();
nodeUrls.add("127.0.0.1:6667");
nodeUrls.add("127.0.0.1:6668");
sessionPool =
new SessionPool.Builder()
.nodeUrls(nodeUrls)
.user("root")
.password("root")
.maxSize(3)
.build();
}
// 批量插入多行數(shù)據(jù)
public static void insertRecordsExample() throws IoTDBConnectionException, StatementExecutionException {
String deviceId = "root.sg1.d1";
// 定義測(cè)點(diǎn)列表
List<String> measurements = new ArrayList<>();
measurements.add("s1");
measurements.add("s2");
measurements.add("s3");
// 初始化批量寫入的參數(shù)集合
List<String> deviceIds = new ArrayList<>();
List<List<String>> measurementsList = new ArrayList<>();
List<List<Object>> valuesList = new ArrayList<>();
List<Long> timestamps = new ArrayList<>();
List<List<TSDataType>> typesList = new ArrayList<>();
// 模擬生成500條數(shù)據(jù),每100條批量寫入一次
for (long time = 0; time < 500; time++) {
List<Object> values = new ArrayList<>();
List<TSDataType> types = new ArrayList<>();
// 模擬測(cè)點(diǎn)值
values.add(1L);
values.add(2L);
values.add(3L);
// 定義測(cè)點(diǎn)數(shù)據(jù)類型
types.add(TSDataType.INT64);
types.add(TSDataType.INT64);
types.add(TSDataType.INT64);
// 添加到批量集合
deviceIds.add(deviceId);
measurementsList.add(measurements);
valuesList.add(values);
typesList.add(types);
timestamps.add(time);
// 每100條執(zhí)行一次寫入,避免集合過大
if (time != 0 && time % 100 == 0) {
try {
sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList);
} catch (IoTDBConnectionException | StatementExecutionException e) {
// 異常處理,如重試、日志記錄
}
// 清空集合,準(zhǔn)備下一批數(shù)據(jù)
deviceIds.clear();
measurementsList.clear();
valuesList.clear();
typesList.clear();
timestamps.clear();
}
}
// 寫入最后一批不足100條的數(shù)據(jù)
try {
sessionPool.insertRecords(deviceIds, timestamps, measurementsList, typesList, valuesList);
} catch (IoTDBConnectionException | StatementExecutionException e) {
// 異常處理
}
}
// 關(guān)閉連接池
public static void closeSessionPool(){
sessionPool.close();
}
}
(2)單設(shè)備多行數(shù)據(jù)寫入:insertTablet
此接口是 IoTDB 官方最為推薦的高效寫入方式,專門用于單個(gè)設(shè)備產(chǎn)生的一段連續(xù)時(shí)間序列數(shù)據(jù)的寫入。它要求先將數(shù)據(jù)封裝在一個(gè)名為 Tablet 的特殊對(duì)象中。Tablet 類似于一個(gè)內(nèi)存中的數(shù)據(jù)塊,它內(nèi)部采用列式存儲(chǔ)結(jié)構(gòu)來表示一個(gè)設(shè)備在一段時(shí)間內(nèi)所有測(cè)點(diǎn)的值。
為什么 insertTablet 比 insertRecords 更高效?
1. 數(shù)據(jù)結(jié)構(gòu)優(yōu)勢(shì):Tablet 采用列式存儲(chǔ),對(duì)于同一個(gè)測(cè)點(diǎn)(如“電流”),其在不同時(shí)間戳下的值在內(nèi)存中是連續(xù)存放的。這與 IoTDB 底層的列式存儲(chǔ)引擎 TsFile 格式天然契合,數(shù)據(jù)傳輸和持久化時(shí)無需進(jìn)行復(fù)雜的行列轉(zhuǎn)置,減少了中央處理器(CPU)開銷。
2. 序列化優(yōu)化:Tablet 在進(jìn)行網(wǎng)絡(luò)傳輸序列化時(shí),能夠更緊湊地打包數(shù)據(jù),減少了傳輸?shù)臄?shù)據(jù)量。
3. 減少對(duì)象創(chuàng)建:寫入同一設(shè)備的大量數(shù)據(jù)時(shí),Tablet 僅需維護(hù)一個(gè)設(shè)備ID和一組測(cè)點(diǎn)元數(shù)據(jù),避免了每條數(shù)據(jù)都重復(fù)攜帶設(shè)備ID等冗余信息。
| 特性對(duì)比項(xiàng) | insertRecords (多行批量) | insertTablet (單設(shè)備批量) |
|---|---|---|
| 適用場(chǎng)景 | 多設(shè)備、少量數(shù)據(jù)點(diǎn)匯聚寫入 | 單設(shè)備、大量連續(xù)數(shù)據(jù)寫入 (如高速采集) |
| 數(shù)據(jù)結(jié)構(gòu) | 行式 (Row-oriented) | 列式 (Column-oriented) |
| 寫入性能 | 高 (優(yōu)于單條循環(huán)) | 極高 (IoTDB 最佳實(shí)踐) |
| 內(nèi)存開銷 | 較高 (每條數(shù)據(jù)攜帶元數(shù)據(jù)) | 較低 (共享設(shè)備/測(cè)點(diǎn)元數(shù)據(jù)) |
使用該接口前,需要先構(gòu)造 Tablet 對(duì)象,然后調(diào)用 insertTablet 方法寫入。
完整代碼案例:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.pool.SessionPool;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.schema.IMeasurementSchema;
import org.apache.tsfile.write.schema.MeasurementSchema;
public class SessionPoolExample {
private static SessionPool sessionPool;
public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException {
// 1. 初始化連接池
constructSessionPool();
// 2. 執(zhí)行Tablet寫入
insertTabletExample();
// 3. 關(guān)閉連接池
closeSessionPool();
}
// 構(gòu)建連接池
private static void constructSessionPool() {
List<String> nodeUrls = new ArrayList<>();
nodeUrls.add("127.0.0.1:6667");
sessionPool =
new SessionPool.Builder()
.nodeUrls(nodeUrls)
.user("root")
.password("root")
.maxSize(3)
.build();
}
// 單設(shè)備Tablet高效寫入
private static void insertTabletExample() throws IoTDBConnectionException, StatementExecutionException {
// 定義設(shè)備的測(cè)點(diǎn)模式(測(cè)點(diǎn)名稱+數(shù)據(jù)類型)
List<IMeasurementSchema> schemaList = new ArrayList<>();
schemaList.add(new MeasurementSchema("s1", TSDataType.INT64));
schemaList.add(new MeasurementSchema("s2", TSDataType.INT64));
schemaList.add(new MeasurementSchema("s3", TSDataType.INT64));
// 創(chuàng)建Tablet對(duì)象:設(shè)備ID + 測(cè)點(diǎn)模式 + 最大行數(shù)量
Tablet tablet = new Tablet("root.sg.d1",schemaList,100);
// 模擬生成數(shù)據(jù)并寫入Tablet
long timestamp = System.currentTimeMillis();
Random random = new Random();
for (long row = 0; row < 100; row++) {
int rowIndex = tablet.getRowSize();
// 添加時(shí)間戳
tablet.addTimestamp(rowIndex, timestamp);
// 為每個(gè)測(cè)點(diǎn)添加值
for (int s = 0; s < 3; s++) {
long value = random.nextLong();
tablet.addValue(schemaList.get(s).getMeasurementName(), rowIndex, value);
}
// 當(dāng)Tablet達(dá)到最大行數(shù)量時(shí),執(zhí)行寫入并重置
if (tablet.getRowSize() == tablet.getMaxRowNumber()) {
sessionPool.insertTablet(tablet);
tablet.reset();
}
timestamp++;
}
// 寫入最后一批不足最大行數(shù)量的數(shù)據(jù)
if (tablet.getRowSize() != 0) {
sessionPool.insertTablet(tablet);
tablet.reset();
}
}
// 關(guān)閉連接池
public static void closeSessionPool(){
sessionPool.close();
}
}
2.3.2 結(jié)構(gòu)化查詢語言(SQL)操作
SessionPool 支持執(zhí)行所有 IoTDB 兼容的 SQL 語句。根據(jù)語句是否有結(jié)果集返回,操作分為兩大類,并對(duì)應(yīng)兩個(gè)核心接口:
- executeNonQueryStatement:用于執(zhí)行非查詢類 SQL,主要包括數(shù)據(jù)定義語言(DDL)和數(shù)據(jù)操縱語言(DML)中的修改操作。例如:創(chuàng)建/刪除時(shí)間序列(CREATE/DROP TIMESERIES)、刪除數(shù)據(jù)點(diǎn)(DELETE FROM ...)、設(shè)置數(shù)據(jù)生命周期(SET TTL TO ...)等。這類操作沒有數(shù)據(jù)結(jié)果集返回。
- executeQueryStatement:用于執(zhí)行查詢類 SQL,例如普通的原始數(shù)據(jù)查詢(SELECT ... FROM ...)、聚合查詢(SELECT COUNT(*) ...)等。這類操作會(huì)返回一個(gè) SessionDataSetWrapper 對(duì)象,它封裝了查詢結(jié)果集,并提供了迭代器用于遍歷每一行數(shù)據(jù)。
注意事項(xiàng):超時(shí)設(shè)置
對(duì)于查詢操作,尤其是可能掃描大量歷史數(shù)據(jù)的聚合查詢,務(wù)必設(shè)置合理的查詢超時(shí)時(shí)間(timeoutInMs 參數(shù))。如果未設(shè)置或設(shè)置過長(zhǎng),一個(gè)異常的慢查詢可能會(huì)長(zhǎng)時(shí)間占用一個(gè) Session 連接,導(dǎo)致連接池中的可用連接被耗盡,其他正常的寫入或查詢請(qǐng)求將被阻塞,最終引發(fā)系統(tǒng)雪崩。
完整代碼案例,展示了兩種操作的具體用法以及結(jié)果集的遍歷方式:
import java.util.ArrayList;
import java.util.List;
import org.apache.iotdb.isession.pool.SessionDataSetWrapper;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.pool.SessionPool;
import org.apache.iotdb.isession.SessionDataSet.DataIterator;
public class SessionPoolExample {
private static SessionPool sessionPool;
public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException {
// 1. 初始化連接池
constructSessionPool();
// 2. 執(zhí)行非查詢SQL(DDL/DML)
executeNonQueryExample();
// 3. 執(zhí)行查詢SQL,遍歷結(jié)果集
executeQueryExample();
// 4. 關(guān)閉連接池
closeSessionPool();
}
// 非查詢SQL操作:創(chuàng)建時(shí)間序列、設(shè)置TTL、刪除時(shí)間序列等
private static void executeNonQueryExample() throws IoTDBConnectionException, StatementExecutionException {
// 創(chuàng)建非對(duì)齊時(shí)間序列
sessionPool.executeNonQueryStatement("create timeseries root.test.d1.s1 with dataType = int32");
// 為指定路徑設(shè)置TTL(過期時(shí)間)
sessionPool.executeNonQueryStatement("set TTL to root.test.** 10000");
// 刪除時(shí)間序列
sessionPool.executeNonQueryStatement("delete timeseries root.test.d1.s1");
}
// 查詢SQL操作:普通查詢 + 聚合查詢,遍歷結(jié)果集
private static void executeQueryExample() throws IoTDBConnectionException, StatementExecutionException {
// 1. 普通查詢:查詢前10條數(shù)據(jù)
try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select s1 from root.sg1.d1 limit 10")) {
DataIterator dataIterator = wrapper.iterator();
// 打印列名和列類型
System.out.println(wrapper.getColumnNames());
System.out.println(wrapper.getColumnTypes());
// 遍歷結(jié)果集
while (dataIterator.next()) {
StringBuilder builder = new StringBuilder();
for (String columnName : wrapper.getColumnNames()) {
builder.append(dataIterator.getString(columnName) + " ");
}
System.out.println(builder);
}
}
// 2. 聚合查詢:按5ms窗口分組統(tǒng)計(jì)s1的數(shù)量
try(SessionDataSetWrapper wrapper = sessionPool.executeQueryStatement("select count(s1) from root.sg1.d1 group by ([0, 40), 5ms) ")) {
DataIterator dataIterator = wrapper.iterator();
System.out.println(wrapper.getColumnNames());
System.out.println(wrapper.getColumnTypes());
while (dataIterator.next()) {
StringBuilder builder = new StringBuilder();
for (String columnName : wrapper.getColumnNames()) {
builder.append(dataIterator.getString(columnName) + " ");
}
System.out.println(builder);
}
}
}
// 構(gòu)建連接池
private static void constructSessionPool() {
List<String> nodeUrls = new ArrayList<>();
nodeUrls.add("127.0.0.1:6667");
nodeUrls.add("127.0.0.1:6668");
sessionPool =
new SessionPool.Builder()
.nodeUrls(nodeUrls)
.user("root")
.password("root")
.maxSize(3)
.build();
}
// 關(guān)閉連接池
public static void closeSessionPool(){
sessionPool.close();
}
}
結(jié)果集高級(jí)遍歷:多數(shù)據(jù)類型取值
在實(shí)際開發(fā)中,你會(huì)遇到各種數(shù)據(jù)類型的測(cè)點(diǎn),如整型(INT32、INT64)、浮點(diǎn)型(FLOAT、DOUBLE)、布爾型(BOOLEAN)、文本(TEXT)以及二進(jìn)制大對(duì)象(BLOB)等。遍歷結(jié)果集時(shí),必須使用與數(shù)據(jù)類型相匹配的 get 方法來獲取值,否則會(huì)拋出類型轉(zhuǎn)換異常。
結(jié)果集的 DataIterator 提供了一系列專屬的取值方法。特別說明的是,對(duì) BLOB 和 DATE 類型的支持從 IoTDB V2.0.4 版本開始才完全穩(wěn)定。因此,如果你的服務(wù)端版本低于此,建議優(yōu)先升級(jí)或避免使用這兩種類型。
核心示例(包含了所有常見數(shù)據(jù)類型的取值和空值判斷邏輯):
import org.apache.iotdb.isession.SessionDataSet;
import org.apache.iotdb.isession.pool.SessionDataSetWrapper;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.pool.SessionPool;
import org.apache.tsfile.enums.TSDataType;
import org.apache.tsfile.utils.Binary;
import org.apache.tsfile.utils.DateUtils;
import org.apache.tsfile.write.record.Tablet;
import org.apache.tsfile.write.schema.MeasurementSchema;
import org.junit.Assert;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class SessionExample {
private static SessionPool sessionPool;
public static void main(String[] args)
throws IoTDBConnectionException, StatementExecutionException {
// 1. 初始化連接池
constructSessionPool();
// 2. 執(zhí)行查詢并遍歷多類型結(jié)果集
executeQueryExample();
// 3. 關(guān)閉連接池
closeSessionPool();
}
private static void executeQueryExample()
throws IoTDBConnectionException, StatementExecutionException {
// 先插入一條多數(shù)據(jù)類型的測(cè)試數(shù)據(jù)
Tablet tablet =
new Tablet(
"root.sg.d1",
Arrays.asList(
new MeasurementSchema("s1", TSDataType.INT32),
new MeasurementSchema("s2", TSDataType.INT64),
new MeasurementSchema("s3", TSDataType.FLOAT),
new MeasurementSchema("s4", TSDataType.DOUBLE),
new MeasurementSchema("s5", TSDataType.TEXT),
new MeasurementSchema("s6", TSDataType.BOOLEAN),
new MeasurementSchema("s7", TSDataType.TIMESTAMP),
new MeasurementSchema("s8", TSDataType.BLOB),
new MeasurementSchema("s9", TSDataType.STRING),
new MeasurementSchema("s10", TSDataType.DATE),
new MeasurementSchema("s11", TSDataType.TIMESTAMP)),
10);
tablet.addTimestamp(0, 0L);
tablet.addValue("s1", 0, 1);
tablet.addValue("s2", 0, 1L);
tablet.addValue("s3", 0, 0f);
tablet.addValue("s4", 0, 0d);
tablet.addValue("s5", 0, "text_value");
tablet.addValue("s6", 0, true);
tablet.addValue("s7", 0, 1L);
tablet.addValue("s8", 0, new Binary(new byte[] {1}));
tablet.addValue("s9", 0, "string_value");
tablet.addValue("s10", 0, DateUtils.parseIntToLocalDate(20250403));
tablet.initBitMaps();
tablet.bitMaps[10].mark(0); // 標(biāo)記s11為null
tablet.rowSize = 1;
sessionPool.insertAlignedTablet(tablet);
// 查詢并遍歷多類型結(jié)果集
try (SessionDataSetWrapper dataSet =
sessionPool.executeQueryStatement("select * from root.sg.d1")) {
SessionDataSet.DataIterator iterator = dataSet.iterator();
int count = 0;
while (iterator.next()) {
count++;
// 各種數(shù)據(jù)類型的取值 + 空值判斷
Assert.assertFalse(iterator.isNull("root.sg.d1.s1"));
Assert.assertEquals(1, iterator.getInt("root.sg.d1.s1")); // 整型
Assert.assertFalse(iterator.isNull("root.sg.d1.s2"));
Assert.assertEquals(1L, iterator.getLong("root.sg.d1.s2")); // 長(zhǎng)整型
Assert.assertFalse(iterator.isNull("root.sg.d1.s3"));
Assert.assertEquals(0, iterator.getFloat("root.sg.d1.s3"), 0.01); // 浮點(diǎn)型
Assert.assertFalse(iterator.isNull("root.sg.d1.s4"));
Assert.assertEquals(0, iterator.getDouble("root.sg.d1.s4"), 0.01); // 雙精度
Assert.assertFalse(iterator.isNull("root.sg.d1.s5"));
Assert.assertEquals("text_value", iterator.getString("root.sg.d1.s5")); // 文本
Assert.assertFalse(iterator.isNull("root.sg.d1.s6"));
Assert.assertTrue(iterator.getBoolean("root.sg.d1.s6")); // 布爾值
Assert.assertFalse(iterator.isNull("root.sg.d1.s7"));
Assert.assertEquals(new Timestamp(1), iterator.getTimestamp("root.sg.d1.s7")); // 時(shí)間戳
Assert.assertFalse(iterator.isNull("root.sg.d1.s8"));
Assert.assertEquals(new Binary(new byte[] {1}), iterator.getBlob("root.sg.d1.s8")); // 二進(jìn)制
Assert.assertFalse(iterator.isNull("root.sg.d1.s10"));
Assert.assertEquals(DateUtils.parseIntToLocalDate(20250403), iterator.getDate("root.sg.d1.s10")); // 日期
Assert.assertTrue(iterator.isNull("root.sg.d1.s11")); // 空值判斷
Assert.assertNull(iterator.getTimestamp("root.sg.d1.s11"));
}
Assert.assertEquals(tablet.rowSize, count);
}
}
private static void constructSessionPool() {
List<String> nodeUrls = new ArrayList<>();
nodeUrls.add("127.0.0.1:6667");
sessionPool =
new SessionPool.Builder()
.nodeUrls(nodeUrls)
.user("root")
.password("root")
.maxSize(3)
.build();
}
public static void closeSessionPool() {
sessionPool.close();
}
}
三、SessionPool 全量接口速查手冊(cè)
上面講的是開發(fā)中最常用的核心用法。在實(shí)際開發(fā)中,你還會(huì)頻繁用到元數(shù)據(jù)管理、數(shù)據(jù)刪除、聚合查詢等更多功能。下面,我為你整理了一份 SessionPool 的核心配置參數(shù)詳解和一份按功能分類的全量接口速查表,方便你在開發(fā)時(shí)隨時(shí)查閱。
3.1 核心配置參數(shù)詳解
合理地配置 SessionPool 參數(shù)是保障系統(tǒng)穩(wěn)定高效運(yùn)行的前提。Session 和 SessionPool 的所有參數(shù)都可以通過構(gòu)造函數(shù)或 Builder 的鏈?zhǔn)秸{(diào)用來設(shè)置。以下是對(duì)核心參數(shù)的詳細(xì)解釋,涵蓋了連接、超時(shí)、性能、容災(zāi)等所有關(guān)鍵維度:
| 字段名 | 類型 | 說明 |
|---|---|---|
| nodeUrls | List | 數(shù)據(jù)庫節(jié)點(diǎn)的 URL 列表,支持多節(jié)點(diǎn)連接,實(shí)現(xiàn)容災(zāi)重試 |
| username | String | 連接IoTDB的用戶名 |
| password | String | 連接IoTDB的密碼 |
| fetchSize | int | 查詢結(jié)果的默認(rèn)批量返回大小 |
| useSSL | boolean | 是否啟用 SSL 加密連接 |
| queryTimeoutInMs | long | 查詢的超時(shí)時(shí)間,單位:毫秒 |
| connectionTimeoutInMs | int | 連接建立的超時(shí)時(shí)間,單位:毫秒 |
| maxRetryCount | int | 連接失敗后的最大重試次數(shù) |
| retryIntervalInMs | long | 重試的間隔時(shí)間,單位:毫秒 |
| enableRPCCompression | boolean | 是否啟用 RPC 傳輸壓縮,提升傳輸效率 |
調(diào)優(yōu)指南:如何確定 maxSize 的值?
這沒有一個(gè)固定的答案,取決于你的業(yè)務(wù)并發(fā)量和單個(gè)操作的平均耗時(shí)。
* 估算公式:maxSize ≈ (核心業(yè)務(wù)線程數(shù)) × (單次數(shù)據(jù)庫操作平均耗時(shí) / 業(yè)務(wù)請(qǐng)求間隔)。
* 經(jīng)驗(yàn)法則:對(duì)于寫入密集型的物聯(lián)網(wǎng)網(wǎng)關(guān)應(yīng)用,通常 CPU 核數(shù) * 2 是一個(gè)不錯(cuò)的起點(diǎn)。例如,一個(gè) 4 核的網(wǎng)關(guān)服務(wù)器,初始可以設(shè)置為 8。
* 壓測(cè)驗(yàn)證:最可靠的方法是通過性能壓力測(cè)試。模擬線上真實(shí)流量,逐步調(diào)大 maxSize,觀察寫入每秒事務(wù)數(shù)(TPS)和平均響應(yīng)延遲。當(dāng)繼續(xù)增大 maxSize 但 TPS 不再增長(zhǎng)甚至開始下降時(shí)(可能由于服務(wù)端連接數(shù)過多導(dǎo)致資源爭(zhēng)搶),那個(gè)拐點(diǎn)就是最優(yōu)的 maxSize 值。
3.2 全量功能接口速查表
以下所有接口都可以通過 SessionPool 實(shí)例直接調(diào)用。我已按功能進(jìn)行分類,并附帶了關(guān)鍵參數(shù)的解釋,你在開發(fā)時(shí)按需選用即可。
3.2.1 元數(shù)據(jù)管理
用于創(chuàng)建/刪除數(shù)據(jù)庫、時(shí)間序列,管理元數(shù)據(jù)模板等,是 IoTDB 的基礎(chǔ)配置操作。
| 方法名 | 功能描述 | 參數(shù)解釋 |
|---|---|---|
| createDatabase(String database) | 創(chuàng)建數(shù)據(jù)庫 | database: 數(shù)據(jù)庫名稱 |
| deleteDatabase(String database) | 刪除指定數(shù)據(jù)庫 | database: 要?jiǎng)h除的數(shù)據(jù)庫名稱 |
| createTimeseries(…) | 創(chuàng)建單個(gè)時(shí)間序列 | path: 時(shí)間序列路徑,dataType: 數(shù)據(jù)類型,encoding: 編碼類型,compressor: 壓縮類型 |
| createAlignedTimeseries(…) | 創(chuàng)建對(duì)齊時(shí)間序列 | 設(shè)備ID、測(cè)點(diǎn)列表、數(shù)據(jù)類型列表、編碼列表、壓縮類型列表 |
| createMultiTimeseries(…) | 批量創(chuàng)建時(shí)間序列 | 多個(gè)路徑、數(shù)據(jù)類型、編碼、壓縮類型、屬性、標(biāo)簽等 |
| deleteTimeseries(String path) | 刪除單個(gè)時(shí)間序列 | path: 要?jiǎng)h除的時(shí)間序列路徑 |
| createSchemaTemplate(Template template) | 創(chuàng)建模式模板 | template: 模板對(duì)象 |
| dropSchemaTemplate(String templateName) | 刪除模式模板 | templateName: 要?jiǎng)h除的模板名稱 |
| showAllTemplates() | 顯示所有已創(chuàng)建的模板 | 無參數(shù) |
3.2.2 數(shù)據(jù)寫入
包含所有寫入接口,覆蓋單條/批量、對(duì)齊/非對(duì)齊時(shí)間序列、Tablet 高效寫入等所有場(chǎng)景,是工業(yè)數(shù)據(jù)采集的核心接口。
| 方法名 | 功能描述 | 參數(shù)解釋 |
|---|---|---|
| insertRecord(…) | 插入單條記錄 | deviceId: 設(shè)備ID,time: 時(shí)間戳,measurements: 測(cè)點(diǎn)列表,values: 值列表 |
| insertRecords(…) | 插入多條記錄(多設(shè)備) | deviceIds: 設(shè)備ID列表,times: 時(shí)間戳列表,measurementsList: 測(cè)點(diǎn)列表集合 |
| insertRecordsOfOneDevice(…) | 插入單設(shè)備的多條記錄 | deviceId: 設(shè)備ID,times: 時(shí)間戳列表,measurementsList: 測(cè)點(diǎn)列表集合 |
| insertAlignedRecord(…) | 插入單條對(duì)齊記錄 | deviceId: 設(shè)備ID,time: 時(shí)間戳,measurements: 測(cè)點(diǎn)列表,values: 值列表 |
| insertTablet(Tablet tablet) | 插入單個(gè)Tablet數(shù)據(jù)(高效) | tablet: 封裝好的設(shè)備數(shù)據(jù)對(duì)象 |
| insertAlignedTablet(Tablet tablet) | 插入對(duì)齊的Tablet數(shù)據(jù)(高效) | tablet: 封裝好的設(shè)備對(duì)齊數(shù)據(jù)對(duì)象 |
| insertTablets(Map<String, Tablet> tablets) | 批量插入多個(gè)Tablet數(shù)據(jù) | tablets: 設(shè)備ID到Tablet的映射表 |
3.2.3 數(shù)據(jù)刪除
用于刪除時(shí)間序列本身或刪除指定時(shí)間范圍內(nèi)的歷史數(shù)據(jù),常用于數(shù)據(jù)清理和存儲(chǔ)成本控制。
| 方法名 | 功能描述 | 參數(shù)解釋 |
|---|---|---|
| deleteTimeseries(List paths) | 批量刪除時(shí)間序列 | paths: 要?jiǎng)h除的時(shí)間序列路徑列表 |
| deleteData(String path, long endTime) | 刪除指定路徑的歷史數(shù)據(jù)(截止到endTime) | path: 路徑,endTime: 結(jié)束時(shí)間戳 |
| deleteData(List paths, long startTime, long endTime) | 刪除時(shí)間范圍內(nèi)的歷史數(shù)據(jù) | paths: 路徑列表,startTime/endTime: 時(shí)間范圍 |
3.2.4 數(shù)據(jù)查詢
包含普通查詢、聚合查詢、原始數(shù)據(jù)查詢、最新數(shù)據(jù)查詢等所有查詢方式,支持超時(shí)配置和豐富的窗口聚合功能。
| 方法名 | 功能描述 | 參數(shù)解釋 |
|---|---|---|
| executeQueryStatement(String sql) | 執(zhí)行自定義查詢SQL | sql: 任意合法的IoTDB查詢語句 |
| executeRawDataQuery(…) | 查詢指定路徑的原始數(shù)據(jù) | paths: 路徑列表,startTime/endTime: 時(shí)間范圍 |
| executeLastDataQuery(List paths) | 查詢指定路徑的最新數(shù)據(jù) | paths: 要查詢的測(cè)點(diǎn)/設(shè)備路徑列表 |
| executeAggregationQuery(…) | 執(zhí)行聚合查詢(count/sum/max等) | paths: 路徑列表,aggregations: 聚合類型列表 |
| executeAggregationQuery(…) | 執(zhí)行滑動(dòng)窗口聚合查詢 | 增加interval: 窗口間隔,slidingStep: 滑動(dòng)步長(zhǎng) |
3.2.5 系統(tǒng)狀態(tài)與備份
用于獲取系統(tǒng)狀態(tài)、備份配置、活動(dòng)連接數(shù)等信息,是進(jìn)行運(yùn)維監(jiān)控和問題排查的得力助手。
| 方法名 | 功能描述 | 參數(shù)解釋 |
|---|---|---|
| getBackupConfiguration() | 獲取數(shù)據(jù)庫的備份配置信息 | 無參數(shù) |
| fetchAllConnections() | 獲取當(dāng)前客戶端的所有活動(dòng)連接信息 | 無參數(shù) |
| getSystemStatus() | 獲取系統(tǒng)狀態(tài)(已廢棄,默認(rèn)返回NORMAL) | 無參數(shù) |
四、開發(fā)注意事項(xiàng)與最佳實(shí)踐(避坑指南)
為了讓你在實(shí)際開發(fā)中少走彎路,我總結(jié)了以下七條關(guān)鍵的注意事項(xiàng)和最佳實(shí)踐,請(qǐng)務(wù)必牢記。
- 版本一致性(鐵律):客戶端依賴版本必須和 IoTDB 服務(wù)端版本完全一致(包括大、中、小版本號(hào))。不一致會(huì)導(dǎo)致遠(yuǎn)程過程調(diào)用(RPC)通信協(xié)議解析失敗、接口方法簽名不匹配等問題,錯(cuò)誤日志通常會(huì)顯示 TTransportException 或 NoSuchMethodError。
- 多節(jié)點(diǎn)容災(zāi)(必備):在生產(chǎn)環(huán)境中,務(wù)必在創(chuàng)建 SessionPool 時(shí)配置至少兩個(gè)nodeUrls。這是實(shí)現(xiàn)客戶端高可用的最簡(jiǎn)單、最有效的方式,能在單個(gè)節(jié)點(diǎn)宕機(jī)時(shí)實(shí)現(xiàn)自動(dòng)故障轉(zhuǎn)移,保障數(shù)據(jù)采集不中斷。
- 連接池大小調(diào)優(yōu):maxSize 參數(shù)的設(shè)置需要權(quán)衡。過大,會(huì)增加服務(wù)端的連接管理負(fù)擔(dān)和內(nèi)存占用,甚至可能觸及服務(wù)端 max_client_count 的限制;過小,會(huì)導(dǎo)致高并發(fā)時(shí)業(yè)務(wù)線程因獲取不到連接而頻繁等待,從而降低系統(tǒng)吞吐量。請(qǐng)根據(jù)實(shí)際壓力測(cè)試結(jié)果進(jìn)行調(diào)整。
- 優(yōu)先使用高效寫入接口:數(shù)據(jù)寫入時(shí),強(qiáng)烈建議優(yōu)先使用 insertTablet(單設(shè)備大批量)和 insertRecords(多設(shè)備批量)。絕對(duì)避免在循環(huán)中使用 insertRecord 逐條寫入,這種模式下的性能極差,無法發(fā)揮 IoTDB 的高吞吐優(yōu)勢(shì)。
- 資源釋放(重中之重):在應(yīng)用程序優(yōu)雅停機(jī)時(shí)(例如在 Java 的 ShutdownHook 中),必須顯式調(diào)用 sessionPool.close() 方法。這會(huì)確保連接池中所有處于活動(dòng)狀態(tài)或空閑狀態(tài)的 Session 連接都能向服務(wù)端發(fā)送斷開請(qǐng)求,并釋放本地占用的套接字(Socket)資源。如果不關(guān)閉,可能會(huì)導(dǎo)致服務(wù)端積累大量僵死連接,占用文件句柄。
- 健全的異常處理:所有數(shù)據(jù)庫操作都應(yīng)捕獲 IoTDBConnectionException(網(wǎng)絡(luò)連接、節(jié)點(diǎn)不可用等異常)和 StatementExecutionException(SQL 語法錯(cuò)誤、數(shù)據(jù)類型不匹配等執(zhí)行異常)。對(duì)于可恢復(fù)的連接異常,建議實(shí)現(xiàn)指數(shù)退避重試(Exponential Backoff Retry) 策略,避免在服務(wù)端短暫抖動(dòng)時(shí)立即失敗。
- 查詢結(jié)果集必須關(guān)閉:使用 executeQueryStatement 執(zhí)行查詢后返回的 SessionDataSetWrapper 對(duì)象,內(nèi)部持有網(wǎng)絡(luò)連接資源。強(qiáng)烈推薦使用 Java 7 引入的 try-with-resources 語句來包裹它,這樣可以確保在代碼塊執(zhí)行完畢后,無論是否發(fā)生異常,結(jié)果集都能被自動(dòng)關(guān)閉,從而防止資源泄露。
五、總結(jié)
在 Apache IoTDB 的 Java 原生 API 體系中,SessionPool 是多線程并發(fā)場(chǎng)景下的不二之選。相較于直接、不安全地使用 Session,它不僅從根本上解決了線程安全問題,更通過連接池化技術(shù)優(yōu)雅地管理了寶貴的網(wǎng)絡(luò)連接資源,從而顯著提升了系統(tǒng)的整體性能和穩(wěn)定性。
本文從基礎(chǔ)的項(xiàng)目搭建、連接池初始化,到數(shù)據(jù)寫入(特別是高性能 Tablet 模式)和 SQL 操作的實(shí)戰(zhàn)案例,再到一份詳盡的全量接口速查手冊(cè)和開發(fā)最佳實(shí)踐,將 SessionPool 的核心用法全部覆蓋。
其實(shí),掌握 SessionPool 的開發(fā)思路非常簡(jiǎn)單,可以概括為九個(gè)字:建好池、調(diào)接口、用完關(guān)。只要你遵循這一核心思路,再結(jié)合本文提供的豐富代碼案例和速查表格,就能輕松應(yīng)對(duì) IoTDB 在各類物聯(lián)網(wǎng)和工業(yè)大數(shù)據(jù)場(chǎng)景下的開發(fā)需求。在日常開發(fā)中,請(qǐng)記?。簝?yōu)先選用 Tablet 高效寫入和批量操作,并配合多節(jié)點(diǎn)容災(zāi)配置,這樣才能在保證極致寫入性能的同時(shí),構(gòu)筑起高可用的數(shù)據(jù)服務(wù)。
附:Apache IoTDB 的各大版本演進(jìn)
Apache IoTDB(Internet of Things Database)是一款專為工業(yè)物聯(lián)網(wǎng)場(chǎng)景設(shè)計(jì)的時(shí)序數(shù)據(jù)庫管理系統(tǒng)。它采用端-邊-云協(xié)同的輕量化架構(gòu),支持從設(shè)備端到邊緣網(wǎng)關(guān)再到云端的一體化時(shí)序數(shù)據(jù)收集、存儲(chǔ)、管理與分析。其核心特點(diǎn)包括:
- 多協(xié)議兼容:原生支持 SQL、樹形數(shù)據(jù)模型,并提供 JDBC、Python、C++、Go 等多種語言接口。
- 超高壓縮比:針對(duì)時(shí)序數(shù)據(jù)的特性,采用了列式存儲(chǔ)、時(shí)間戳差值編碼、游程編碼等技術(shù),可實(shí)現(xiàn)高達(dá) 30 倍以上的無損壓縮。
- 高通量讀寫:?jiǎn)喂?jié)點(diǎn)寫入速度可達(dá)千萬數(shù)據(jù)點(diǎn)/秒,查詢性能卓越。
- 工業(yè)級(jí)穩(wěn)定:經(jīng)過眾多頭部制造、能源、交通企業(yè)的生產(chǎn)環(huán)境驗(yàn)證,具備高可用和容錯(cuò)能力。
- 極簡(jiǎn)運(yùn)維:安裝部署簡(jiǎn)單,提供可視化的管理控制臺(tái)。
| 版本 | IoTDB 二進(jìn)制包 | IoTDB 源代碼 | 發(fā)布說明 |
|---|---|---|---|
| 2.0.5 | - All-in-one - AINode - SHA512 - ASC | - 源代碼 - SHA512 - ASC | release notes |
| 1.3.5 | - All-in-one - AINode - SHA512 - ASC | - 源代碼 - SHA512 - ASC | release notes |
| 0.13.4 | - All-in-one - Grafana 連接器 - Grafana 插件 - SHA512 - ASC | - 源代碼 - SHA512 - ASC | release notes |
? 當(dāng)前最新穩(wěn)定版本為 2.0.6,該版本在分布式能力、查詢性能、數(shù)據(jù)壓縮以及監(jiān)控運(yùn)維方面均有重大提升。您可以訪問以下鏈接獲取最新版本及其源代碼:
https://archive.apache.org/dist/iotdb/
到此這篇關(guān)于Java開發(fā)者必看:IoTDB原生接口SessionPool 的高效使用與避坑指南(附實(shí)例代碼)的文章就介紹到這了,更多相關(guān)IoTDB連接池:SessionPool 用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot集成本地緩存Caffeine的三種使用方式(小結(jié))
本文主要介紹了springboot集成本地緩存Caffeine的三種使用方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Java對(duì)敏感數(shù)據(jù)進(jìn)行加密的方法詳解
敏感數(shù)據(jù)的加密是數(shù)據(jù)安全的重要方面,尤其是對(duì)于手機(jī)號(hào)和身份證號(hào)這類個(gè)人信息,本文主要為大家介紹了Java對(duì)敏感數(shù)據(jù)進(jìn)行加密的相關(guān)方法,希望對(duì)大家有所幫助2024-03-03
java String 轉(zhuǎn)成Double二維數(shù)組的方法
下面小編就為大家?guī)硪黄猨ava String 轉(zhuǎn)成Double二維數(shù)組的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-10-10
Spring Boot緩存實(shí)戰(zhàn) Caffeine示例
本篇文章主要介紹了Spring Boot緩存實(shí)戰(zhàn) Caffeine示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02
通過實(shí)例學(xué)習(xí)Java集合框架HashSet
這篇文章主要介紹了通過實(shí)例學(xué)習(xí)Java集合框架HashSet,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
關(guān)于Java中阻塞隊(duì)列BlockingQueue的詳解
這篇文章主要介紹了關(guān)于Java中阻塞隊(duì)列BlockingQueue的詳解,BlockingQueue是為了解決多線程中數(shù)據(jù)高效安全傳輸而提出的,從阻塞這個(gè)詞可以看出,在某些情況下對(duì)阻塞隊(duì)列的訪問可能會(huì)造成阻塞,需要的朋友可以參考下2023-05-05
Java集合之Comparable和Comparator接口詳解
Java提供了Comparable接口與Comparator接口,它們?yōu)閿?shù)組或集合中的元素提供了排序邏輯,實(shí)現(xiàn)此接口的對(duì)象數(shù)組或集合可以通過Arrays.sort或Collections.sort進(jìn)行自動(dòng)排序。本文將通過示例講講它們的使用,需要的可以參考一下2022-12-12

