跳到主要内容
跳到主要内容

JDBC 驱动

注意

clickhouse-jdbc 使用最新的 Java 客户端实现了标准 JDBC 接口。 如果对性能或直接访问有苛刻要求,建议直接使用最新的 Java 客户端。

0.7.x 的变更

在 0.8 中,我们尝试让驱动程序更加严格地遵循 JDBC 规范,因此有一些被移除的特性可能会对你产生影响:

旧特性说明
事务支持驱动程序的早期版本只是模拟了事务支持,这可能会产生意外结果。
响应列重命名ResultSet 之前是可变的——出于效率考虑,现在它是只读的。
多语句 SQL多语句支持之前只是模拟的,现在严格遵循 1:1。
命名参数不属于 JDBC 规范的一部分。
基于流的 PreparedStatement驱动程序的早期版本允许以非 JDBC 的方式使用 PreparedStatement——如果你需要此类选项,我们建议使用 Java Client 及其 examples
注意

Date 在存储时不带时区,而 DateTime 在存储时带有时区。如果不加以注意,这可能会导致意外结果。

环境要求

环境配置

<!-- https://mvnrepository.com/artifact/com.clickhouse/clickhouse-jdbc -->
<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>clickhouse-jdbc</artifactId>
    <version>0.9.1</version>
    <classifier>shaded-all</classifier>
</dependency>

配置

驱动类com.clickhouse.jdbc.ClickHouseDriver

URL 语法jdbc:(ch|clickhouse)[:<protocol>]://endpoint1[,endpoint2,...][/<database>][?param1=value1&param2=value2][#tag1,tag2,...],例如:

  • jdbc:clickhouse:http://localhost:8123
  • jdbc:clickhouse:https://localhost:8443?ssl=true

连接属性

除了标准 JDBC 属性之外,驱动还支持底层 Java 客户端 提供的 ClickHouse 专用属性。 在可能的情况下,如果某个特性不受支持,相应方法将返回 SQLFeatureNotSupportedException。其他自定义属性包括:

PropertyDefaultDescription
disable_frameworks_detectiontrue禁用用于构造 User-Agent 的框架检测
jdbc_ignore_unsupported_valuesfalse屏蔽 SQLFeatureNotSupportedException 的抛出
clickhouse.jdbc.v1false使用旧版 JDBC 实现,而不是新版 JDBC
default_query_settingsnull允许在查询操作中传递默认查询设置
jdbc_resultset_auto_closetrueStatement 关闭时自动关闭 ResultSet
beta.row_binary_for_simple_insertfalse使用基于 RowBinary writer 的 PreparedStatement 实现。仅适用于 INSERT INTO ... VALUES 查询。

支持的数据类型

JDBC 驱动程序支持与其底层 Java 客户端 相同的数据格式。

处理日期、时间和时区

java.sql.Datejava.sql.Timejava.sql.Timestamp 可能会使时区计算变得更加复杂——虽然这些类型当然也受到支持,但你可能需要考虑使用 java.time 包。ZonedDateTimeOffsetDateTime 都是替代 java.sql.Timestampjava.sql.Datejava.sql.Time 的不错选择。

建立连接

String url = "jdbc:ch://my-server:8123/system";

Properties properties = new Properties();
DataSource dataSource = new DataSource(url, properties);//DataSource 或 DriverManager 是主要的入口点
try (Connection conn = dataSource.getConnection()) {
... // 对连接执行操作

提供凭证和配置

String url = "jdbc:ch://localhost:8123?jdbc_ignore_unsupported_values=true&socket_timeout=10";

Properties info = new Properties();
info.put("user", "default");
info.put("password", "password");
info.put("database", "some_db");

//使用 DataSource 创建连接
DataSource dataSource = new DataSource(url, info);
try (Connection conn = dataSource.getConnection()) {
... // 对连接进行操作
}

//使用 DriverManager 的替代方式
try (Connection conn = DriverManager.getConnection(url, info)) {
... // 对连接进行操作
}

简单语句


try (Connection conn = dataSource.getConnection(...);
    Statement stmt = conn.createStatement()) {
    ResultSet rs = stmt.executeQuery("select * from numbers(50000)");
    while(rs.next()) {
        // ...
    }
}

INSERT

try (PreparedStatement ps = conn.prepareStatement("INSERT INTO mytable VALUES (?, ?)")) {
    ps.setString(1, "test"); // id
    ps.setObject(2, LocalDateTime.now()); // 时间戳
    ps.addBatch();
    ...
    ps.executeBatch(); // 将当前批次数据流式写入 ClickHouse
}

HikariCP

// 连接池对性能提升帮助不大,
// 因为底层实现已有自己的连接池。
// 例如:HttpURLConnection 为套接字维护了连接池
HikariConfig poolConfig = new HikariConfig();
poolConfig.setConnectionTimeout(5000L);
poolConfig.setMaximumPoolSize(20);
poolConfig.setMaxLifetime(300_000L);
poolConfig.setDataSource(new ClickHouseDataSource(url, properties));

try (HikariDataSource ds = new HikariDataSource(poolConfig);
     Connection conn = ds.getConnection();
     Statement s = conn.createStatement();
     ResultSet rs = s.executeQuery("SELECT * FROM system.numbers LIMIT 3")) {
    while (rs.next()) {
        // 处理行数据
        log.info("Integer: {}, String: {}", rs.getInt(1), rs.getString(1));//同一列,不同类型
    }
}

更多信息

如需了解更多信息,请参阅我们的 GitHub 仓库Java Client 文档

故障排除

日志记录

该驱动使用 slf4j 进行日志记录,并会在 classpath 中使用首个可用的实现。

解决大批量插入时的 JDBC 超时问题

在 ClickHouse 中执行耗时较长的大批量插入操作时,您可能会遇到如下所示的 JDBC 超时错误:

原因:java.sql.SQLException:读取超时,服务器 myHostname [uri=https://hostname.aws.clickhouse.cloud:8443]

这些错误可能会导致数据插入过程中断,并影响系统稳定性。为了解决该问题,您可能需要在客户端操作系统中调整一些超时设置。

Mac OS

在 Mac OS 上,可以调整以下设置来解决此问题:

  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1

Linux

在 Linux 上,仅设置对应的参数可能无法解决该问题。由于 Linux 处理套接字 keep-alive 设置的方式不同,还需要执行额外步骤。请按以下步骤操作:

  1. /etc/sysctl.conf 或相关配置文件中调整以下 Linux 内核参数:
  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1
  • net.ipv4.tcp_keepalive_intvl: 75
  • net.ipv4.tcp_keepalive_probes: 9
  • net.ipv4.tcp_keepalive_time: 60(可以考虑将该值从默认的 300 秒下调)
  1. 修改内核参数后,运行以下命令以应用更改:
sudo sysctl -p

在完成这些设置后,您需要确保客户端在套接字上启用了 Keep-Alive 选项:

properties.setProperty("socket_keepalive", "true");