用于通过协议与数据库服务器通信的 Java 客户端库。当前实现仅支持 HTTP interface。
该库提供了自有 API,用于向服务器发送请求,同时还提供了处理不同二进制数据格式 (RowBinary* & Native*) 的工具。
使用访问令牌进行身份验证需要调用 通过 SSL 客户端证书进行身份验证,需要分别调用
将产生以下 应用程序可以设置自定义 HTTP 请求头 ⚠️ 当通过 通过 参数参数参数参数参数参数参数参数V2 插入 TSV 格式数据。
设置
- Maven Central (项目页面) :https://mvnrepository.com/artifact/com.clickhouse/client-v2
- 夜间构建 (仓库链接) :https://central.sonatype.com/repository/maven-snapshots/
- 旧版 Nightly 构建制品库 (仓库链接) :https://s01.oss.sonatype.org/content/repositories/snapshots/
- Maven
- Gradle (Kotlin)
- Gradle
初始化
Client 对象通过com.clickhouse.client.api.Client.Builder#build() 初始化。每个客户端拥有独立的上下文,客户端之间不共享任何对象。
Builder 提供了多种配置方法,方便快速完成设置。示例:showLineNumbers
Client 实现了 AutoCloseable 接口,不再需要时应将其关闭。身份验证
身份验证在初始化阶段按客户端进行配置。支持三种身份验证方法:密码、访问令牌以及 SSL 客户端证书。通过密码进行身份验证需要调用setUsername(String) 和 setPassword(String) 来设置用户名和密码:showLineNumbers
setAccessToken(String) 来设置访问令牌:showLineNumbers
setUsername(String)、useSSLAuthentication(boolean)、setClientCertificate(String) 和 setClientKey(String) 来设置用户名、启用 SSL 身份验证、设置客户端证书和客户端密钥:showLineNumbers
在生产环境中,SSL 身份验证往往很难排查,因为 SSL 库返回的很多错误信息都不够充分。例如,如果客户端证书与密钥不匹配,server 会立即终止 connection (对于 HTTP,这会发生在 connection 建立阶段,此时还不会发送任何 HTTP request,因此也不会返回任何响应) 。请使用 openssl 等工具验证证书和密钥:
- 检查密钥完整性:
openssl rsa -in [key-file.key] -check -noout - 检查客户端证书是否包含与用户匹配的 CN:
- 从用户证书中获取 CN:
openssl x509 -noout -subject -in [user.cert] - 验证 database 中是否设置了相同的值:
select name, auth_type, auth_params from system.users where auth_type = 'ssl_certificate'(该查询会输出auth_params,类似{"common_names":["some_user"]})
- 从用户证书中获取 CN:
配置
所有设置均通过实例方法 (即配置方法) 定义,使每个值的作用域和上下文一目了然。 主要配置参数在单一作用域 (客户端或操作) 内定义,彼此之间不会相互覆盖。配置在客户端创建时定义。请参阅com.clickhouse.client.api.Client.Builder。客户端配置
- 连接与端点
- 身份验证
- 超时与重试
- 套接字选项
- 压缩
- SSL/安全
- 代理
- HTTP 和请求头
- 服务器设置
- 时区
- 高级
客户端识别
查询日志中有两个字段用于标识发起请求的应用程序:client_name 和 http_user_agent。Native TCP 协议使用 client_name 标识应用程序,HTTP 协议使用 http_user_agent 标识应用程序。Client builder 提供了 setClientName 方法,可为两种协议正确设置相应的值。
字段 http_user_agent 遵循 User-Agent 请求头的通用格式:application-name[/version] [(operating-system; architecture; ...)]。
这组值会在每个 layer 中重复出现:应用程序层、客户端库层、HTTP 客户端库层。由 setClientName 方法设置的内容在列表中排在最前面。例如:showLineNumbers
http_user_agent 值:User-Agent 来标识自身,但 clickhouse-java-v2/0.9.6-SNAPSHOT 部分会自动追加到该请求头的末尾。操作标识
查询日志还有另外两个字段query_id 和 log_comment,可用于标识操作并向查询日志添加额外信息。query_id 是操作的唯一标识符。应用程序可通过调用 QuerySettings 类的 setQueryId 方法来设置该值。showLineNumbers
log_comment 是一个可以添加到查询日志中的注释。应用程序可以通过调用 QuerySettings 类的 logComment 方法来设置此注释。showLineNumbers
服务器设置
服务器端配置可以在创建客户端时统一设置 (参见Builder 的 serverSetting 方法) ,也可以在操作级别单独设置 (参见操作配置类的 serverSetting) 。showLineNumbers
setOption 方法 (Client.Builder 或操作设置类) 设置选项时,server settings 名称应加上 clickhouse_setting_ 前缀。此时 com.clickhouse.client.api.ClientConfigProperties#serverSetting() 会很有帮助。自定义 HTTP 请求头
可以为所有操作 (客户端级别) 或单个操作 (操作级别) 设置自定义 HTTP 请求头。showLineNumbers
setOption 方法 (Client.Builder 或操作设置类) 设置选项时,自定义请求头名称应以 http_header_ 为前缀。在这种情况下,com.clickhouse.client.api.ClientConfigProperties#httpHeader() 方法会很有帮助。常用定义
ClickHouseFormat
支持格式的枚举类型,包含 ClickHouse 支持的所有格式。raw- 用户应对原始数据进行转码full- 客户端可以自行转码数据,并接收原始数据流-- ClickHouse 不支持此格式的该操作
插入 API
insert(String tableName, InputStream data, ClickHouseFormat format)
以指定格式接受字节InputStream 形式的数据。data 须以 format 指定的格式进行编码。签名tableName - 目标表名称。data - 已编码数据的输入 stream。format - 数据编码所使用的格式。settings - 请求设置。返回值InsertResponse 类型的 Future——操作结果及附加信息,例如服务器端指标。示例showLineNumbers
insert(String tableName, List<?> data, InsertSettings settings)
向数据库发送写请求。对象列表将被转换为高效格式后发送至服务器。列表项的类需要预先通过register(Class, TableSchema) 方法注册。签名tableName - 目标表的名称。data - 集合 DTO (数据传输对象) 对象。settings - 请求设置。返回值InsertResponse 类型的 Future——包含操作结果及服务端指标等附加信息。示例showLineNumbers
InsertSettings
插入操作的配置选项。配置方法InsertResponse
保存插入操作结果的响应对象。仅在客户端收到服务器响应时可用。应尽快关闭此对象以释放连接,因为在完全读取前一个响应的所有数据之前,该连接无法重新使用。
查询 API
query(String sqlQuery)
按原样发送sqlQuery。响应格式由查询设置决定。QueryResponse 将持有对响应 stream 的引用,该 stream 应由支持相应格式的读取器消费。签名sqlQuery - 单条 SQL 语句。查询将按原样发送至服务器。settings - 请求设置。返回值QueryResponse 类型的 Future——包含结果数据集及服务端指标等附加信息。消费完数据集后,应关闭 Response 对象。示例query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)
按原样发送sqlQuery,同时发送查询参数,以便服务器编译 SQL 表达式。签名sqlQuery - 带占位符 {} 的 SQL 表达式。queryParams - 用于在服务器端补全 SQL 表达式的变量映射。settings - 请求设置。返回值QueryResponse 类型的 Future——包含结果数据集及服务端指标等附加信息。消费完数据集后,应关闭 Response 对象。示例showLineNumbers
queryAll(String sqlQuery)
以RowBinaryWithNamesAndTypes 格式查询数据,并以集合形式返回结果。读取性能与使用 reader 时相同,但需要占用更多内存来存储完整的数据集。签名sqlQuery - 用于从服务器查询数据的 SQL 表达式。返回值完整数据集,由一组 GenericRecord 对象列表表示,以行方式访问结果数据。示例showLineNumbers
QuerySettings
查询操作的配置选项。配置方法QueryResponse
保存查询执行结果的响应对象。仅当客户端收到来自服务器的响应时,该对象才可用。应尽快关闭此对象以释放连接,因为在完全读取前一个响应的所有数据之前,该连接无法重新使用。
示例
通用 API
getTableSchema(String table)
拉取table 的表 schema。签名table - 需要拉取 schema 数据的表名。database - 目标表所在的数据库。返回值返回一个包含表列列表的 TableSchema 对象。getTableSchemaFromQuery(String sql)
从 SQL 语句中拉取 schema。签名sql - 需要返回其 schema 的 “SELECT” SQL 语句。返回值返回一个 TableSchema 对象,其列与 sql 表达式相匹配。TableSchema
register(Class<?> clazz, TableSchema schema)
为 Java 类编译序列化与反序列化 layer,以便通过schema 进行数据读写。该 method 将为 getter/setter 对及其对应列创建序列化器和反序列化器。
列的匹配通过从方法名中提取列名来实现。例如,getFirstName 对应的列为 first_name 或 firstname。签名clazz - 表示用于读取/写入数据的 POJO 的类。schema - 用于与 POJO 属性进行匹配的数据 schema。示例showLineNumbers
使用示例
完整的示例代码存放在代码仓库的 ‘example` 文件夹中:- client-v2 - 主要示例。
- demo-service - 展示如何在 Spring Boot 应用程序中使用该客户端的示例。
- demo-kotlin-service - 在 Ktor (Kotlin) 应用中使用客户端的示例。
读取数据
读取数据有两种常见方式:- 返回底层
QueryResponse对象的query()方法,该对象包含带有数据的InputStream。通常会结合ClickHouseBinaryFormatReader用于流式读取,但 也可搭配任何其他自定义 reader 实现使用。QueryResponse还提供对结果集元数据和指标的访问。 queryAll()方法,并使用GenericRecord以便更方便地访问行。在这种情况下,整个结果集都会加载到内存中。- 返回
com.clickhouse.client.api.query.Records的queryRecords()方法——它是一个用于遍历GenericRecord对象的迭代器。该方法采用流式方式 (不会将任何数据加载到内存中) ,并通过GenericRecord访问数据。
读取数组
ClickHouseBinaryFormatReader 方法getList(...)- 将任意Array(...)读取为List<T>。这是灵活类型读取的默认推荐选择。支持嵌套数组。getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)- 最适合用于包含与基本类型兼容值的一维数组。getStringArray(...)- 用于Array(String)(以及以名称形式表示的枚举值) 。getObjectArray(...)- 适用于任意Array(...)元素类型的通用选项,包括嵌套数组。可用于读取包含 Nullable 值和嵌套数组的数组。
GenericRecord 方法getList(...)- 将任意Array(...)读取为List<T>。这是灵活类型读取的默认推荐选择。支持嵌套数组。getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)- 最适合用于包含与基本类型兼容值的一维数组。getStringArray(...)- 用于Array(String)(以及以名称形式表示的枚举值) 。getObjectArray(...)- 适用于任意Array(...)元素类型的通用选项,包括嵌套数组。可用于读取包含 Nullable 值和嵌套数组的数组。
迁移指南
旧版客户端 (V1) 以com.clickhouse.client.ClickHouseClient#builder 作为起点。新版客户端 (V2) 采用类似的模式,使用 com.clickhouse.client.api.Client.Builder。主要区别如下:- 未使用服务加载器来获取具体实现。
com.clickhouse.client.api.Client是一个门面类,未来可适配各种实现。 - 配置来源更少:一类提供给构建器,另一类在操作设置 (
QuerySettings、InsertSettings) 中。先前版本会为每个节点分别配置,并且在某些情况下会加载 环境变量。
配置参数匹配
V1 中有 3 个与配置相关的枚举类:com.clickhouse.client.config.ClickHouseDefaults- 在大多数情况下都需要设置的配置参数,例如USER和PASSWORD。com.clickhouse.client.config.ClickHouseClientOption- 客户端特有的配置参数,例如HEALTH_CHECK_INTERVAL。com.clickhouse.client.http.config.ClickHouseHttpOption- HTTP 接口专用的配置参数,例如RECEIVE_QUERY_PROGRESS。
com.clickhouse.client.config.ClickHouseDefaults#ASYNC 与
com.clickhouse.client.config.ClickHouseClientOption#ASYNC 之间究竟有何区别?) 。新的 V2 客户端以 com.clickhouse.client.api.Client.Builder 作为所有可用客户端配置选项的统一字典。所有配置参数名称均列于
com.clickhouse.client.api.ClientConfigProperties 中。下表列出了新客户端中支持的旧选项及其新含义。图例: ✔ = 支持,✗ = 已丢弃- 连接与认证
- SSL 与安全
- 套接字选项
- 压缩
- 代理
- 超时与重试
- 时区
- 缓冲区与性能
- 线程与异步
- HTTP 和请求头
- 格式与查询
- 节点发现与负载均衡
- 杂项
主要差异
- Client V2 使用更少的专有类,以提高可移植性。例如,V2 可配合
java.io.InputStream的任何实现来 将数据写入服务器。 - Client V2 的
async设置默认值为off。这意味着不会额外创建线程,且应用程序对客户端有更强的控制能力。对于绝大多数用例,此设置都应保持为off。启用async会为每个请求创建一个单独的线程。只有在使用由应用程序控制的 executor 时,这样做才有意义 (请参见com.clickhouse.client.api.Client.Builder#setSharedOperationExecutor)
写入数据
- 可使用
java.io.InputStream的任何实现。支持 V1com.clickhouse.data.ClickHouseInputStream,但不建议使用。 - 一旦检测到输入流结束,就会进行相应处理。在此之前,应关闭请求的输出流。
- 只需调用一个方法。无需另外创建请求对象。
- 请求体流会在所有数据复制完毕后自动关闭。
- 现已提供新的底层 API:
com.clickhouse.client.api.Client#insert(java.lang.String, java.util.List<java.lang.String>, com.clickhouse.client.api.DataStreamWriter, com.clickhouse.data.ClickHouseFormat, com.clickhouse.client.api.insert.InsertSettings)。com.clickhouse.client.api.DataStreamWriter用于实现自定义的数据写入逻辑。例如,从 队列中读取数据。
读取数据
- 默认使用
RowBinaryWithNamesAndTypes格式读取数据。当前在需要进行数据绑定时,仅支持此格式。 - 可以使用
List<GenericRecord> com.clickhouse.client.api.Client#queryAll(java.lang.String)方法,将数据作为记录集合读取。它会将数据读入内存并释放连接,无需额外处理。GenericRecord提供对数据的访问,并支持一些类型转换。