跳到主要内容

TDengine Java Connector

taos-jdbcdriver 是 TDengine 的官方 Java 语言连接器,Java 开发人员可以通过它开发存取 TDengine 数据库的应用软件。taos-jdbcdriver 实现了 JDBC driver 标准的接口,通过 REST 接口连接 TDengine 实例。

TDengine DataType 和 Java DataType

TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对应类型转换如下:

TDengine DataTypeJDBCType
TIMESTAMPjava.sql.Timestamp
INTjava.lang.Integer
BIGINTjava.lang.Long
FLOATjava.lang.Float
DOUBLEjava.lang.Double
SMALLINTjava.lang.Short
TINYINTjava.lang.Byte
BOOLjava.lang.Boolean
BINARYbyte array
NCHARjava.lang.String
JSONjava.lang.String

注意:JSON 类型仅在 tag 中支持。

安装步骤

安装前准备

使用 Java Connector 连接数据库前,需要具备以下条件:

  • 已安装 Java 1.8 或以上版本运行时环境和 Maven 3.6 或以上版本
  • 已安装 TDengine 客户端驱动(使用原生连接必须安装,使用 REST 连接无需安装),具体步骤请参考安装客户端驱动

安装连接器

目前 taos-jdbcdriver 已经发布到 Sonatype Repository 仓库,且各大仓库都已同步。

Maven 项目中,在 pom.xml 中添加以下依赖:

<dependency>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>3.2.7</version>
</dependency>

建立连接

TDengine 的 JDBC URL 规范格式为: jdbc:TAOS-RS://[host_name]:[port]/[database_name]?batchfetch={true|false}&useSSL={true|false}&token={token}&httpPoolSize={httpPoolSize}&httpKeepAlive={true|false}]&httpConnectTimeout={httpTimeout}&httpSocketTimeout={socketTimeout}

Class.forName("com.taosdata.jdbc.rs.RestfulDriver");
String jdbcUrl = "jdbc:TAOS-RS://taosdemo.com:6041/test?user=root&password=taosdata";
Connection conn = DriverManager.getConnection(jdbcUrl);
IMPORTANT
  • REST 接口是无状态的。在使用 JDBC REST 连接时,需要在 SQL 中指定表、超级表的数据库名称。例如:
INSERT INTO test.t1 USING test.weather (ts, temperature) TAGS('California.SanFrancisco') VALUES(now, 24.6);
  • 如果在 URL 中指定了 dbname,那么 JDBC REST 连接会默认使用 /rest/sql/dbname 作为 restful 请求的 URL,在 SQL 中不需要指定 dbname。例如:URL 为 jdbc:TAOS-RS://127.0.0.1:6041/test,那么,可以执行 SQL:

    insert into t1 using weather(ts, temperature) tags('California.SanFrancisco') values(now, 24.6);

指定 URL 和 Properties 获取连接

除了通过指定的 URL 获取连接,还可以使用 Properties 指定建立连接时的参数。

注意

  • 应用中设置的 client parameter 为进程级别的,即如果要更新 client 的参数,需要重启应用。这是因为 client parameter 是全局参数,仅在应用程序的第一次设置生效。
  • 以下示例代码基于 taos-jdbcdriver-3.0.0。
public Connection getRestConn() throws Exception{
Class.forName("com.taosdata.jdbc.rs.RestfulDriver");
String jdbcUrl = System.getenv("TDENGINE_JDBC_URL");
Properties connProps = new Properties();
connProps.setProperty(TSDBDriver.PROPERTY_KEY_BATCH_LOAD, "true");
Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
return conn;
}

配置参数的优先级

通过前面三种方式获取连接,如果配置参数在 url、Properties、客户端配置文件中有重复,则参数的优先级由高到低分别如下:

  1. JDBC URL 参数,如上所述,可以在 JDBC URL 的参数中指定。
  2. Properties connProps

使用示例

创建数据库和表

Statement stmt = conn.createStatement();

// create database
stmt.executeUpdate("create database if not exists db");

// use database
stmt.executeUpdate("use db");

// create table
stmt.executeUpdate("create table if not exists tb (ts timestamp, temperature int, humidity float)");

插入数据

// insert data
int affectedRows = stmt.executeUpdate("insert into tb values(now, 23, 10.3) (now + 1s, 20, 9.3)");

System.out.println("insert " + affectedRows + " rows.");

now 为系统内部函数,默认为客户端所在计算机当前时间。 now + 1s 代表客户端当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒),s(秒),m(分),h(小时),d(天),w(周),n(月),y(年)。

查询数据

// query data
ResultSet resultSet = stmt.executeQuery("select * from tb");

Timestamp ts = null;
int temperature = 0;
float humidity = 0;
while(resultSet.next()){

ts = resultSet.getTimestamp(1);
temperature = resultSet.getInt(2);
humidity = resultSet.getFloat("humidity");

System.out.printf("%s, %d, %s\n", ts, temperature, humidity);
}

查询和操作关系型数据库一致,使用下标获取返回字段内容时从 1 开始,建议使用字段名称获取。

处理异常

在报错后,通过 SQLException 可以获取到错误的信息和错误码:

try (Statement statement = connection.createStatement()) {
// executeQuery
ResultSet resultSet = statement.executeQuery(sql);
// print result
printResult(resultSet);
} catch (SQLException e) {
System.out.println("ERROR Message: " + e.getMessage());
System.out.println("ERROR Code: " + e.getErrorCode());
e.printStackTrace();
}

JDBC 连接器可能报错的错误码包括 3 种:JDBC driver 本身的报错(错误码在 0x2301 到 0x2350 之间),原生连接方法的报错(错误码在 0x2351 到 0x2400 之间),TDengine 其他功能模块的报错。

具体的错误码请参考:

关闭资源

resultSet.close();
stmt.close();
conn.close();
IMPORTANT

请确保关闭连接,否则会造成连接池泄露。

与连接池使用

HikariCP

使用示例如下:

 public static void main(String[] args) throws SQLException {
HikariConfig config = new HikariConfig();
// jdbc properties
config.setJdbcUrl("jdbc:TAOS://127.0.0.1:6030/log");
config.setUsername("root");
config.setPassword("taosdata");
// connection pool configurations
config.setMinimumIdle(10); //minimum number of idle connection
config.setMaximumPoolSize(10); //maximum number of connection in the pool
config.setConnectionTimeout(30000); //maximum wait milliseconds for get connection from pool
config.setMaxLifetime(0); // maximum life time for each connection
config.setIdleTimeout(0); // max idle time for recycle idle connection
config.setConnectionTestQuery("select server_status()"); //validation query

HikariDataSource ds = new HikariDataSource(config); //create datasource

Connection connection = ds.getConnection(); // get connection
Statement statement = connection.createStatement(); // get statement

//query or insert
// ...

connection.close(); // put back to connection pool
}

通过 HikariDataSource.getConnection() 获取连接后,使用完成后需要调用 close() 方法,实际上它并不会关闭连接,只是放回连接池中。 更多 HikariCP 使用问题请查看官方说明

Druid

使用示例如下:

public static void main(String[] args) throws Exception {

DruidDataSource dataSource = new DruidDataSource();
// jdbc properties
dataSource.setDriverClassName("com.taosdata.jdbc.TSDBDriver");
dataSource.setUrl(url);
dataSource.setUsername("root");
dataSource.setPassword("taosdata");
// pool configurations
dataSource.setInitialSize(10);
dataSource.setMinIdle(10);
dataSource.setMaxActive(10);
dataSource.setMaxWait(30000);
dataSource.setValidationQuery("select server_status()");

Connection connection = dataSource.getConnection(); // get connection
Statement statement = connection.createStatement(); // get statement
//query or insert
// ...

connection.close(); // put back to connection pool
}

更多 druid 使用问题请查看官方说明

更多示例程序

示例程序源码位于 TDengine/examples/JDBC 下:

  • JDBCDemo:JDBC 示例源程序。
  • JDBCConnectorChecker:JDBC 安装校验源程序及 jar 包。
  • connectionPools:HikariCP, Druid, dbcp, c3p0 等连接池中使用 taos-jdbcdriver。
  • SpringJdbcTemplate:Spring JdbcTemplate 中使用 taos-jdbcdriver。
  • mybatisplus-demo:Springboot + Mybatis 中使用 taos-jdbcdriver。

请参考:JDBC example

最近更新记录

taos-jdbcdriver 版本主要变化
3.0.3修复 REST 连接在 jdk17+ 版本时间戳解析错误问题
3.0.1 - 3.0.2修复一些情况下结果集数据解析错误的问题。3.0.1 在 JDK 11 环境编译,JDK 8 环境下建议使用 3.0.2 版本
3.0.0支持 TDengine 3.0
2.0.42修在 WebSocket 连接中 wasNull 接口返回值
2.0.41修正 REST 连接中用户名和密码转码方式
2.0.39 - 2.0.40增加 REST 连接/请求 超时设置
2.0.38JDBC REST 连接增加批量拉取功能
2.0.37增加对 json tag 支持
2.0.36增加对 schemaless 写入支持

常见问题

  1. 使用 Statement 的 addBatch()executeBatch() 来执行“批量写入/更新”,为什么没有带来性能上的提升?

原因:TDengine 的 JDBC 实现中,通过 addBatch 方法提交的 SQL 语句,会按照添加的顺序,依次执行,这种方式没有减少与服务端的交互次数,不会带来性能上的提升。

解决方法:1. 在一条 insert 语句中拼接多个 values 值;2. 使用多线程的方式并发插入;3. 使用参数绑定的写入方式

  1. java.lang.UnsatisfiedLinkError: no taos in java.library.path

原因:程序没有找到依赖的本地函数库 taos。

解决方法:Windows 下可以将 C:\TDengine\driver\taos.dll 拷贝到 C:\Windows\System32\ 目录下,Linux 下将建立如下软链 ln -s /usr/local/taos/driver/libtaos.so.x.x.x.x /usr/lib/libtaos.so 即可,macOS 下需要建立软链 ln -s /usr/local/lib/libtaos.dylib

  1. java.lang.UnsatisfiedLinkError: taos.dll Can't load AMD 64 bit on a IA 32-bit platform

原因:目前 TDengine 只支持 64 位 JDK。

解决方法:重新安装 64 位 JDK。

  1. java.lang.NoSuchMethodError: setByteArray

原因:taos-jdbcdriver 3.* 版本仅支持 TDengine 3.0 及以上版本。

解决方法: 使用 taos-jdbcdriver 2.* 版本连接 TDengine 2.* 版本。

  1. java.lang.NoSuchMethodError: java.nio.ByteBuffer.position(I)Ljava/nio/ByteBuffer; ... taos-jdbcdriver-3.0.1.jar

原因:taos-jdbcdriver 3.0.1 版本需要在 JDK 11+ 环境使用。

API 参考

taos-jdbcdriver doc