說了半天語法和部署運維,實際使用仍是要落到代碼裏的,今天介紹一下客戶端的接口。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 作查詢時,須要手動關閉結果集(我對這個印象深入,曾經踩了幾天的坑)。