无码人妻精品一区二区三18禁,影音先锋男人AV橹橹色,污污污污污污www网站免费,日韩成人av无码一区二区三区,欧美性受xxxx狂喷水

Java Connector

總體介紹

taos-jdbcdriver 的(de)(de)實(shi)現(xian)包括 2 種(zhong)形式: JDBC-JNI 和 JDBC-RESTful(taos-jdbcdriver-2.0.18 開始支(zhi)持 JDBC-RESTful)。 JDBC-JNI 通(tong)過調用(yong)客戶端 libtaos.so(或 taos.dll )的(de)(de)本地方法實(shi)現(xian), JDBC-RESTful 則在內部封(feng)裝了 RESTful 接(jie)口實(shi)現(xian)。

tdengine-connector

上(shang)圖顯(xian)示了 3 種 Java 應用使用連接器訪問(wen) TDengine 的方式(shi):

  • JDBC-JNI:Java 應用在物理節點1(pnode1)上使用 JDBC-JNI 的 API ,直接調用客戶端 API(libtaos.so 或 taos.dll)將寫入和查詢請求發送到位于物理節點2(pnode2)上的 taosd 實例。
  • RESTful:應用將 SQL 發送給位于物理節點2(pnode2)上的 RESTful 連接器,再調用客戶端 API(libtaos.so)。
  • JDBC-RESTful:Java 應用通過 JDBC-RESTful 的 API ,將 SQL 封裝成一個 RESTful 請求,發送給物理節點2的 RESTful 連接器。

TDengine 的 JDBC 驅動實現盡可能與關系型數據庫驅動保持一致,但TDengine與關系對象型數據庫的使用場景和技術特征存在差異,導致 taos-jdbcdriver 與傳(chuan)統的 JDBC driver 也存(cun)在(zai)(zai)一定(ding)差異。在(zai)(zai)使用時需要注意以下幾點:

  • TDengine 目前不支持針對單條數據記錄的刪除操作。
  • 目前不支持事務操作。

JDBC-JNI和JDBC-RESTful的對比

對比項JDBC-JNIJDBC-RESTful
支持的操作系統 Linux、Windows 全平臺
是否需要安裝 client 需要 不需要
server 升級后是否需要升級 client 需要 不需要
寫入性能 JDBC-RESTful 是 JDBC-JNI 的 50%~90%
查詢性能 JDBC-RESTful 與 JDBC-JNI 沒有差別

注意:

  • 與 JNI 方式不同,RESTful 接口是無狀態的。在使用JDBC-RESTful時,需要在sql中指定表、超級表的數據庫名稱。例如:
    INSERT INTO test.t1 USING test.weather (ts, temperature) TAGS('beijing') VALUES(now, 24.6);
  • 從taos-jdbcdriver-2.0.36和TDengine 2.2.0.0 版本開始,如果在url中指定了dbname,那么,JDBC-RESTful會默認使用/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('beijing') values(now, 24.6);

TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本

taos-jdbcdriver 版本 TDengine 2.0.x.x 版本 TDengine 2.2.x.x 版本 TDengine 2.4.x.x 版本 JDK 版本
2.0.38 X X 2.4.0.14 及以上 1.8.x
2.0.37 X X 2.4.0.6 及以上 1.8.x
2.0.36 X 2.2.2.11 及以上 2.4.0.0 - 2.4.0.5 1.8.x
2.0.35 X 2.2.2.11 及以上 2.3.0.0 - 2.4.0.5 1.8.x
2.0.33 - 2.0.34 2.0.3.0 及以上 2.2.0.0 及以上 2.4.0.0 - 2.4.0.5 1.8.x
2.0.31 - 2.0.32 2.1.3.0 - 2.1.7.7 X X 1.8.x
2.0.22 - 2.0.30 2.0.18.0 - 2.1.2.1 X X 1.8.x
2.0.12 - 2.0.21 2.0.8.0 - 2.0.17.4 X X 1.8.x
2.0.4 - 2.0.11 2.0.0.0 - 2.0.7.3 X X 1.8.x

TDengine DataType 和 Java DataType

TDengine 目前(qian)支持時(shi)間戳、數字、字符、布(bu)爾(er)類型(xing),與 Java 對應類型(xing)轉換如下:

TDengine DataType JDBCType (driver 版本 < 2.0.24) JDBCType (driver 版本 >= 2.0.24)
TIMESTAMP java.lang.Long java.sql.Timestamp
INT java.lang.Integer java.lang.Integer
BIGINT java.lang.Long java.lang.Long
FLOAT java.lang.Float java.lang.Float
DOUBLE java.lang.Double java.lang.Double
SMALLINT java.lang.Short java.lang.Short
TINYINT java.lang.Byte java.lang.Byte
BOOL java.lang.Boolean java.lang.Boolean
BINARY java.lang.String byte array
NCHAR java.lang.String java.lang.String
JSON - java.lang.String

注意:JSON類(lei)型(xing)僅在tag中支持。

安裝Java Connector

安裝前準備

使用Java Connector連接(jie)數據(ju)庫前,需要具(ju)備以下條件(jian):

  1. Linux或Windows操作系統
  2. Java 1.8以上運行時環境
  3. TDengine-client(使用JDBC-JNI時必須,使用JDBC-RESTful時非必須)

注意:由于 TDengine 的應(ying)用(yong)(yong)驅(qu)(qu)動是使用(yong)(yong)C語言(yan)開(kai)發的,使用(yong)(yong) taos-jdbcdriver 驅(qu)(qu)動包時需(xu)要依(yi)賴系統對應(ying)的本地函數(shu)庫(ku)。

  • libtaos.so 在 Linux 系統中成功安裝 TDengine 后,依賴的本地函數庫 libtaos.so 文件會被自動拷貝至 /usr/lib/libtaos.so,該目錄包含在 Linux 自動掃描路徑上,無需單獨指定。
  • taos.dll 在 Windows 系統中安裝完客戶端之后,驅動包依賴的 taos.dll 文件會自動拷貝到系統默認搜索路徑 C:/Windows/System32 下,同樣無需要單獨指定。

注意:在 Windows 環境開發時需要安裝 TDengine 對應的 windows 客戶端,Linux 服務器安裝完 TDengine 之后默認已安裝 client,也可以單獨安裝 Linux 客戶端 連接遠程 TDengine Server。

通過maven獲取JDBC driver

目前 taos-jdbcdriver 已(yi)經(jing)發布到  倉(cang)庫,且各(ge)大(da)倉(cang)庫都已(yi)同步(bu)。

maven 項目(mu)中,在pom.xml 中添加以下依賴:

<dependency>
 <groupId>com.taosdata.jdbc</groupId>
 <artifactId>taos-jdbcdriver</artifactId>
 <!--具體版本請參考上面的版本對應表-->
 <version>2.x.xx</version>
</dependency>

通過源碼編譯獲取JDBC driver

可以(yi)通(tong)過下載TDengine的(de)源(yuan)碼,自己編譯最新版本的(de)java connector

git clone //github.com/taosdata/TDengine.git
cd TDengine/src/connector/jdbc
mvn clean package -Dmaven.test.skip=true

編譯后,在target目(mu)錄下會產生taos-jdbcdriver-2.0.XX-dist.jar的(de)jar包。

Java連接器的使用

獲取連接

指定URL獲取連接

通過(guo)指定URL獲取連(lian)接(jie),如下所示:

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);

以上示例,使用 JDBC-RESTful 的(de) driver,建立了到(dao) hostname 為(wei)(wei) taosdemo.com,端口為(wei)(wei) 6041,數(shu)據庫(ku)名為(wei)(wei) test 的(de)連接。這個 URL 中指(zhi)定(ding)用戶(hu)名(user)為(wei)(wei) root,密碼(password)為(wei)(wei) taosdata。

使用 JDBC-RESTful 接口,不需(xu)要(yao)依賴本地函數庫。與 JDBC-JNI 相比(bi),僅需(xu)要(yao):

  1. driverClass 指定為“com.taosdata.jdbc.rs.RestfulDriver”;
  2. jdbcUrl 以“jdbc:TAOS-RS://”開頭;
  3. 使用 6041 作為連接端口。

從 taos-jdbcdriver-2.0.38 和 TDengine 2.4.0.12 版本開始,JDBC-RESTful 的 driver 增加批量拉取數據功能。taos-jdbcdriver 與 TDengine 之間通過 WebSocket 連接進行數據傳輸。相較于 HTTP,WebSocket 可以使 JDBC-RESTful 支持大數據量查詢,并(bing)提(ti)升(sheng)查詢性(xing)能。

連接開(kai)啟批量拉取(qu)方式(shi):

String url = "jdbc:TAOS-RS://taosdemo.com:6041/?user=root&password=taosdata";Properties properties = new Properties();
properties.setProperty(TSDBDriver.PROPERTY_KEY_BATCH_LOAD, "true");
Connection connection = DriverManager.getConnection(url, properties);

如果希望獲得更好的寫入和查詢性能,Java 應用可以使用 JDBC-JNI 的 driver,如下(xia)所示:

Class.forName("com.taosdata.jdbc.TSDBDriver");
String jdbcUrl = "jdbc:TAOS://taosdemo.com:6030/test?user=root&password=taosdata";
Connection conn = DriverManager.getConnection(jdbcUrl);

以上示(shi)例,使(shi)用(yong)了 JDBC-JNI 的 driver,建(jian)立了到 hostname 為(wei) taosdemo.com,端口為(wei) 6030(TDengine 的默認端口),數據庫(ku)名(ming)為(wei) test 的連(lian)接。這個 URL 中指定(ding)用(yong)戶(hu)名(ming)(user)為(wei) root,密碼(ma)(password)為(wei) taosdata。

注意:使用(yong) JDBC-JNI 的(de) driver,taos-jdbcdriver 驅(qu)動包時需要依(yi)賴系統對應的(de)本地函數庫(Linux 下(xia)是 libtaos.so;Windows 下(xia)是 taos.dll)。

在 Windows 環境開發時需要安裝 TDengine 對應的 windows 客戶端,Linux 服務器安裝完 TDengine 之后默認已安裝 client,也可以單獨安裝 Linux 客戶端 連接遠程 TDengine Server。

JDBC-JNI 的使用請參見視頻教程

TDengine 的 JDBC URL 規范格式為: jdbc:[TAOS|TAOS-RS]://[host_name]:[port]/[database_name]?[user={user}|&password={password}|&charset={charset}|&cfgdir={config_dir}|&locale={locale}|&timezone={timezone}]

url中的(de)配置參數如下:

  • user:登錄 TDengine 用戶名,默認值 'root'。
  • password:用戶登錄密碼,默認值 'taosdata'。
  • cfgdir:客戶端配置文件目錄路徑,Linux OS 上默認值 /etc/taos,Windows OS 上默認值 C:/TDengine/cfg
  • charset:客戶端使用的字符集,默認值為系統字符集。
  • locale:客戶端語言環境,默認值系統當前 locale。
  • timezone:客戶端使用的時區,默認值為系統當前時區。
  • batchfetch: 僅在使用JDBC-JNI時生效。true:在執行查詢時批量拉取結果集;false:逐行拉取結果集。默認值為:false。
  • timestampFormat: 僅在使用JDBC-RESTful時生效. 'TIMESTAMP':結果集中timestamp類型的字段為一個long值; 'UTC':結果集中timestamp類型的字段為一個UTC時間格式的字符串; 'STRING':結果集中timestamp類型的字段為一個本地時間格式的字符串。默認值為'STRING'。
  • batchErrorIgnore:true:在執行Statement的executeBatch時,如果中間有一條sql執行失敗,繼續執行下面的sql了。false:不再執行失敗sql后的任何語句。默認值為:false。

指定URL和Properties獲取連接

除了通過指定(ding)的(de) URL 獲取連(lian)接,還可以使用 Properties 指定(ding)建立連(lian)接時的(de)參數(shu),如下所示:

public Connection getConn() throws Exception{
  Class.forName("com.taosdata.jdbc.TSDBDriver");
  // Class.forName("com.taosdata.jdbc.rs.RestfulDriver");
  String jdbcUrl = "jdbc:TAOS://taosdemo.com:6030/test?user=root&password=taosdata";
  // String jdbcUrl = "jdbc:TAOS-RS://taosdemo.com:6041/test?user=root&password=taosdata";
  Properties connProps = new Properties();
  connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
  connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
  connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
  Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
  return conn;
}

以上示例(li),建(jian)立(li)一個到 hostname 為(wei) taosdemo.com,端口為(wei) 6030,數據庫名為(wei) test 的連接(jie)。注釋為(wei)使用(yong)(yong) JDBC-RESTful 時的方(fang)法。這個連接(jie)在 url 中指定(ding)了用(yong)(yong)戶(hu)名(user)為(wei) root,密碼(password)為(wei) taosdata,并(bing)在 connProps 中指定(ding)了使用(yong)(yong)的字符集、語言環境、時區等信息。

properties 中的配(pei)置參數如下:

  • TSDBDriver.PROPERTY_KEY_USER:登錄 TDengine 用戶名,默認值 'root'。
  • TSDBDriver.PROPERTY_KEY_PASSWORD:用戶登錄密碼,默認值 'taosdata'。
  • TSDBDriver.PROPERTY_KEY_CONFIG_DIR:客戶端配置文件目錄路徑,Linux OS 上默認值 /etc/taos,Windows OS 上默認值 C:/TDengine/cfg
  • TSDBDriver.PROPERTY_KEY_CHARSET:客戶端使用的字符集,默認值為系統字符集。
  • TSDBDriver.PROPERTY_KEY_LOCALE:客戶端語言環境,默認值系統當前 locale。
  • TSDBDriver.PROPERTY_KEY_TIME_ZONE:客戶端使用的時區,默認值為系統當前時區。
  • TSDBDriver.PROPERTY_KEY_BATCH_LOAD: true:在執行查詢時批量拉取結果集;false:逐行拉取結果集。默認值為:false。
  • TSDBDriver.PROPERTY_KEY_TIMESTAMP_FORMAT: 僅在使用JDBC-RESTful時生效. 'TIMESTAMP':結果集中timestamp類型的字段為一個long值; 'UTC':結果集中timestamp類型的字段為一個UTC時間格式的字符串; 'STRING':結果集中timestamp類型的字段為一個本地時間格式的字符串。默認值為'STRING'。
  • TSDBDriver.PROPERTY_KEY_BATCH_ERROR_IGNORE:true:在執行Statement的executeBatch時,如果中間有一條sql執行失敗,繼續執行下面的sq了。false:不再執行失敗sql后的任何語句。默認值為:false。

使用客戶端配置文件建立連接

當使用 JDBC-JNI 連接 TDengine 集群時,可以(yi)使用客(ke)戶(hu)端配置(zhi)文(wen)件(jian),在客(ke)戶(hu)端配置(zhi)文(wen)件(jian)中指定集群的 firstEp、secondEp參數(shu)。如下(xia)所(suo)示:

  1. 在 Java 應用中不指定 hostname 和 port
public Connection getConn() throws Exception{
  Class.forName("com.taosdata.jdbc.TSDBDriver");
  String jdbcUrl = "jdbc:TAOS://:/test?user=root&password=taosdata";
  Properties connProps = new Properties();
  connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
  connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
  connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
  Connection conn = DriverManager.getConnection(jdbcUrl, connProps);
  return conn;
}
  1. 在配置文件中指定 firstEp 和 secondEp
# first fully qualified domain name (FQDN) for TDengine system
firstEp               cluster_node1:6030

# second fully qualified domain name (FQDN) for TDengine system, for cluster only
secondEp              cluster_node2:6030

# default system charset
# charset               UTF-8  

# system locale
# locale                en_US.UTF-8

以上示例,jdbc 會(hui)使(shi)用客戶(hu)端的(de)(de)配置文(wen)件(jian),建立到(dao) hostname 為 cluster_node1、端口為 6030、數據庫(ku)名為 test 的(de)(de)連(lian)接。當集群中(zhong) firstEp 節點失效時,JDBC 會(hui)嘗試使(shi)用 secondEp 連(lian)接集群。

TDengine 中,只要保(bao)證 firstEp 和 secondEp 中一個節(jie)點有效,就可以正(zheng)常建立到集群(qun)的(de)連接。

注意:這里(li)的(de)(de)配置文件指(zhi)的(de)(de)是(shi)調用 JDBC Connector 的(de)(de)應用程序所在機器上的(de)(de)配置文件,Linux OS 上默(mo)認(ren)值 /etc/taos/taos.cfg ,Windows OS 上默(mo)認(ren)值 C://TDengine/cfg/taos.cfg。

配置參數的優先級

通過以上 3 種方式獲取連接,如果配置參數在 url、Properties、客戶端配置文件中有重復,則參數的優先級由高到低分別如下:

  1. JDBC URL 參數,如上所述,可以在 JDBC URL 的參數中指定。
  2. Properties connProps
  3. 客戶端配置文件 taos.cfg

例如:在(zai) url 中(zhong)指定了 password 為(wei) taosdata,在(zai) Properties 中(zhong)指定了 password 為(wei) taosdemo,那么,JDBC 會(hui)使用 url 中(zhong)的(de) password 建立連接(jie)。

更多詳細配置請參考客戶端配置

創建數據庫和表

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)");

注意:如果不使用 use db 指定(ding)數據庫(ku),則后續對表的操作都需要增加數據庫(ku)名稱作為前綴,如 db.tb。

插入數據

// 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 代表客戶端當(dang)前時(shi)間(jian)往后加(jia) 1 秒(miao)(miao),數字(zi)后面代表時(shi)間(jian)單位:a(毫秒(miao)(miao)),s(秒(miao)(miao)),m(分),h(小時(shi)),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);
}

查詢和操作關系型數據庫(ku)一(yi)致,使用下標獲(huo)取返回字段(duan)內容(rong)時從 1 開始,建議使用字段(duan)名稱獲(huo)取。

處理異常

在(zai)報錯(cuo)后,通過SQLException可(ke)以獲取到錯(cuo)誤(wu)的信(xin)息和錯(cuo)誤(wu)碼:

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連接器可(ke)能(neng)報錯(cuo)(cuo)的錯(cuo)(cuo)誤(wu)碼(ma)包括3種:JDBC driver本身的報錯(cuo)(cuo)(錯(cuo)(cuo)誤(wu)碼(ma)在0x2301到0x2350之間(jian)),JNI方法的報錯(cuo)(cuo)(錯(cuo)(cuo)誤(wu)碼(ma)在0x2351到0x2400之間(jian)),TDengine其他(ta)功(gong)能(neng)模塊的報錯(cuo)(cuo)。

具體的錯誤(wu)碼請參考:

  • //github.com/taosdata/TDengine/blob/develop/src/connector/jdbc/src/main/java/com/taosdata/jdbc/TSDBErrorNumbers.java
  • //github.com/taosdata/TDengine/blob/develop/src/inc/taoserror.h

通過參數綁定寫入數據

從(cong) 2.1.2.0 版本開始,TDengine 的(de) JDBC-JNI 實(shi)現大幅改進(jin)了參數綁定方式(shi)對數據寫入(ru)(INSERT)場景的(de)支持。采用這種方式(shi)寫入(ru)數據時,能避(bi)免 SQL 語(yu)法解析(xi)的(de)資(zi)源消耗,從(cong)而在很多情況下顯著(zhu)提升寫入(ru)性能。 注意:

  • JDBC-RESTful 實現并不提供參數綁定這種使用方式
  • 以下示例代碼基于taos-jdbcdriver-2.0.36
  • binary類型數據需要調用setString方法,nchar類型數據需要調用setNString方法
  • setString 和 setNString 都要求用戶在 size 參數里聲明表定義中對應列的列寬

示例代碼:

public class ParameterBindingDemo {

    private static final String host = "127.0.0.1";
    private static final Random random = new Random(System.currentTimeMillis());
    private static final int BINARY_COLUMN_SIZE = 20;
    private static final String[] schemaList = {
            "create table stable1(ts timestamp, f1 tinyint, f2 smallint, f3 int, f4 bigint) tags(t1 tinyint, t2 smallint, t3 int, t4 bigint)",
            "create table stable2(ts timestamp, f1 float, f2 double) tags(t1 float, t2 double)",
            "create table stable3(ts timestamp, f1 bool) tags(t1 bool)",
            "create table stable4(ts timestamp, f1 binary(" + BINARY_COLUMN_SIZE + ")) tags(t1 binary(" + BINARY_COLUMN_SIZE + "))",
            "create table stable5(ts timestamp, f1 nchar(" + BINARY_COLUMN_SIZE + ")) tags(t1 nchar(" + BINARY_COLUMN_SIZE + "))"
    };
    private static final int numOfSubTable = 10, numOfRow = 10;

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

        String jdbcUrl = "jdbc:TAOS://" + host + ":6030/";
        Connection conn = DriverManager.getConnection(jdbcUrl, "root", "taosdata");

        init(conn);

        bindInteger(conn);

        bindFloat(conn);

        bindBoolean(conn);

        bindBytes(conn);

        bindString(conn);

        conn.close();
    }

    private static void init(Connection conn) throws SQLException {
        try (Statement stmt = conn.createStatement()) {
            stmt.execute("drop database if exists test_parabind");
            stmt.execute("create database if not exists test_parabind");
            stmt.execute("use test_parabind");
            for (int i = 0; i < schemaList.length; i++) {
                stmt.execute(schemaList[i]);
            }
        }
    }

    private static void bindInteger(Connection conn) throws SQLException {
        String sql = "insert into ? using stable1 tags(?,?,?,?) values(?,?,?,?,?)";

        try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) {

            for (int i = 1; i <= numOfSubTable; i++) {
                // set table name
                pstmt.setTableName("t1_" + i);
                // set tags
                pstmt.setTagByte(0, Byte.parseByte(Integer.toString(random.nextInt(Byte.MAX_VALUE))));
                pstmt.setTagShort(1, Short.parseShort(Integer.toString(random.nextInt(Short.MAX_VALUE))));
                pstmt.setTagInt(2, random.nextInt(Integer.MAX_VALUE));
                pstmt.setTagLong(3, random.nextLong());
                // set columns
                ArrayList<Long> tsList = new ArrayList<>();
                long current = System.currentTimeMillis();
                for (int j = 0; j < numOfRow; j++)
                    tsList.add(current + j);
                pstmt.setTimestamp(0, tsList);

                ArrayList<Byte> f1List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++)
                    f1List.add(Byte.parseByte(Integer.toString(random.nextInt(Byte.MAX_VALUE))));
                pstmt.setByte(1, f1List);

                ArrayList<Short> f2List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++)
                    f2List.add(Short.parseShort(Integer.toString(random.nextInt(Short.MAX_VALUE))));
                pstmt.setShort(2, f2List);

                ArrayList<Integer> f3List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++)
                    f3List.add(random.nextInt(Integer.MAX_VALUE));
                pstmt.setInt(3, f3List);

                ArrayList<Long> f4List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++)
                    f4List.add(random.nextLong());
                pstmt.setLong(4, f4List);

                // add column
                pstmt.columnDataAddBatch();
            }
            // execute column
            pstmt.columnDataExecuteBatch();
        }
    }

    private static void bindFloat(Connection conn) throws SQLException {
        String sql = "insert into ? using stable2 tags(?,?) values(?,?,?)";

        TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class);

        for (int i = 1; i <= numOfSubTable; i++) {
            // set table name
            pstmt.setTableName("t2_" + i);
            // set tags
            pstmt.setTagFloat(0, random.nextFloat());
            pstmt.setTagDouble(1, random.nextDouble());
            // set columns
            ArrayList<Long> tsList = new ArrayList<>();
            long current = System.currentTimeMillis();
            for (int j = 0; j < numOfRow; j++)
                tsList.add(current + j);
            pstmt.setTimestamp(0, tsList);

            ArrayList<Float> f1List = new ArrayList<>();
            for (int j = 0; j < numOfRow; j++)
                f1List.add(random.nextFloat());
            pstmt.setFloat(1, f1List);

            ArrayList<Double> f2List = new ArrayList<>();
            for (int j = 0; j < numOfRow; j++)
                f2List.add(random.nextDouble());
            pstmt.setDouble(2, f2List);

            // add column
            pstmt.columnDataAddBatch();
        }
        // execute
        pstmt.columnDataExecuteBatch();
        // close if no try-with-catch statement is used
        pstmt.close();
    }

    private static void bindBoolean(Connection conn) throws SQLException {
        String sql = "insert into ? using stable3 tags(?) values(?,?)";

        try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) {
            for (int i = 1; i <= numOfSubTable; i++) {
                // set table name
                pstmt.setTableName("t3_" + i);
                // set tags
                pstmt.setTagBoolean(0, random.nextBoolean());
                // set columns
                ArrayList<Long> tsList = new ArrayList<>();
                long current = System.currentTimeMillis();
                for (int j = 0; j < numOfRow; j++)
                    tsList.add(current + j);
                pstmt.setTimestamp(0, tsList);

                ArrayList<Boolean> f1List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++)
                    f1List.add(random.nextBoolean());
                pstmt.setBoolean(1, f1List);

                // add column
                pstmt.columnDataAddBatch();
            }
            // execute
            pstmt.columnDataExecuteBatch();
        }
    }

    private static void bindBytes(Connection conn) throws SQLException {
        String sql = "insert into ? using stable4 tags(?) values(?,?)";

        try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) {

            for (int i = 1; i <= numOfSubTable; i++) {
                // set table name
                pstmt.setTableName("t4_" + i);
                // set tags
                pstmt.setTagString(0, new String("abc"));

                // set columns
                ArrayList<Long> tsList = new ArrayList<>();
                long current = System.currentTimeMillis();
                for (int j = 0; j < numOfRow; j++)
                    tsList.add(current + j);
                pstmt.setTimestamp(0, tsList);

                ArrayList<String> f1List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++) {
                    f1List.add(new String("abc"));
                }
                pstmt.setString(1, f1List, BINARY_COLUMN_SIZE);

                // add column
                pstmt.columnDataAddBatch();
            }
            // execute
            pstmt.columnDataExecuteBatch();
        }
    }

    private static void bindString(Connection conn) throws SQLException {
        String sql = "insert into ? using stable5 tags(?) values(?,?)";

        try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) {

            for (int i = 1; i <= numOfSubTable; i++) {
                // set table name
                pstmt.setTableName("t5_" + i);
                // set tags
                pstmt.setTagNString(0, "北京-abc");

                // set columns
                ArrayList<Long> tsList = new ArrayList<>();
                long current = System.currentTimeMillis();
                for (int j = 0; j < numOfRow; j++)
                    tsList.add(current + j);
                pstmt.setTimestamp(0, tsList);

                ArrayList<String> f1List = new ArrayList<>();
                for (int j = 0; j < numOfRow; j++) {
                    f1List.add("北京-abc");
                }
                pstmt.setNString(1, f1List, BINARY_COLUMN_SIZE);

                // add column
                pstmt.columnDataAddBatch();
            }
            // execute
            pstmt.columnDataExecuteBatch();
        }
    }
}

用于設(she)定 TAGS 取值(zhi)的方法總共(gong)有:

public void setTagNull(int index, int type)
public void setTagBoolean(int index, boolean value)
public void setTagInt(int index, int value)
public void setTagByte(int index, byte value)
public void setTagShort(int index, short value)
public void setTagLong(int index, long value)
public void setTagTimestamp(int index, long value)
public void setTagFloat(int index, float value)
public void setTagDouble(int index, double value)
public void setTagString(int index, String value)
public void setTagNString(int index, String value)

用于設定(ding) VALUES 數據列(lie)的(de)取(qu)值的(de)方法總共有:

public void setInt(int columnIndex, ArrayList<Integer> list) throws SQLException
public void setFloat(int columnIndex, ArrayList<Float> list) throws SQLException
public void setTimestamp(int columnIndex, ArrayList<Long> list) throws SQLException
public void setLong(int columnIndex, ArrayList<Long> list) throws SQLException
public void setDouble(int columnIndex, ArrayList<Double> list) throws SQLException
public void setBoolean(int columnIndex, ArrayList<Boolean> list) throws SQLException
public void setByte(int columnIndex, ArrayList<Byte> list) throws SQLException
public void setShort(int columnIndex, ArrayList<Short> list) throws SQLException
public void setString(int columnIndex, ArrayList<String> list, int size) throws SQLException
public void setNString(int columnIndex, ArrayList<String> list, int size) throws SQLException

無模式寫入

從 2.2.0.0 版本開始,TDengine 增加了對無模式寫入功能。無模式寫入兼容 InfluxDB 的 行協議(Line Protocol)、OpenTSDB 的 telnet 行協議和 OpenTSDB 的 JSON 格式協議。詳情請參見無模式寫入

注意:

  • JDBC-RESTful 實現并不提供無模式寫入這種使用方式
  • 以下示例代碼基于taos-jdbcdriver-2.0.36

示例代碼:

public class SchemalessInsertTest {
    private static final String host = "127.0.0.1";
    private static final String lineDemo = "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000";
    private static final String telnetDemo = "stb0_0 1626006833 4 host=host0 interface=eth0";
    private static final String jsonDemo = "{\"metric\": \"meter_current\",\"timestamp\": 1346846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"Beijing\", \"id\": \"d1001\"}}";

    public static void main(String[] args) throws SQLException {
        final String url = "jdbc:TAOS://" + host + ":6030/?user=root&password=taosdata";
        try (Connection connection = DriverManager.getConnection(url)) {
            init(connection);

            SchemalessWriter writer = new SchemalessWriter(connection);
            writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO_SECONDS);
            writer.write(telnetDemo, SchemalessProtocolType.TELNET, SchemalessTimestampType.MILLI_SECONDS);
            writer.write(jsonDemo, SchemalessProtocolType.JSON, SchemalessTimestampType.NOT_CONFIGURED);
        }
    }

    private static void init(Connection connection) throws SQLException {
        try (Statement stmt = connection.createStatement()) {
            stmt.executeUpdate("drop database if exists test_schemaless");
            stmt.executeUpdate("create database if not exists test_schemaless");
            stmt.executeUpdate("use test_schemaless");
        }
    }
}

設置客戶端參數

從TDengine-2.3.5.0版本開始,jdbc driver支(zhi)(zhi)持在(zai)應用的(de)第一(yi)次連(lian)接中,設置TDengine的(de)客戶端參(can)數。Driver支(zhi)(zhi)持JDBC-JNI方(fang)式中,通過jdbcUrl和properties兩種方(fang)式設置client parameter。

注意:

  • JDBC-RESTful不支持設置client parameter的功能。
  • 應用中設置的client parameter為進程級別的,即如果要更新client的參數,需要重啟應用。這是因為client parameter是全局參數,僅在應用程序的第一次設置生效。
  • 以下示例代碼基于taos-jdbcdriver-2.0.36。

示例代碼:

public class ClientParameterSetting {
    private static final String host = "127.0.0.1";

    public static void main(String[] args) throws SQLException {
        setParameterInJdbcUrl();

        setParameterInProperties();
    }

    private static void setParameterInJdbcUrl() throws SQLException {
        String jdbcUrl = "jdbc:TAOS://" + host + ":6030/?debugFlag=135&asyncLog=0";

        Connection connection = DriverManager.getConnection(jdbcUrl, "root", "taosdata");

        printDatabase(connection);

        connection.close();
    }

    private static void setParameterInProperties() throws SQLException {
        String jdbcUrl = "jdbc:TAOS://" + host + ":6030/";
        Properties properties = new Properties();
        properties.setProperty("user", "root");
        properties.setProperty("password", "taosdata");
        properties.setProperty("debugFlag", "135");
        properties.setProperty("asyncLog", "0");
        properties.setProperty("maxSQLLength", "1048576");

        try (Connection conn = DriverManager.getConnection(jdbcUrl, properties)) {
            printDatabase(conn);
        }
    }

    private static void printDatabase(Connection connection) throws SQLException {
        try (Statement stmt = connection.createStatement()) {
            ResultSet rs = stmt.executeQuery("show databases");

            ResultSetMetaData meta = rs.getMetaData();
            while (rs.next()) {
                for (int i = 1; i <= meta.getColumnCount(); i++) {
                    System.out.print(meta.getColumnLabel(i) + ": " + rs.getString(i) + "\t");
                }
                System.out.println();
            }
        }
    }
}

訂閱

創建

TSDBSubscribe sub = ((TSDBConnection)conn).subscribe("topic", "select * from meters", false);

subscribe 方法的(de)三個參數含義如下(xia):

  • topic:訂閱的主題(即名稱),此參數是訂閱的唯一標識
  • sql:訂閱的查詢語句,此語句只能是 select 語句,只應查詢原始數據,只能按時間正序查詢數據
  • restart:如果訂閱已經存在,是重新開始,還是繼續之前的訂閱

如上面的例子將使用 SQL 語句 select * from meters 創建一個名為 topic 的(de)訂閱,如果這(zhe)個訂閱已經存在(zai),將繼(ji)續之前的(de)查詢進度,而不是從頭(tou)開始消(xiao)費所(suo)有(you)的(de)數據。

消費數據

int total = 0;
while(true) {
    TSDBResultSet rs = sub.consume();
    int count = 0;
    while(rs.next()) {
        count++;
    }
    total += count;
    System.out.printf("%d rows consumed, total %d\n", count, total);
    Thread.sleep(1000);
}

consume 方法返回一個結果集,其中包含從上次 consume 到目前為止的所有新數據。請務必按需選擇合理的調用 consume 的頻率(如例子中的 Thread.sleep(1000)),否則(ze)會(hui)給服務端造成(cheng)不必要的壓力。

關閉訂閱

sub.close(true);

close 方法關閉一個訂閱。如果其參數為 true 表示保留訂閱進度信息,后續可以創建同名訂閱繼續消費數據;如為 false 則不保留訂閱進度(du)。

關閉資源

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

注意務必要將 connection 進行關閉,否則會(hui)出(chu)現連(lian)接泄露。

與連接池使用

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 conneciton pool
}

通(tong)過 HikariDataSource.getConnection() 獲取連接后(hou),使用(yong)完成后(hou)需要調(diao)用(yong) close() 方法,實際上它并不會(hui)關閉連接,只是(shi)放回連接池(chi)中。 更(geng)多(duo) HikariCP 使用(yong)問題請查看。

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 conneciton pool
}

更多(duo) druid 使用問題請(qing)查看。

注意事項:

  • TDengine v1.6.4.1 版本開始提供了一個專門用于心跳檢測的函數 select server_status(),所以在使用連接池時推薦使用 select server_status() 進行 Validation Query。

如下所示,select server_status() 執行成功會返回 1

taos> select server_status();
server_status()|
================
1              |
Query OK, 1 row(s) in set (0.000141s)

在框架中使用

  • Spring JdbcTemplate 中使用 taos-jdbcdriver,可參考
  • Springboot + Mybatis 中使用,可參考

示例程序

示(shi)例(li)程序(xu)源碼位于TDengine/test/examples/JDBC下(xia):

  • JDBCDemo:JDBC示例源程序
  • JDBCConnectorChecker:JDBC安裝校驗源程序及jar包
  • Springbootdemo:springboot示例源程序
  • SpringJdbcTemplate:SpringJDBC模板

請參考:

常見問題

  • 使用 Statement 的 addBatch() 和 executeBatch() 來執行“批量寫入/更新”,為什么沒有帶來性能上的提升? 原因:TDengine 的 JDBC 實現中,通過 addBatch() 方法提交的sql語句,會按照添加的順序,依次執行,這種方式沒有減少與服務端的交互次數,不會帶來性能上的提升。 解決方法:1. 在(zai)一條(tiao) insert 語句中(zhong)拼接(jie)多(duo)個 values 值;2. 使用多(duo)線程的方(fang)式(shi)并發(fa)插入(ru);3. 使用參數綁定的寫入(ru)方(fang)式(shi)

  • 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 即可。

  • java.lang.UnsatisfiedLinkError: taos.dll Can't load AMD 64 bit on a IA 32-bit platform 原因:目前 TDengine 只支持 64 位 JDK。 解決方法:重(zhong)新(xin)安裝 64 位 JDK。

  • 其它問題請參考