说了半天语法和部署运维,实际使用仍是要落到代码里的,今天介绍一下客户端的接口。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 作查询时,须要手动关闭结果集(我对这个印象深入,曾经踩了几天的坑)。