Клиентская библиотека Java для взаимодействия с сервером базы данных через его протоколы. Текущая реализация поддерживает только HTTP-интерфейс.
Библиотека предоставляет собственный API для отправки запросов на сервер, а также инструменты для работы с различными бинарными форматами данных (RowBinary* & Native*).
Для аутентификации с помощью токена доступа необходимо задать токен доступа, вызвав Аутентификация с помощью SSL-сертификата клиента требует указания имени пользователя, включения SSL-аутентификации, а также задания клиентского сертификата и клиентского ключа посредством вызовов
приведёт к следующему значению Приложение может задать собственный HTTP-заголовок ⚠️ Если параметры задаются через метод Если параметры задаются через метод ПараметрыПараметрыПараметрыПараметрыПараметрыПараметрыПараметрыПараметрыМетоды V2 Вставка данных в формате TSV.
Setup
- Maven Central (веб-страница проекта): https://mvnrepository.com/artifact/com.clickhouse/client-v2
- Ночные сборки (ссылка на репозиторий): https://central.sonatype.com/repository/maven-snapshots/
- Artifactory со старыми ночными сборками (ссылка на репозиторий): 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) соответственно:showLineNumbers
Аутентификацию по SSL бывает сложно диагностировать в продакшне, потому что многие ошибки из библиотек SSL дают недостаточно информации. Например, если сертификат клиента и ключ не совпадают, сервер немедленно разорвет соединение (в случае HTTP это произойдет на этапе установления соединения, когда HTTP-запросы еще не отправляются, поэтому ответ не будет отправлен).Пожалуйста, используйте такие инструменты, как openssl, чтобы проверить сертификаты и ключи:
- проверить целостность ключа:
openssl rsa -in [key-file.key] -check -noout - проверить, что сертификат клиента содержит CN, соответствующий пользователю:
- получить CN из сертификата пользователя —
openssl x509 -noout -subject -in [user.cert] - убедиться, что в базе данных задано то же значение:
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. Нативный TCP-протокол использует
client_name для идентификации приложения. HTTP-протокол использует http_user_agent для идентификации приложения. В билдере клиента есть метод setClientName, который задаёт корректные значения
для обоих протоколов.
Поле http_user_agent задаётся в соответствии с общепринятым форматом заголовка User-Agent: application-name[/version] [(operating-system; architecture; ...)].
Этот набор значений повторяется для каждого уровня: приложение, клиентская библиотека, HTTP-клиентская библиотека. Значение, заданное методом setClientName, идёт первым в списке.Например:showLineNumbers
http_user_agent:User-Agent для самоидентификации. При этом строка clickhouse-java-v2/0.9.6-SNAPSHOT будет добавлена в конец заголовка.Идентификация операции
Log запросов содержит ещё два поля —query_id и log_comment, — которые можно использовать для идентификации операции и добавления дополнительных сведений в log запросов.query_id — уникальный идентификатор операции. Его можно задать в приложении, вызвав метод setQueryId класса QuerySettings.showLineNumbers
log_comment — это комментарий, который можно добавить в лог запросов. Его можно задать в приложении, вызвав метод logComment класса QuerySettings.showLineNumbers
Настройки сервера
Настройки на стороне сервера можно задать на уровне клиента один раз при создании (см. методserverSetting класса Builder) и на уровне операции (см. serverSetting для класса настроек операции).showLineNumbers
setOption (будь то Client.Builder или класс настроек операции), имя настройки сервера должно иметь префикс 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 — входной поток закодированных данных.format — формат, в котором закодированы данные.settings - параметры запроса.Возвращаемое значениеFuture типа InsertResponse — результат операции и дополнительная информация, например метрики на стороне сервера.ПримерыshowLineNumbers
insert(String tableName, List<?> data, InsertSettings settings)
Отправляет запрос на запись в базу данных. Список объектов преобразуется в эффективный формат и затем отправляется на сервер. Класс элементов списка должен быть заранее зарегистрирован с помощью методаregister(Class, TableSchema).СигнатурыtableName — имя целевой таблицы.data — объекты DTO (Data Transfer Object) коллекции.settings - параметры запроса.Возвращаемое значениеFuture типа InsertResponse — результат операции и дополнительная информация, например метрики на стороне сервера.ПримерыshowLineNumbers
InsertSettings
Параметры для операций вставки.Методы конфигурацииInsertResponse
Объект ответа, содержащий результат операции вставки. Доступен только в том случае, если клиент получил ответ от сервера.Этот объект следует закрыть как можно скорее, чтобы освободить соединение, поскольку его нельзя использовать повторно, пока не будут полностью прочитаны все данные из предыдущего ответа.
API запросов
query(String sqlQuery)
ОтправляетsqlQuery без изменений. Формат ответа задаётся настройками запроса. QueryResponse будет содержать ссылку на поток ответа, который должен быть обработан ридером для соответствующего формата.СигнатурыsqlQuery — один SQL-оператор. Запрос отправляется на сервер без изменений.settings - параметры запроса.Возвращаемое значениеFuture типа QueryResponse — результирующий набор данных и дополнительная информация, например метрики на стороне сервера. Объект Response следует закрыть после обработки набора данных.Примерыquery(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)
ОтправляетsqlQuery без изменений. Также передаёт параметры запроса, чтобы сервер мог скомпилировать SQL-выражение.СигнатурыsqlQuery — SQL-выражение с плейсхолдерами {}.queryParams — набор переменных для подстановки в SQL-выражение на сервере.settings - параметры запроса.Возвращаемое значениеFuture типа QueryResponse — результирующий набор данных и дополнительная информация, например метрики на стороне сервера. Объект Response следует закрыть после обработки набора данных.ПримерыshowLineNumbers
queryAll(String sqlQuery)
Запрашивает данные в форматеRowBinaryWithNamesAndTypes. Возвращает результат в виде коллекции. Производительность чтения аналогична reader, однако для хранения всего набора данных требуется больше памяти.СигнатурыsqlQuery — SQL-выражение для запроса данных с сервера.Возвращаемое значениеПолный набор данных, представленный в виде списка объектов GenericRecord, обеспечивающих построчный доступ к результирующим данным.ПримерыshowLineNumbers
QuerySettings
Параметры конфигурации для операций с запросами.Методы конфигурацииQueryResponse
Объект ответа, содержащий результат выполнения запроса. Доступен только в том случае, если клиент получил ответ от сервера.Этот объект следует закрыть как можно скорее, чтобы освободить соединение, поскольку его нельзя использовать повторно, пока не будут полностью прочитаны все данные из предыдущего ответа.
Примеры
- Пример кода доступен в репозитории
- Справочник по Spring Service реализации
Общий API
getTableSchema(String table)
Загружает схему таблицы дляtable.Сигнатурыtable - имя таблицы, для которой нужно получить данные схемы.database — база данных, в которой определена целевая таблица.Возвращаемое значениеВозвращает объект TableSchema со списком столбцов таблицы.getTableSchemaFromQuery(String sql)
Извлекает схему из SQL-оператора.Сигнатурыsql - оператор SQL “SELECT”, схему которого необходимо вернуть.Возвращаемое значениеВозвращает объект TableSchema со столбцами, соответствующими выражению sql.TableSchema
register(Class<?> clazz, TableSchema schema)
Компилирует слой сериализации и десериализации для Java-класса, используемого при записи/чтении данных с помощьюschema. Метод создаёт сериализатор и десериализатор для пары геттер/сеттер и соответствующего столбца.
Соответствие столбца определяется путём извлечения его имени из имени метода. Например, getFirstName будет соответствовать столбцу first_name или firstname.Сигнатурыclazz — класс, представляющий POJO, используемый для чтения/записи данных.schema — схема данных для сопоставления со свойствами POJO.ПримерыshowLineNumbers
Примеры использования
Полный код примеров хранится в репозитории в папке ‘example`:- client-v2 — основной набор примеров.
- demo-service — пример использования клиента в приложении Spring Boot.
- demo-kotlin-service — пример использования клиента в приложении на Ktor (Kotlin).
Чтение данных
Есть два распространённых способа чтения данных:- метод
query(), который возвращает низкоуровневый объектQueryResponse, содержащийInputStreamс данными. Обычно используется вместе сClickHouseBinaryFormatReaderдля потокового чтения, но может использоваться и с любой другой пользовательской реализацией ридера.QueryResponseтакже предоставляет доступ к метаданным результирующего набора и метрикам. - Метод
queryAll()и использованиеGenericRecordдля удобного доступа к строкам. В этом случае весь результирующий набор загружается в память. - Метод
queryRecords(), который возвращаетcom.clickhouse.client.api.query.Records, — это итератор по объектамGenericRecord. Этот метод использует потоковый подход (данные не загружаются в память) иGenericRecordдля доступа к данным.
Чтение массивов
МетодыClickHouseBinaryFormatReadergetList(...)— читает любойArray(...)какList<T>. Хороший вариант по умолчанию для чтения с гибкой типизацией. Поддерживает вложенные массивы.getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)— лучше всего подходят для одномерных массивов значений, совместимых с примитивными типами.getStringArray(...)— дляArray(String)(и значенийenum, представленных в виде имён).getObjectArray(...)— универсальный вариант дляArray(...)с любым типом элементов, включая вложенные массивы. Используйте для чтения массивов с Nullable-значениями и вложенных массивов.
GenericRecordgetList(...)— читает любойArray(...)какList<T>. Хороший вариант по умолчанию для чтения с гибкой типизацией. Поддерживает вложенные массивы.getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)— лучше всего подходят для одномерных массивов значений, совместимых с примитивными типами.getStringArray(...)— дляArray(String)(и значенийenum, представленных в виде имён).getObjectArray(...)— универсальный вариант дляArray(...)с любым типом элементов, включая вложенные массивы. Используйте для чтения массивов с Nullable-значениями и вложенных массивов.
Руководство по миграции
Старый клиент (V1) использовалcom.clickhouse.client.ClickHouseClient#builder в качестве точки входа. Новый клиент (V2) использует аналогичный подход с com.clickhouse.client.api.Client.Builder. Основные
отличия:- Для получения реализации service loader не используется.
com.clickhouse.client.api.Client— это класс-фасад для любых реализаций, которые могут появиться в будущем. - меньше источников конфигурации: один передаётся билдеру, а другой — через настройки операции (
QuerySettings,InsertSettings). В предыдущей версии конфигурация задавалась для каждого узла, а в некоторых случаях также загружались переменные окружения.
Соответствие параметров конфигурации
В V1 есть 3 класса enum, связанных с конфигурацией: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 & заголовки
- Формат & запрос
- Обнаружение узлов & балансировка нагрузки
- Прочее
Общие различия
- Клиент V2 использует меньше проприетарных классов, что повышает переносимость. Например, V2 работает с любой реализацией
java.io.InputStreamдля записи данных на сервер. - Настройка
asyncв Client V2 по умолчанию имеет значениеoff. Это означает отсутствие дополнительных потоков и больший контроль приложения над клиентом. Для большинства сценариев использования эта настройка должна оставатьсяoff. При включенииasyncдля запроса создаётся отдельный поток. Это имеет смысл только при использовании исполнителя, управляемого приложением (см.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предоставляет доступ к данным и поддерживает некоторые преобразования.