Apache IoTDB 系列教程-4:客戶端接口

說了半天語法和部署運維,實際使用仍是要落到代碼裏的,今天介紹一下客戶端的接口。php

正文 3516 字,預計閱讀時間 5 分鐘。
java

如今的客戶端和服務器通訊採用了跨語言的 RPC 框架 Thirft,理論上 Thrift 能生成的語言都能支持。可是直接用 Thrift 生成的代碼對數據庫使用者不太友好,因此咱們在生成代碼的基礎上,包裝出來了咱們的各類客戶端接口,這種接口對用戶就比較友好了。接下來介紹一下各類客戶端接口。git

JDBC 接口
github

JDBC 是關係數據庫的標準接口,也是你們最熟悉的接口。因此一開始咱們就提供了這種接口。
typescript

和標準 JDBC 的使用方式同樣,須要加載數據庫驅動類,創建鏈接,創建 Statement,經過 Statement 執行語句,對於非查詢來講,能夠批量執行減小網絡傳輸次數。下面是一個簡單的例子,
數據庫

public static void main(String[] args) throws ClassNotFoundException, SQLException {
    Class.forName("org.apache.iotdb.jdbc.IoTDBDriver");
    try (Connection connection = DriverManager
        .getConnection("jdbc:iotdb://127.0.0.1:6667/", "root", "root");
        Statement statement = connection.createStatement()) {
      // 建立存儲組
      statement.execute("SET STORAGE GROUP TO root.sg1");
      // 建立時間序列
      statement.execute("CREATE TIMESERIES root.sg1.d1.s1 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
      statement.execute("CREATE TIMESERIES root.sg1.d1.s2 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
      statement.execute("CREATE TIMESERIES root.sg1.d1.s3 WITH DATATYPE=INT64, ENCODING=RLE, COMPRESSOR=SNAPPY");
      // 在客戶端積累一批更新語句
      for (int i = 0; i <= 100; i++) {
        statement.addBatch("insert into root.sg1.d1(timestamp, s1, s2, s3) values("+ i + "," + 1 + "," + 1 + "," + 1 + ")"); 
      }
      // 執行
      statement.executeBatch();
      statement.clearBatch();
      // 查詢
      ResultSet resultSet = statement.executeQuery("select * from root where time <= 10");
      // 打印結果集
      ResultSetMetaData metaData = resultSet.getMetaData();
      int columnCount = metaData.getColumnCount();
      while (resultSet.next()) {
        for (int i = 1; i < columnCount; i++) {
          System.out.print(resultSet.getString(i));
          System.out.print(" ");
        }
        System.out.println();
      }
    }
  }

完整的示例代碼位置:apache

https://github.com/apache/incubator-iotdb/blob/master/example/jdbc/src/main/java/org/apache/iotdb/JDBCExample.java數組

Java 原生接口 Session服務器

對於數據寫入,SQL 解析就佔了 70% 耗時。因而咱們提供了一個原生的 NoSQL 接口(Session),相比於 JDBC 更高效。網絡

insertRecord(String deviceId, long time, List<String> measurements,
      List<TSDataType> types, List<Object> values)

這個接口就對應一個 insert 語句,一次能夠寫入一個設備一個時間戳多個測點的值,其中值的類型須要和註冊的類型保持一致,若是沒註冊過則自動註冊此類型。

insertRecord(String deviceId, long time, List<String> measurements,
      List<String> values)

在一些場景下,客戶端拿不到具體的數據類型,這時候能夠用這種 String 參數的接口。若是提早註冊了序列,服務器會根據註冊的類型來解析這些 String 的值,若是沒註冊,會根據值的格式推斷類型進行註冊。

insertTablet(Tablet tablet, boolean sorted)

一個Tablet 是一個設備多個時間戳多個測點的值。這裏要注意,每一個測點在每一個時間戳都須要有值,不能有空的。sorted 表示是否時間戳是遞增的,若是能保證遞增,能夠設置爲 true,不然咱們還會再排個序。

若是只計算執行時間,這個接口是最高效的,由於裏邊使用了原始類型的數組,避免了裝箱。可是,這個接口對數據的格式要求很高,若是數據採集不是對齊採的,強行轉化成這種接口,轉化的耗時須要統計一下。

此外還有 insertTablets 和 insertRecords 兩種,其實就是以上幾種接口的批量的形式。

Session 的查詢結果集是 SessionDataSet,這個結構提供的 hasNext 和 next 方法把每一行數據都轉化成了 RowRecord 這個結構,若是客戶端還須要作其餘轉化,這個結構就多餘了。這時候能夠經過 SessionDataSet.iterator()獲得一個迭代器,這個迭代器的訪問數據的方式和 JDBC 的 ResultSet 是同樣的,直接從字節數組裏拿數據,比 RowRecord 更高效。

完整的示例代碼位置:

https://github.com/apache/incubator-iotdb/blob/master/example/session/src/main/java/org/apache/iotdb/SessionExample.java

鏈接池 SessionPool

自從原生接口誕生以來,不少用戶就從 JDBC 遷移到原始接口了,咱們也擴充了原生接口的能力,增長了 Session 的鏈接池(東哥傾情奉獻)。鏈接池的接口和 Session 基本同樣,可是鏈接池能夠供多線程使用,並且能夠屏蔽鏈接異常等問題。

使用鏈接池惟一一點須要注意的是,查詢獲得的結果集使用完須要返還給鏈接池(調用鏈接池的 closeResultSet 方法),否則鏈接會被佔用,沒法獲得新的鏈接就報超時了。

SessionDataSetWrapper wrapper = null;
try {
  wrapper = pool.executeQueryStatement("select * from root.sg1.d1");
  while (wrapper.hasNext()) {
    System.out.println(wrapper.next());
  }
} catch (IoTDBConnectionException | StatementExecutionException e) {
  e.printStackTrace();
} finally {
  // remember to close data set finally!
  pool.closeResultSet(wrapper);
}

完整的示例代碼位置:

https://github.com/apache/incubator-iotdb/blob/master/example/session/src/main/java/org/apache/iotdb/SessionPoolExample.java

Python 接口

除了 JAVA 的接口,咱們還包裝了一下 Python 的接口,是在 0.9 版本以後才增長的。位置在 

https://github.com/apache/incubator-iotdb/blob/master/client-py

總結

今天主要介紹了 JDBC 接口、JAVA 原生接口 Session 和鏈接池,裏邊有一些注意事項,好比使用 SessionPool 作查詢時,須要手動關閉結果集(我對這個印象深入,曾經踩了幾天的坑)。