JDBC

注意: 目前的JDBC实现仅是为与第三方工具连接使用的。不推荐使用 JDBC (执行插入语句时),因无法提供高性能写入,查询推荐使用 JDBC。

对于Java应用,我们推荐使用Java 原生接口

1. 使用方式

环境要求:

  • JDK >= 1.8

  • Maven >= 3.6

获取依赖包:

联系技术支持获取依赖包udbds-jdbc-${version}-jar-with-dependencies.jar

安装依赖包至本地仓库:

mvn install:install-file \
  -Dfile=/parh/to/jar/udbds-jdbc-${version}-jar-with-dependencies.jar \
  -DgroupId=com.unvdb.udbds \
  -DartifactId=udbds-jdbc \
  -Dversion=${version} \
  -Dpackaging=jar \
  -Dclassifier=jar-with-dependencies \
  -DgeneratePom=true

在maven中添加依赖:

<dependencies>
    <dependency>
        <groupId>com.unvdb.udbds</groupId>
        <artifactId>udbds-jdbc</artifactId>
        <version>${version}</version>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>

2. 示例代码

本章提供了如何建立数据库连接、执行 SQL 和显示查询结果的示例。

要求您已经在工程中包含了数据库编程所需引入的包和 JDBC class.

注意:为了更快地插入,建议使用 executeBatch()

import com.unvdb.udbds.jdbc.UDBDSSQLException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.time.LocalDate;
import java.util.Properties;

public class JDBCExample {
  private static final Logger LOGGER = LoggerFactory.getLogger(JDBCExample.class);

  public static void main(String[] args) throws ClassNotFoundException, SQLException {
    final Properties info = new Properties();
    info.put("user", "root");
    info.put("password", "root");

    /*
     * TLCP协议配置说明:
     * 1. 启用协议前需配置JVM模块开放参数(适用于JDK9+):
     *    --add-opens=java.base/javax.crypto=ALL-UNNAMED
     *    --add-opens=java.base/sun.security.util=ALL-UNNAMED
     *    --add-opens=java.base/sun.security.x509=ALL-UNNAMED
     *    --add-opens=java.base/sun.security.pkcs12=ALL-UNNAMED
     *    --add-exports=java.base/jdk.internal.access=ALL-UNNAMED
     *    --add-exports=java.base/sun.net.util=ALL-UNNAMED
     *    --add-exports=java.base/sun.security.pkcs=ALL-UNNAMED
     *    --add-exports=java.base/sun.security.action=ALL-UNNAMED
     *    --add-exports=java.base/sun.security.provider=ALL-UNNAMED
     *    --add-exports=java.base/sun.security.provider.certpath=ALL-UNNAMED
     */
    // info.put("use_tlcp", "true");

    /*
     * 证书信任库配置(单向认证)
     * - 文件路径需使用类路径格式(如/cacert.truststore)
     * - 证书文件需放置在src/main/resources目录下
     */
    // info.put("tlcp_trust_store", "cacert.truststore");
    // info.put("tlcp_trust_store_pwd", "unvdb@123"); // CA证书密码

    /*
     * 客户端密钥库配置(双向认证)
     * - 文件路径需使用类路径格式(如/client.keystore)
     * - 密钥库需包含客户端证书链及私钥
     */
    // info.put("tlcp_key_store", "client.keystore");
    // info.put("tlcp_key_store_pwd", "unvdb@123"); // 客户端证书密码

    Class.forName("com.unvdb.udbds.jdbc.UDBDSDriver");
    try (Connection connection =
            DriverManager.getConnection("jdbc:udbds://127.0.0.1:7777", info);
        Statement statement = connection.createStatement()) {

      // set JDBC fetchSize
      statement.setFetchSize(10000);

      statement.execute("CREATE DATABASE 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");
      statement.execute(
          "CREATE TIMESERIES root.sg1.d1.s4 WITH DATATYPE=DATE, ENCODING=PLAIN, COMPRESSOR=SNAPPY");
      statement.execute(
          "CREATE TIMESERIES root.sg1.d1.s5 WITH DATATYPE=TIMESTAMP, ENCODING=PLAIN, COMPRESSOR=SNAPPY");
      statement.execute(
          "CREATE TIMESERIES root.sg1.d1.s6 WITH DATATYPE=BLOB, ENCODING=PLAIN, COMPRESSOR=SNAPPY");
      statement.execute(
          "CREATE TIMESERIES root.sg1.d1.s7 WITH DATATYPE=STRING, ENCODING=PLAIN, COMPRESSOR=SNAPPY");

      for (int i = 0; i <= 100; i++) {
        statement.addBatch(prepareInsertStatement(i));
      }
      statement.executeBatch();
      statement.clearBatch();

      ResultSet resultSet = statement.executeQuery("select ** from root where time <= 10");
      outputResult(resultSet);
      resultSet = statement.executeQuery("select count(**) from root");
      outputResult(resultSet);
      resultSet =
          statement.executeQuery(
              "select count(**) from root where time >= 1 and time <= 100 group by ([0, 100), 20ms, 20ms)");
      outputResult(resultSet);
    } catch (UDBDSSQLException e) {
      LOGGER.error("UDB-DS Jdbc example error", e);
    }
  }

  @SuppressWarnings({"squid:S106"})
  private static void outputResult(ResultSet resultSet) throws SQLException {
    if (resultSet != null) {
      System.out.println("--------------------------");
      final ResultSetMetaData metaData = resultSet.getMetaData();
      final int columnCount = metaData.getColumnCount();
      for (int i = 0; i < columnCount; i++) {
        System.out.print(metaData.getColumnLabel(i + 1) + " ");
      }
      System.out.println();
      while (resultSet.next()) {
        for (int i = 1; ; i++) {
          System.out.print(resultSet.getString(i));
          if (i < columnCount) {
            System.out.print(", ");
          } else {
            System.out.println();
            break;
          }
        }
      }
      System.out.println("--------------------------\n");
    }
  }

  private static String prepareInsertStatement(int time) {
    return String.format(
        "insert into root.sg1.d1(timestamp, s1, s2, s3, s4, s5, s6, s7) values(%d, %d, %d, %d, \"%s\", %d, %s, \"%s\")",
        time, 1, 1, 1, LocalDate.of(2024, 5, time % 31 + 1), time, "X'cafebabe'", time);
  }
}

UDB-DS 在 JDBC 中提供了额外的接口,供用户在连接中使用不同的字符集(例如 GB18030)读写数据库。 UDB-DS 默认的字符集为 UTF-8。当用户期望使用 UTF-8 外的字符集时,需要在 JDBC 的连接中,指定 charset 属性。例如:

  1. 使用 GB18030 的 charset 创建连接:

DriverManager.getConnection("jdbc:udbds://127.0.0.1:7777?charset=GB18030", "root", "root")
  1. 调用如下 UDBDSStatement 接口执行 SQL 时,可以接受 byte[] 编码的 SQL,该 SQL 将按照被指定的 charset 解析成字符串。

public boolean execute(byte[] sql) throws SQLException;
  1. 查询结果输出时,可使用 ResultSetgetBytes 方法得到的 byte[]byte[] 的编码使用连接指定的 charset 进行。

System.out.print(resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")");

以下是完整示例:

import com.unvdb.udbds.jdbc.UDBDSSQLException;
import com.unvdb.udbds.jdbc.UDBDSStatement;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class JDBCCharsetExample {

  private static final Logger LOGGER = LoggerFactory.getLogger(JDBCCharsetExample.class);

  public static void main(String[] args) throws Exception {
    Class.forName("com.unvdb.udbds.jdbc.UDBDSDriver");

    try (final Connection connection =
            DriverManager.getConnection(
                "jdbc:udbds://127.0.0.1:7777?charset=GB18030", "root", "root");
        final UDBDSStatement statement = (UDBDSStatement) connection.createStatement()) {

      final String insertSQLWithGB18030 =
          "insert into root.测试(timestamp, 彝语, 繁体, 蒙文, 简体, 标点符号, 藏语) values(1, 'ꆈꌠꉙ', \"繁體\", 'ᠮᠣᠩᠭᠣᠯ ᠬᠡᠯᠡ', '简体', '——?!', \"བོད་སྐད།\");";
      final byte[] insertSQLWithGB18030Bytes = insertSQLWithGB18030.getBytes("GB18030");
      statement.execute(insertSQLWithGB18030Bytes);
    } catch (UDBDSSQLException e) {
      LOGGER.error("UDB-DS Jdbc example error", e);
    }

    outputResult("GB18030");
    outputResult("UTF-8");
    outputResult("UTF-16");
    outputResult("GBK");
    outputResult("ISO-8859-1");
  }

  private static void outputResult(String charset) throws SQLException {
    System.out.println("[Charset: " + charset + "]");
    try (final Connection connection =
            DriverManager.getConnection(
                "jdbc:udbds://127.0.0.1:7777?charset=" + charset, "root", "root");
        final UDBDSStatement statement = (UDBDSStatement) connection.createStatement()) {
      outputResult(statement.executeQuery("select ** from root"), Charset.forName(charset));
    } catch (UDBDSSQLException e) {
      LOGGER.error("UDB-DS Jdbc example error", e);
    }
  }

  private static void outputResult(ResultSet resultSet, Charset charset) throws SQLException {
    if (resultSet != null) {
      System.out.println("--------------------------");
      final ResultSetMetaData metaData = resultSet.getMetaData();
      final int columnCount = metaData.getColumnCount();
      for (int i = 0; i < columnCount; i++) {
        System.out.print(metaData.getColumnLabel(i + 1) + " ");
      }
      System.out.println();

      while (resultSet.next()) {
        for (int i = 1; ; i++) {
          System.out.print(
              resultSet.getString(i) + " (" + new String(resultSet.getBytes(i), charset) + ")");
          if (i < columnCount) {
            System.out.print(", ");
          } else {
            System.out.println();
            break;
          }
        }
      }
      System.out.println("--------------------------\n");
    }
  }
}