Перейти к основному содержимому
Перейти к основному содержимому

Java-клиент

Клиентская библиотека Java для взаимодействия с сервером БД по его протоколам. Текущая реализация поддерживает только HTTP-интерфейс. Библиотека предоставляет собственный API для отправки запросов на сервер. Также она содержит инструменты для работы с различными форматами бинарных данных (RowBinary* & Native*).

Настройка


<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>client-v2</artifactId>
    <version>0.9.7</version>
</dependency>

Инициализация

Объект Client инициализируется с помощью com.clickhouse.client.api.Client.Builder#build(). Каждый клиент имеет собственный контекст, объекты между клиентами не разделяются. Builder предоставляет методы конфигурации для удобной настройки.

Пример:

 Client client = new Client.Builder()
                .addEndpoint("https://clickhouse-cloud-instance:8443/")
                .setUsername(user)
                .setPassword(password)
                .build();

Client реализует интерфейс AutoCloseable, и его следует закрывать, когда он больше не нужен.

Аутентификация

Аутентификация настраивается для каждого клиента на этапе инициализации. Поддерживаются три метода аутентификации: по паролю, по токену доступа и по клиентскому SSL‑сертификату.

Для аутентификации по паролю необходимо задать имя пользователя и пароль, вызвав методы setUsername(String) и setPassword(String):

 Client client = new Client.Builder()
        .addEndpoint("https://clickhouse-cloud-instance:8443/")
        .setUsername(user)
        .setPassword(password)
        .build();

Для аутентификации по токену доступа необходимо задать его, вызвав метод setAccessToken(String):

 Client client = new Client.Builder()
        .addEndpoint("https://clickhouse-cloud-instance:8443/")
        .setAccessToken(userAccessToken)
        .build();

Аутентификация по SSL-сертификату клиента требует указания имени пользователя, включения SSL-аутентификации, указания клиентского сертификата и клиентского ключа с помощью вызова методов setUsername(String), useSSLAuthentication(boolean), setClientCertificate(String) и setClientKey(String) соответственно:

Client client = new Client.Builder()
        .useSSLAuthentication(true)
        .setUsername("some_user")
        .setClientCertificate("some_user.crt")
        .setClientKey("some_user.key")
Примечание

Аутентификацию 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"]})

Конфигурация

Все настройки задаются методами экземпляра (так называемыми методами конфигурации), которые однозначно определяют область действия и контекст каждого значения. Ключевые параметры конфигурации задаются на одном уровне (клиент или операция) и не переопределяют друг друга.

Конфигурация задаётся при создании клиента. См. com.clickhouse.client.api.Client.Builder.

Настройка клиента

MethodArgumentsDescriptionDefaultKey
addEndpoint(String endpoint)endpoint - адрес сервера в формате URLДобавляет endpoint сервера в список доступных серверов. В настоящее время поддерживается только один endpoint.nonenone
addEndpoint(Protocol protocol, String host, int port, boolean secure)protocol - протокол подключения
host - IP-адрес или имя хоста
secure - использовать HTTPS
Добавляет endpoint сервера в список доступных серверов. В настоящее время поддерживается только один endpoint.nonenone
enableConnectionPool(boolean enable)enable - флаг включения/отключенияУстанавливает, включен ли пул соединенийtrueconnection_pool_enabled
setMaxConnections(int maxConnections)maxConnections - число соединенийУстанавливает, сколько соединений клиент может открыть к каждому endpoint-у сервера.10max_open_connections
setConnectionTTL(long timeout, ChronoUnit unit)timeout - значение тайм-аута
unit - единица времени
Устанавливает TTL соединения, по истечении которого соединение будет считаться неактивным-1connection_ttl
setKeepAliveTimeout(long timeout, ChronoUnit unit)timeout - значение тайм-аута
unit - единица времени
Устанавливает тайм-аут Keep-Alive для HTTP-соединения. Установите 0, чтобы отключить Keep-Alive.-http_keep_alive_timeout
setConnectionReuseStrategy(ConnectionReuseStrategy strategy)strategy - LIFO или FIFOВыбирает стратегию повторного использования соединений, которую должен применять пул соединенийFIFOconnection_reuse_strategy
setDefaultDatabase(String database)database - имя базы данныхУстанавливает базу данных по умолчанию.defaultdatabase

Идентификация клиента

В журнале запросов есть два поля, идентифицирующих приложение, из которого поступил запрос: client_name и http_user_agent. Нативный TCP-протокол использует client_name для идентификации приложения. HTTP-протокол использует http_user_agent для идентификации приложения. Метод setClientName в Client builder устанавливает корректные значения для обоих протоколов. Поле http_user_agent задаётся в соответствии с общим форматом заголовка User-Agent: application-name[/version] [(operating-system; architecture; ...)]. Этот набор значений повторяется для каждого уровня: приложение, клиентская библиотека, HTTP-клиентская библиотека. Значение, заданное методом setClientName, стоит первым в списке.

Например:

client.setClientName("my-app-01/1.0");

приведёт к следующему значению http_user_agent:

my-app-01/1.0 clickhouse-java-v2/0.9.6-SNAPSHOT (Linux; jvm:17.0.17) Apache-HttpClient/5.4.4

Приложение может задать собственный HTTP-заголовок User-Agent для своей идентификации. Однако часть clickhouse-java-v2/0.9.6-SNAPSHOT будет добавлена в конец заголовка.

Идентификация операции

Журнал запросов содержит ещё два поля query_id и log_comment, которые можно использовать, чтобы идентифицировать операцию и добавить дополнительную информацию в журнал запросов.

query_id — уникальный идентификатор операции. Его можно задать в приложении, вызвав метод setQueryId класса QuerySettings.

QuerySettings querySettings = new QuerySettings();
querySettings.setQueryId("some-query-id");

log_comment — это комментарий, который можно добавить в журнал запросов. Его можно задать в приложении, вызвав метод logComment класса QuerySettings.

QuerySettings querySettings = new QuerySettings();
querySettings.logComment("some-comment");

Настройки сервера

Настройки на стороне сервера можно задать на уровне клиента один раз при его создании (см. метод serverSetting класса Builder) и на уровне операции (см. serverSetting в классе настроек операции).

 try (Client client = new Client.Builder().addEndpoint(Protocol.HTTP, "localhost", mockServer.port(), false)
        .setUsername("default")
        .setPassword(ClickHouseServerForTest.getPassword())
        .compressClientRequest(true)

        // Client level
        .serverSetting("max_threads", "10")
        .serverSetting("async_insert", "1")
        .serverSetting("roles", Arrays.asList("role1", "role2"))

        .build()) {

	// Operation level
	QuerySettings querySettings = new QuerySettings();
	querySettings.serverSetting("session_timezone", "Europe/Zurich");

	...
}

⚠️ При задании параметров методом setOption (как у Client.Builder, так и у класса настроек операции) имя серверной настройки должно начинаться с префикса clickhouse_setting_. В этом случае может пригодиться метод com.clickhouse.client.api.ClientConfigProperties#serverSetting().

Пользовательский HTTP-заголовок

Пользовательские HTTP-заголовки можно задать для всех операций (на уровне клиента) или только для отдельной операции (на уровне операции).


QuerySettings settings = new QuerySettings()
    .httpHeader(HttpHeaders.REFERER, clientReferer)
    .setQueryId(qId);

Когда параметры задаются с помощью метода setOptionClient.Builder или в классе настроек операции), имя пользовательского заголовка должно начинаться с префикса http_header_. В этом случае пригодится метод com.clickhouse.client.api.ClientConfigProperties#httpHeader().

Общие определения

ClickHouseFormat

Перечисление поддерживаемых форматов. Включает все форматы, поддерживаемые ClickHouse.

  • raw - пользователь должен самостоятельно преобразовать сырые данные
  • full — клиент может самостоятельно транскодировать данные и принимать сырой поток данных
  • - — операция не поддерживается в ClickHouse для этого формата

Эта версия клиента поддерживает:

ФорматВходные данныеВыходные данные
TabSeparatedrawraw
TabSeparatedRawrawraw
TabSeparatedWithNamesrawraw
TabSeparatedWithNamesAndTypesrawraw
TabSeparatedRawWithNamesrawraw
TabSeparatedRawWithNamesAndTypesrawraw
Templaterawraw
TemplateIgnoreSpacesraw*
CSVrawraw
CSVWithNamesrawraw
CSVWithNamesAndTypesrawraw
CustomSeparatedrawraw
CustomSeparatedWithNamesrawraw
CustomSeparatedWithNamesAndTypesrawraw
SQLInsert-raw
Valuesrawraw
Vertical*raw
JSONrawraw
JSONAsStringraw-
JSONAsObjectraw*
JSONStringsrawraw
JSONColumnsrawraw
JSONColumnsWithMetadatarawraw
JSONCompactrawraw
JSONCompactStrings-raw
JSONCompactColumnsrawraw
JSONEachRow*raw
PrettyJSONEachRow-как есть
JSONEachRowWithProgress*raw
JSONStringsEachRow-как есть
JSONStringsEachRowWithProgress*raw
JSONCompactEachRow-raw
JSONCompactEachRowWithNamesкак естькак есть
JSONCompactEachRowWithNamesAndTypesrawraw
JSONCompactStringsEachRowrawкак есть
JSONCompactStringsEachRowWithNamesrawraw
JSONCompactStringsEachRowWithNamesAndTypesrawкак есть
JSONObjectEachRowrawкак есть
BSONEachRowкак естькак есть
TSKVrawraw
Pretty*raw
PrettyNoEscapes-raw
PrettyMonoBlock*raw
PrettyNoEscapesMonoBlock-raw
PrettyCompact*raw
PrettyCompactNoEscapes-raw
PrettyCompactMonoBlock*raw
PrettyCompactNoEscapesMonoBlock-raw
PrettySpace*raw
PrettySpaceNoEscapes-raw
PrettySpaceMonoBlock*raw
PrettySpaceNoEscapesMonoBlock-raw
Prometheus*raw
Protobufrawraw
ProtobufSinglerawraw
ProtobufListrawraw
Avrorawraw
AvroConfluentraw-
Parquetrawraw
ParquetMetadataraw*
Arrowrawraw
ArrowStreamrawraw
ORCrawraw
Oneraw-
Npyrawraw
RowBinaryfullfull
RowBinaryWithNamesfullполная
RowBinaryWithNamesAndTypesполнаяполный
RowBinaryWithDefaultsfull*
Nativefullнеобработанный
Null-raw
XML*raw
CapnProtorawraw
LineAsStringкак естьraw
Regexpraw-
RawBLOBrawraw
MsgPackrawкак есть
MySQLDumpraw*
DWARFraw-
Markdown*raw
Formraw-

API вставки

insert(String tableName, InputStream data, ClickHouseFormat format)

Принимает данные в виде потока байтов (InputStream) в указанном формате. Ожидается, что data закодирован в формате format.

Сигнатуры

CompletableFuture<InsertResponse> insert(String tableName, InputStream data, ClickHouseFormat format, InsertSettings settings)
CompletableFuture<InsertResponse> insert(String tableName, InputStream data, ClickHouseFormat format)

Параметры

tableName — имя целевой таблицы.

data — входной поток закодированных данных.

format — формат, в котором закодированы данные.

settings — настройки запроса.

Возвращаемое значение

Future типа InsertResponse — результат операции и дополнительная информация, например, метрики на стороне сервера.

Примеры

try (InputStream dataStream = getDataStream()) {
    try (InsertResponse response = client.insert(TABLE_NAME, dataStream, ClickHouseFormat.JSONEachRow,
            insertSettings).get(3, TimeUnit.SECONDS)) {

        log.info("Insert finished: {} rows written", response.getMetrics().getMetric(ServerMetrics.NUM_ROWS_WRITTEN).getLong());
    } catch (Exception e) {
        log.error("Failed to write JSONEachRow data", e);
        throw new RuntimeException(e);
    }
}

insert(String tableName, List<?> data, InsertSettings settings)

Отправляет запрос на запись в базу данных. Список объектов преобразуется в эффективный формат и затем отправляется на сервер. Класс элементов списка должен быть предварительно зарегистрирован с помощью метода register(Class, TableSchema).

Сигнатуры

client.insert(String tableName, List<?> data, InsertSettings settings)
client.insert(String tableName, List<?> data)

Параметры

tableName — имя целевой таблицы.

data — коллекция объектов DTO (Data Transfer Object).

settings — настройки запроса.

Возвращаемое значение

Future типа InsertResponse — это результат операции и дополнительная информация, например метрики сервера.

Примеры

// Important step (done once) - register class to pre-compile object serializer according to the table schema.
client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME));

List<ArticleViewEvent> events = loadBatch();

try (InsertResponse response = client.insert(TABLE_NAME, events).get()) {
    // handle response, then it will be closed and connection that served request will be released.
}

InsertSettings

Параметры конфигурации операций вставки.

Методы конфигурации

МетодОписание
setQueryId(String queryId)Устанавливает идентификатор запроса, который будет присвоен операции. Значение по умолчанию: null.
setDeduplicationToken(String token)Устанавливает токен дедупликации. Этот токен будет отправлен на сервер и может использоваться для идентификации запроса. Значение по умолчанию: null.
setInputStreamCopyBufferSize(int size)Размер буфера копирования. Буфер используется при выполнении операций записи для копирования данных из входного потока, предоставленного пользователем, в выходной поток. Значение по умолчанию: 8196.
serverSetting(String name, String value)Устанавливает индивидуальную настройку сервера для операции.
serverSetting(String name, Collection values)Устанавливает отдельную серверную настройку с несколькими значениями для данной операции. Элементы коллекции должны быть значениями типа String.
setDBRoles(Collection dbRoles)Задаёт роли БД, которые будут установлены перед выполнением операции. Элементы коллекции должны быть значениями типа String.
setOption(String option, Object value)Устанавливает параметр конфигурации в «сыром» виде. Это не настройка сервера.

InsertResponse

Объект ответа, содержащий результат операции вставки. Он доступен только в том случае, если клиент получил ответ от сервера.

Примечание

Этот объект необходимо закрыть как можно скорее, чтобы освободить соединение, так как соединение нельзя повторно использовать, пока все данные предыдущего ответа не будут полностью прочитаны.

МетодОписание
OperationMetrics getMetrics()Возвращает объект с метриками операции.
String getQueryId()Возвращает идентификатор запроса, назначенный операции приложением (через настройки операции) или сервером.

API запросов

query(String sqlQuery)

Отправляет sqlQuery как есть. Формат ответа определяется настройками запроса. QueryResponse будет содержать ссылку на поток ответа, который должен быть прочитан ридером, работающим с соответствующим форматом.

Сигнатуры

CompletableFuture<QueryResponse> query(String sqlQuery, QuerySettings settings)
CompletableFuture<QueryResponse> query(String sqlQuery)

Параметры

sqlQuery — один SQL-оператор. Запрос отправляется на сервер как есть.

settings — настройки запроса.

Возвращаемое значение

Future с типом QueryResponse — результирующий набор данных и дополнительная информация, например метрики на стороне сервера. Объект Response следует закрыть после чтения набора данных.

Примеры

final String sql = "select * from " + TABLE_NAME + " where title <> '' limit 10";

// Default format is RowBinaryWithNamesAndTypesFormatReader so reader have all information about columns
try (QueryResponse response = client.query(sql).get(3, TimeUnit.SECONDS);) {

    // Create a reader to access the data in a convenient way
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);

    while (reader.hasNext()) {
        reader.next(); // Read the next record from stream and parse it

        // get values
        double id = reader.getDouble("id");
        String title = reader.getString("title");
        String url = reader.getString("url");

        // collecting data
    }
} catch (Exception e) {
    log.error("Failed to read data", e);
}

// put business logic outside of the reading block to release http connection asap.

query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)

Отправляет sqlQuery как есть. Также передаёт параметры запроса, чтобы сервер мог скомпилировать SQL-выражение.

Сигнатуры

CompletableFuture<QueryResponse> query(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)

Параметры

sqlQuery - SQL-выражение с плейсхолдерами {}.

queryParams — словарь переменных для подстановки значений при формировании SQL-выражения на стороне сервера.

settings — настройки запроса.

Возвращаемое значение

Future типа QueryResponse — результирующий набор данных и дополнительная информация, например метрики на стороне сервера. Объект Response должен быть закрыт после полного чтения набора данных.

Примеры


// define parameters. They will be sent to the server along with the request.
Map<String, Object> queryParams = new HashMap<>();
queryParams.put("param1", 2);

try (QueryResponse response =
        client.query("SELECT * FROM " + table + " WHERE col1 >= {param1:UInt32}", queryParams, new QuerySettings()).get()) {

    // Create a reader to access the data in a convenient way
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);

    while (reader.hasNext()) {
        reader.next(); // Read the next record from stream and parse it

        // reading data
    }

} catch (Exception e) {
    log.error("Failed to read data", e);
}

queryAll(String sqlQuery)

Запрашивает данные в формате RowBinaryWithNamesAndTypes. Возвращает результат в виде коллекции. Скорость чтения такая же, как у reader, но для хранения всего набора данных требуется больше памяти.

Сигнатуры

List<GenericRecord> queryAll(String sqlQuery)

Параметры

sqlQuery — SQL-выражение для запроса данных с сервера.

Возвращаемое значение

Полный набор данных, представленный списком объектов GenericRecord, обеспечивающих построчный доступ к данным результата.

Примеры

try {
    log.info("Reading whole table and process record by record");
    final String sql = "select * from " + TABLE_NAME + " where title <> ''";

    // Read whole result set and process it record by record
    client.queryAll(sql).forEach(row -> {
        double id = row.getDouble("id");
        String title = row.getString("title");
        String url = row.getString("url");

        log.info("id: {}, title: {}, url: {}", id, title, url);
    });
} catch (Exception e) {
    log.error("Failed to read data", e);
}

QuerySettings

Параметры конфигурации для операций выполнения запросов.

Методы настройки

МетодОписание
setQueryId(String queryId)Устанавливает идентификатор запроса, который будет присвоен операции.
setFormat(ClickHouseFormat format)Задаёт формат ответа. Полный список см. в RowBinaryWithNamesAndTypes.
setMaxExecutionTime(Integer maxExecutionTime)Устанавливает время выполнения операции на сервере. Не влияет на тайм-аут чтения.
waitEndOfQuery(Boolean waitEndOfQuery)Заставляет сервер дожидаться завершения запроса перед отправкой ответа.
setUseServerTimeZone(Boolean useServerTimeZone)Часовой пояс сервера (см. конфигурацию клиента) будет использоваться для разбора значений типов даты и времени в результате выполнения операции. По умолчанию false.
setUseTimeZone(String timeZone)Запрашивает, чтобы сервер использовал часовой пояс timeZone для преобразования времени. См. session_timezone.
serverSetting(String name, String value)Устанавливает отдельные настройки сервера для операции.
serverSetting(String name, Collection values)Устанавливает отдельную серверную настройку с несколькими значениями для операции. Элементы коллекции должны быть значениями типа String.
setDBRoles(Collection dbRoles)Задаёт роли БД, которые будут назначены перед выполнением операции. Элементы коллекции должны быть значениями типа String.
setOption(String option, Object value)Устанавливает параметр конфигурации в «сыром» виде. Это не настройка сервера.

QueryResponse

Объект ответа, содержащий результат выполнения запроса. Доступен только в том случае, если клиент получил ответ от сервера.

Примечание

Этот объект следует закрыть как можно скорее, чтобы освободить соединение, поскольку соединение нельзя повторно использовать, пока все данные предыдущего ответа не будут полностью прочитаны.

МетодОписание
ClickHouseFormat getFormat()Возвращает формат, в котором закодированы данные в ответе.
InputStream getInputStream()Возвращает несжатый поток байтов с данными в указанном формате.
OperationMetrics getMetrics()Возвращает объект, содержащий метрики операции.
String getQueryId()Возвращает идентификатор запроса, назначенный операции приложением (через настройки операции) или сервером.
TimeZone getTimeZone()Возвращает часовой пояс, который должен использоваться для обработки типов Date/DateTime в ответе.

Примеры

Общий API

getTableSchema(String table)

Извлекает схему таблицы table.

Подписи

TableSchema getTableSchema(String table)
TableSchema getTableSchema(String table, String database)

Параметры

table — имя таблицы, для которой необходимо получить данные схемы.

database — база данных, в которой определена целевая таблица.

Возвращаемое значение

Возвращает объект TableSchema со списком столбцов таблицы.

getTableSchemaFromQuery(String sql)

Извлекает схему из SQL-выражения.

Сигнатуры

TableSchema getTableSchemaFromQuery(String sql)

Параметры

sql - SQL-оператор "SELECT", схема которого должна быть возвращена.

Возвращаемое значение

Возвращает объект TableSchema со столбцами, соответствующими выражению sql.

TableSchema

register(Class<?> clazz, TableSchema schema)

Компилирует слой сериализации и десериализации для Java-класса, который будет использоваться для записи и чтения данных в соответствии со схемой schema. Метод создаёт сериализатор и десериализатор для пары геттер/сеттер и соответствующего столбца. Соответствие столбца определяется путём извлечения его имени из имени метода. Например, getFirstName будет соответствовать столбцу first_name или firstname.

Сигнатуры

void register(Class<?> clazz, TableSchema schema)

Параметры

clazz — класс POJO, используемый для чтения и записи данных.

schema - Схема данных для сопоставления со свойствами POJO.

Примеры

client.register(ArticleViewEvent.class, client.getTableSchema(TABLE_NAME));

Примеры использования

Полный код примеров хранится в репозитории в каталоге example (folder):

  • 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 для доступа к данным.

Примечание: потоковый подход требует быстрого чтения; в противном случае может произойти тайм-аут записи на сервере, так как данные читаются непосредственно из сетевого потока.

Чтение массивов

Методы ClickHouseBinaryFormatReader

  • getList(...) — читает любой Array(...) как List<T>. Оптимальный вариант по умолчанию для гибкого типизированного чтения. Поддерживает вложенные массивы.
  • getByteArray(...), getShortArray(...), getIntArray(...), getLongArray(...), getFloatArray(...), getDoubleArray(...), getBooleanArray(...) — наиболее подходят для одномерных массивов значений, совместимых с примитивными типами.
  • getStringArray(...) — для Array(String) (и значений перечислений, представленных в виде имён).
  • getObjectArray(...) - универсальный вариант для любого типа элементов Array(...), включая вложенные массивы. Используйте его для чтения массивов с Nullable-значениями и вложенных массивов.

Перегрузки на основе индекса и имени доступны для всех методов. Индексация начинается с 1. Методы, использующие индекс, выполняют прямой доступ к столбцу. Методы, основанные на имени, при каждом вызове выполняют поиск индекса.

try (QueryResponse response = client.query("SELECT * FROM my_table").get()) {
    ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);
    while (reader.next() != null) {
        
        Object[] uint64 = reader.getObjectArray("uint64_arr"); // Array(UInt64) -> BigInteger[]
        Object[] arr2d = reader.getObjectArray("arr2d");       // Array(Array(Int64)) -> Object[]

        // nested arrays are returned as nested Object[]:
        Object[] firstInner = (Object[]) arr2d[0];
        Long firstValue = (Long) firstInner[0];
    }
}

Методы GenericRecord

  • getList(...) — читает любой Array(...) как List<T>. Хороший вариант по умолчанию для гибкого типизированного чтения. Поддерживает вложенные массивы.
  • getByteArray(...), getShortArray(...), getIntArray(...), getLongArray(...), getFloatArray(...), getDoubleArray(...), getBooleanArray(...) — наиболее подходят для одномерных массивов значений, совместимых с примитивными типами.
  • getStringArray(...) — для Array(String) (и значений перечислений, заданных по имени).
  • getObjectArray(...) - универсальный метод для любого типа элементов Array(...), включая вложенные массивы. Используйте его для чтения массивов со значениями Nullable и вложенными массивами.

Перегрузки по индексу и по имени доступны для всех методов. Нумерация индексов начинается с 1. Методы, основанные на индексе, обеспечивают прямой доступ к столбцу. Методы, основанные на имени, при каждом вызове выполняют поиск индекса.

try (QueryResponse response = client.query("SELECT * FROM my_table").get()) {
    List<GenericRecord> rows = client.queryAll(
        "SELECT int_arr, arr2d_nullable FROM test_arrays ORDER BY id");

    for (GenericRecord row : rows) {
        Object[] intArr = row.getObjectArray("int_arr");                 // Array(Int32) -> Integer[]
        Object[] arr2d = row.getObjectArray("arr2d_nullable");           // Array(Array(Nullable(Int32)))

        Object[] inner = (Object[]) arr2d[0];
        Object maybeNull = inner[1]; // may be null
    }
}


## Migration Guide                   


Old client (V1) was using `com.clickhouse.client.ClickHouseClient#builder` as start point. The new client (V2) uses similar pattern with `com.clickhouse.client.api.Client.Builder`. Main
differences are:
- no service loader is used to grab implementation. The `com.clickhouse.client.api.Client` is facade class for all kinds of implementation in the future.
- a fewer sources of configuration: one is provided to the builder and one is with operation settings (`QuerySettings`, `InsertSettings`). Previous version had configuration per node and was loading
env. variables in some cases.

### Configuration Parameters Match                            

There are 3 enum classes related to configuration in V1:
- `com.clickhouse.client.config.ClickHouseDefaults` - configuration parameters that supposed to be set in most use cases. Like `USER` and `PASSWORD`.
- `com.clickhouse.client.config.ClickHouseClientOption` - configuration parameters specific for the client. Like `HEALTH_CHECK_INTERVAL`.
- `com.clickhouse.client.http.config.ClickHouseHttpOption` - configuration parameters specific for HTTP interface. Like `RECEIVE_QUERY_PROGRESS`.

They were designed to group parameters and provide clear separation. However in some cases it lead to a confusion (is there a difference between `com.clickhouse.client.config.ClickHouseDefaults#ASYNC` and
`com.clickhouse.client.config.ClickHouseClientOption#ASYNC`). The new V2 client uses `com.clickhouse.client.api.Client.Builder` as single dictionary of all possible client configuration options.There is
`com.clickhouse.client.api.ClientConfigProperties` where all configuration parameter names are listed.

Table below shows what old options are supported in the new client and their new meaning.

**Legend:** ✔ = supported, ✗ = dropped

<Tabs groupId="v1-migration">
<TabItem value="connection-auth" label="Connection & Auth">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#HOST` | `Client.Builder#addEndpoint` | |
| `ClickHouseDefaults#PROTOCOL` | ✗ | Only HTTP supported in V2 |
| `ClickHouseDefaults#DATABASE`<br/>`ClickHouseClientOption#DATABASE` | `Client.Builder#setDefaultDatabase` | |
| `ClickHouseDefaults#USER` | `Client.Builder#setUsername` | |
| `ClickHouseDefaults#PASSWORD` | `Client.Builder#setPassword` | |
| `ClickHouseClientOption#CONNECTION_TIMEOUT` | `Client.Builder#setConnectTimeout` | |
| `ClickHouseClientOption#CONNECTION_TTL` | `Client.Builder#setConnectionTTL` | |
| `ClickHouseHttpOption#MAX_OPEN_CONNECTIONS` | `Client.Builder#setMaxConnections` | |
| `ClickHouseHttpOption#KEEP_ALIVE`<br/>`ClickHouseHttpOption#KEEP_ALIVE_TIMEOUT` | `Client.Builder#setKeepAliveTimeout` | |
| `ClickHouseHttpOption#CONNECTION_REUSE_STRATEGY` | `Client.Builder#setConnectionReuseStrategy` | |
| `ClickHouseHttpOption#USE_BASIC_AUTHENTICATION` | `Client.Builder#useHTTPBasicAuth` | |

</TabItem>

<TabItem value="ssl" label="SSL & Security">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#SSL_CERTIFICATE_TYPE` | ✗ | |
| `ClickHouseDefaults#SSL_KEY_ALGORITHM` | ✗ | |
| `ClickHouseDefaults#SSL_PROTOCOL` | ✗ | |
| `ClickHouseClientOption#SSL` | ✗ | See `Client.Builder#addEndpoint` |
| `ClickHouseClientOption#SSL_MODE` | ✗ | |
| `ClickHouseClientOption#SSL_ROOT_CERTIFICATE` | `Client.Builder#setRootCertificate` | SSL Auth should be enabled by `useSSLAuthentication` |
| `ClickHouseClientOption#SSL_CERTIFICATE` | `Client.Builder#setClientCertificate` | |
| `ClickHouseClientOption#SSL_KEY` | `Client.Builder#setClientKey` | |
| `ClickHouseClientOption#KEY_STORE_TYPE` | `Client.Builder#setSSLTrustStoreType` | |
| `ClickHouseClientOption#TRUST_STORE` | `Client.Builder#setSSLTrustStore` | |
| `ClickHouseClientOption#KEY_STORE_PASSWORD` | `Client.Builder#setSSLTrustStorePassword` | |
| `ClickHouseClientOption#SSL_SOCKET_SNI` | `Client.Builder#sslSocketSNI` | |
| `ClickHouseClientOption#CUSTOM_SOCKET_FACTORY` | ✗ | |
| `ClickHouseClientOption#CUSTOM_SOCKET_FACTORY_OPTIONS` | ✗ | See `Client.Builder#sslSocketSNI` to set SNI |

</TabItem>

<TabItem value="socket" label="Socket Options">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#SOCKET_TIMEOUT` | `Client.Builder#setSocketTimeout` | |
| `ClickHouseClientOption#SOCKET_REUSEADDR` | `Client.Builder#setSocketReuseAddress` | |
| `ClickHouseClientOption#SOCKET_KEEPALIVE` | `Client.Builder#setSocketKeepAlive` | |
| `ClickHouseClientOption#SOCKET_LINGER` | `Client.Builder#setSocketLinger` | |
| `ClickHouseClientOption#SOCKET_IP_TOS` | ✗ | |
| `ClickHouseClientOption#SOCKET_TCP_NODELAY` | `Client.Builder#setSocketTcpNodelay` | |
| `ClickHouseClientOption#SOCKET_RCVBUF` | `Client.Builder#setSocketRcvbuf` | |
| `ClickHouseClientOption#SOCKET_SNDBUF` | `Client.Builder#setSocketSndbuf` | |

</TabItem>

<TabItem value="compression" label="Compression">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#COMPRESS` | `Client.Builder#compressServerResponse` | See also `useHttpCompression` |
| `ClickHouseClientOption#DECOMPRESS` | `Client.Builder#compressClientRequest` | See also `useHttpCompression` |
| `ClickHouseClientOption#COMPRESS_ALGORITHM` | ✗ | `LZ4` for non-http. Http uses `Accept-Encoding` |
| `ClickHouseClientOption#DECOMPRESS_ALGORITHM` | ✗ | `LZ4` for non-http. Http uses `Content-Encoding` |
| `ClickHouseClientOption#COMPRESS_LEVEL` | ✗ | |
| `ClickHouseClientOption#DECOMPRESS_LEVEL` | ✗ | |

</TabItem>

<TabItem value="proxy" label="Proxy">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#PROXY_TYPE` | `Client.Builder#addProxy` | |
| `ClickHouseClientOption#PROXY_HOST` | `Client.Builder#addProxy` | |
| `ClickHouseClientOption#PROXY_PORT` | `Client.Builder#addProxy` | |
| `ClickHouseClientOption#PROXY_USERNAME` | `Client.Builder#setProxyCredentials` | |
| `ClickHouseClientOption#PROXY_PASSWORD` | `Client.Builder#setProxyCredentials` | |

</TabItem>

<TabItem value="timeouts-retry" label="Timeouts & Retry">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#MAX_EXECUTION_TIME` | `Client.Builder#setExecutionTimeout` | |
| `ClickHouseClientOption#RETRY` | `Client.Builder#setMaxRetries` | See also `retryOnFailures` |
| `ClickHouseHttpOption#AHC_RETRY_ON_FAILURE` | `Client.Builder#retryOnFailures` | |
| `ClickHouseClientOption#FAILOVER` | ✗ | |
| `ClickHouseClientOption#REPEAT_ON_SESSION_LOCK` | ✗ | |
| `ClickHouseClientOption#SESSION_ID` | ✗ | |
| `ClickHouseClientOption#SESSION_CHECK` | ✗ | |
| `ClickHouseClientOption#SESSION_TIMEOUT` | ✗ | |

</TabItem>

<TabItem value="timezone" label="Timezone">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#SERVER_TIME_ZONE`<br/>`ClickHouseClientOption#SERVER_TIME_ZONE` | `Client.Builder#setServerTimeZone` | |
| `ClickHouseClientOption#USE_SERVER_TIME_ZONE` | `Client.Builder#useServerTimeZone` | |
| `ClickHouseClientOption#USE_SERVER_TIME_ZONE_FOR_DATES` | | |
| `ClickHouseClientOption#USE_TIME_ZONE` | `Client.Builder#useTimeZone` | |

</TabItem>

<TabItem value="buffers" label="Buffers & Performance">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#BUFFER_SIZE` | `Client.Builder#setClientNetworkBufferSize` | |
| `ClickHouseClientOption#BUFFER_QUEUE_VARIATION` | ✗ | |
| `ClickHouseClientOption#READ_BUFFER_SIZE` | ✗ | |
| `ClickHouseClientOption#WRITE_BUFFER_SIZE` | ✗ | |
| `ClickHouseClientOption#REQUEST_CHUNK_SIZE` | ✗ | |
| `ClickHouseClientOption#REQUEST_BUFFERING` | ✗ | |
| `ClickHouseClientOption#RESPONSE_BUFFERING` | ✗ | |
| `ClickHouseClientOption#MAX_BUFFER_SIZE` | ✗ | |
| `ClickHouseClientOption#MAX_QUEUED_BUFFERS` | ✗ | |
| `ClickHouseClientOption#MAX_QUEUED_REQUESTS` | ✗ | |
| `ClickHouseClientOption#REUSE_VALUE_WRAPPER` | ✗ | |

</TabItem>

<TabItem value="threading" label="Threading & Async">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#ASYNC`<br/>`ClickHouseClientOption#ASYNC` | `Client.Builder#useAsyncRequests` | |
| `ClickHouseDefaults#MAX_SCHEDULER_THREADS` | ✗ | see `setSharedOperationExecutor` |
| `ClickHouseDefaults#MAX_THREADS` | ✗ | see `setSharedOperationExecutor` |
| `ClickHouseDefaults#THREAD_KEEPALIVE_TIMEOUT` | see `setSharedOperationExecutor` | |
| `ClickHouseClientOption#MAX_THREADS_PER_CLIENT` | ✗ | |
| `ClickHouseClientOption#MAX_CORE_THREAD_TTL` | ✗ | |

</TabItem>

<TabItem value="http-headers" label="HTTP & Headers">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseHttpOption#CUSTOM_HEADERS` | `Client.Builder#httpHeaders` | |
| `ClickHouseHttpOption#CUSTOM_PARAMS` | ✗ | See `Client.Builder#serverSetting` |
| `ClickHouseClientOption#CLIENT_NAME` | `Client.Builder#setClientName` | |
| `ClickHouseHttpOption#CONNECTION_PROVIDER` | ✗ | |
| `ClickHouseHttpOption#DEFAULT_RESPONSE` | ✗ | |
| `ClickHouseHttpOption#SEND_HTTP_CLIENT_ID` | ✗ | |
| `ClickHouseHttpOption#AHC_VALIDATE_AFTER_INACTIVITY` | ✗ | Always enabled when Apache Http Client is used |

</TabItem>

<TabItem value="format-query" label="Format & Query">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#FORMAT`<br/>`ClickHouseClientOption#FORMAT` | ✗ | Moved to operation settings (`QuerySettings` and `InsertSettings`) |
| `ClickHouseClientOption#QUERY_ID` | ✗ | See `QuerySettings` and `InsertSettings` |
| `ClickHouseClientOption#LOG_LEADING_COMMENT` | ✗ | See `QuerySettings#logComment` and `InsertSettings#logComment` |
| `ClickHouseClientOption#MAX_RESULT_ROWS` | ✗ | Is server side setting |
| `ClickHouseClientOption#RESULT_OVERFLOW_MODE` | ✗ | Is server side setting |
| `ClickHouseHttpOption#RECEIVE_QUERY_PROGRESS` | ✗ | Server side setting |
| `ClickHouseHttpOption#WAIT_END_OF_QUERY` | ✗ | Server side setting |
| `ClickHouseHttpOption#REMEMBER_LAST_SET_ROLES` | `Client#setDBRoles` | Runtime config now. See also `QuerySettings#setDBRoles` and `InsertSettings#setDBRoles` |

</TabItem>

<TabItem value="node-discovery" label="Node Discovery & Load Balancing">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseClientOption#AUTO_DISCOVERY` | ✗ | |
| `ClickHouseClientOption#LOAD_BALANCING_POLICY` | ✗ | |
| `ClickHouseClientOption#LOAD_BALANCING_TAGS` | ✗ | |
| `ClickHouseClientOption#HEALTH_CHECK_INTERVAL` | ✗ | |
| `ClickHouseClientOption#HEALTH_CHECK_METHOD` | ✗ | |
| `ClickHouseClientOption#NODE_DISCOVERY_INTERVAL` | ✗ | |
| `ClickHouseClientOption#NODE_DISCOVERY_LIMIT` | ✗ | |
| `ClickHouseClientOption#NODE_CHECK_INTERVAL` | ✗ | |
| `ClickHouseClientOption#NODE_GROUP_SIZE` | ✗ | |
| `ClickHouseClientOption#CHECK_ALL_NODES` | ✗ | |

</TabItem>

<TabItem value="misc" label="Miscellaneous">

| V1 Configuration | V2 Builder Method | Comments |
|------------------|-------------------|----------|
| `ClickHouseDefaults#AUTO_SESSION` | ✗ | Session support will be reviewed |
| `ClickHouseDefaults#BUFFERING` | ✗ | |
| `ClickHouseDefaults#MAX_REQUESTS` | ✗ | |
| `ClickHouseDefaults#ROUNDING_MODE` | | |
| `ClickHouseDefaults#SERVER_VERSION`<br/>`ClickHouseClientOption#SERVER_VERSION` | `Client.Builder#setServerVersion` | |
| `ClickHouseDefaults#SRV_RESOLVE` | ✗ | |
| `ClickHouseClientOption#CUSTOM_SETTINGS` | | |
| `ClickHouseClientOption#PRODUCT_NAME` | ✗ | Use client name |
| `ClickHouseClientOption#RENAME_RESPONSE_COLUMN` | ✗ | |
| `ClickHouseClientOption#SERVER_REVISION` | ✗ | |
| `ClickHouseClientOption#TRANSACTION_TIMEOUT` | ✗ | |
| `ClickHouseClientOption#WIDEN_UNSIGNED_TYPES` | ✗ | |
| `ClickHouseClientOption#USE_BINARY_STRING` | ✗ | |
| `ClickHouseClientOption#USE_BLOCKING_QUEUE` | ✗ | |
| `ClickHouseClientOption#USE_COMPILATION` | ✗ | |
| `ClickHouseClientOption#USE_OBJECTS_IN_ARRAYS` | ✗ | |
| `ClickHouseClientOption#MAX_MAPPER_CACHE` | ✗ | |
| `ClickHouseClientOption#MEASURE_REQUEST_TIME` | ✗ | |

</TabItem>
</Tabs>


### General Differences

- Client V2 uses less proprietary classes to increase portability. For example, V2 works with any implementation of `java.io.InputStream` for
writing data to a server.
- Client V2 `async` settings is `off` by default. It means no extra threads and more application control over client. This setting should be `off` for majority of use cases. Enabling `async` will create a separate thread for a request. It only make sense when using application controlled
executor (see `com.clickhouse.client.api.Client.Builder#setSharedOperationExecutor`)

### Writing Data

- use any implementation of `java.io.InputStream`. V1 `com.clickhouse.data.ClickHouseInputStream` is supported but NOT recommended.
- once end of input stream is detected it handled accordingly. Previously output stream of a request should be closed.

__V1 Insert TSV formatted data.__
```java
InputStream inData = getInData();
ClickHouseRequest.Mutation request = client.read(server)
        .write()
        .table(tableName)
        .format(ClickHouseFormat.TSV);
ClickHouseConfig config = request.getConfig();
CompletableFuture<ClickHouseResponse> future;
try (ClickHousePipedOutputStream requestBody = ClickHouseDataStreamFactory.getInstance()
        .createPipedOutputStream(config)) {
    // start the worker thread which transfer data from the input into ClickHouse
    future = request.data(requestBody.getInputStream()).execute();

    // Copy data from inData stream to requestBody stream

    // We need to close the stream before getting a response
    requestBody.close();

    try (ClickHouseResponse response = future.get()) {
        ClickHouseResponseSummary summary = response.getSummary();
        Assert.assertEquals(summary.getWrittenRows(), numRows, "Num of written rows");
    }
}

V2 Вставка данных в формате TSV.

InputStream inData = getInData();
InsertSettings settings = new InsertSettings().setInputStreamCopyBufferSize(8198 * 2); // set copy buffer size
try (InsertResponse response = client.insert(tableName, inData, ClickHouseFormat.TSV, settings).get(30, TimeUnit.SECONDS)) {

  // Insert is complete at this point

} catch (Exception e) {
 // Handle exception
}
  • достаточно вызвать один метод — нет необходимости создавать дополнительный объект запроса.
  • Поток тела запроса автоматически закрывается после копирования всех данных.
  • Теперь доступен новый низкоуровневый 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 предоставляет доступ к данным и выполняет некоторые преобразования типов.
Collection<GenericRecord> records = client.queryAll("SELECT * FROM table");
for (GenericRecord record : records) {
    int rowId = record.getInteger("rowID");
    String name = record.getString("name");
    LocalDateTime ts = record.getLocalDateTime("ts");
}

Клиентская библиотека на Java для взаимодействия с сервером БД через его протоколы. Текущая реализация поддерживает только HTTP-интерфейс. Библиотека предоставляет собственный API для отправки запросов на сервер.

Устаревшая библиотека

Эта библиотека скоро будет объявлена устаревшей. Для новых проектов используйте последнюю версию Java Client

Настройка

<!-- https://mvnrepository.com/artifact/com.clickhouse/clickhouse-http-client -->
<dependency>
    <groupId>com.clickhouse</groupId>
    <artifactId>clickhouse-http-client</artifactId>
    <version>0.7.2</version>
</dependency>

Начиная с версии 0.5.0, драйвер использует новую клиентскую HTTP-библиотеку, которую необходимо добавить в качестве зависимости.

<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents.client5/httpclient5 -->
<dependency>
    <groupId>org.apache.httpcomponents.client5</groupId>
    <artifactId>httpclient5</artifactId>
    <version>5.3.1</version>
</dependency>

Инициализация

Формат URL-адреса подключения: protocol://host[:port][/database][?param[=value][&param[=value]][#tag[,tag]], например:

Подключитесь к одному узлу:

ClickHouseNode server = ClickHouseNode.of("http://localhost:8123/default?compress=0");

Подключитесь к кластеру с несколькими узлами:

ClickHouseNodes servers = ClickHouseNodes.of(
    "jdbc:ch:http://server1.domain,server2.domain,server3.domain/my_db"
    + "?load_balancing_policy=random&health_check_interval=5000&failover=2");

API запросов

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from numbers limit :limit")
        .params(1000)
        .executeAndWait()) {
            ClickHouseResponseSummary summary = response.getSummary();
            long totalRows = summary.getTotalRowsToRead();
}

API потоковых запросов

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from numbers limit :limit")
        .params(1000)
        .executeAndWait()) {
            for (ClickHouseRecord r : response.records()) {
            int num = r.getValue(0).asInteger();
            // type conversion
            String str = r.getValue(0).asString();
            LocalDate date = r.getValue(0).asDate();
        }
}

См. полный пример кода в репозитории.

API вставки данных


try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers).write()
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("insert into my_table select c2, c3 from input('c1 UInt8, c2 String, c3 Int32')")
        .data(myInputStream) // `myInputStream` is source of data in RowBinary format
        .executeAndWait()) {
            ClickHouseResponseSummary summary = response.getSummary();
            summary.getWrittenRows();
}

См. полный пример кода в репозитории.

Кодирование в формате RowBinary

Формат RowBinary описан на его странице.

Пример приведён в коде.

Возможности

Сжатие

По умолчанию клиент использует алгоритм сжатия LZ4; для этого требуется следующая зависимость:

<!-- https://mvnrepository.com/artifact/org.lz4/lz4-java -->
<dependency>
    <groupId>org.lz4</groupId>
    <artifactId>lz4-java</artifactId>
    <version>1.8.0</version>
</dependency>

Вместо этого можно использовать gzip, задав compress_algorithm=gzip в URL-адресе подключения.

Сжатие также можно отключить несколькими способами.

  1. Отключите сжатие, указав compress=0 в URL-адресе подключения: http://localhost:8123/default?compress=0
  2. Отключите через конфигурацию клиента:
ClickHouseClient client = ClickHouseClient.builder()
   .config(new ClickHouseConfig(Map.of(ClickHouseClientOption.COMPRESS, false)))
   .nodeSelector(ClickHouseNodeSelector.of(ClickHouseProtocol.HTTP))
   .build();

Подробнее о различных вариантах сжатия см. в документации по сжатию.

Несколько запросов

Выполните несколько запросов в рабочем потоке последовательно в рамках одного сеанса:

CompletableFuture<List<ClickHouseResponseSummary>> future = ClickHouseClient.send(servers.apply(servers.getNodeSelector()),
    "create database if not exists my_base",
    "use my_base",
    "create table if not exists test_table(s String) engine=Memory",
    "insert into test_table values('1')('2')('3')",
    "select * from test_table limit 1",
    "truncate table test_table",
    "drop table if exists test_table");
List<ClickHouseResponseSummary> results = future.get();

Именованные параметры

Параметры можно передавать по имени, а не только полагаясь на их положение в списке параметров. Эта возможность доступна с помощью функции params.

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name limit :limit")
        .params("Ben", 1000)
        .executeAndWait()) {
            //...
        }
}
Параметры

Все сигнатуры params, включающие тип String (String, String[], Map<String, String>), предполагают, что передаваемые ключи являются корректными строками SQL для ClickHouse. Например:

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name")
        .params(Map.of("name","'Ben'"))
        .executeAndWait()) {
            //...
        }
}

Если вы не хотите вручную преобразовывать объекты String в выражения ClickHouse SQL, используйте вспомогательную функцию ClickHouseValues.convertToSqlExpression, расположенную в пакете com.clickhouse.data:

try (ClickHouseClient client = ClickHouseClient.newInstance(ClickHouseProtocol.HTTP);
     ClickHouseResponse response = client.read(servers)
        .format(ClickHouseFormat.RowBinaryWithNamesAndTypes)
        .query("select * from my_table where name=:name")
        .params(Map.of("name", ClickHouseValues.convertToSqlExpression("Ben's")))
        .executeAndWait()) {
            //...
        }
}

В приведённом выше примере ClickHouseValues.convertToSqlExpression экранирует внутреннюю одинарную кавычку и обернёт значение переменной в корректные одинарные кавычки.

Другие типы, такие как Integer, UUID, Array и Enum, будут автоматически преобразованы внутри params.

Обнаружение узлов

Java-клиент предоставляет возможность автоматического обнаружения узлов ClickHouse. Автообнаружение отключено по умолчанию. Чтобы включить его вручную, установите параметр auto_discovery в true:

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

Или в URL-адресе подключения:

jdbc:ch://my-server/system?auto_discovery=true

При включённом автообнаружении нет необходимости указывать все узлы ClickHouse в URL подключения. Узлы, указанные в URL, будут рассматриваться как начальные (seed) узлы, и Java-клиент автоматически обнаружит дополнительные узлы по данным системных таблиц и/или через clickhouse-keeper или ZooKeeper.

Следующие параметры отвечают за настройку автоматического обнаружения:

СвойствоЗначение по умолчаниюОписание
auto_discoveryfalseОпределяет, должен ли клиент автоматически обнаруживать дополнительные узлы из системных таблиц и/или через clickhouse-keeper/ZooKeeper.
node_discovery_interval0Интервал обнаружения узлов в миллисекундах; нулевое или отрицательное значение означает однократное обнаружение.
node_discovery_limit100Максимальное количество узлов, которые могут быть обнаружены за один раз; нулевое или отрицательное значение означает отсутствие ограничения.

Балансировка нагрузки

Java-клиент выбирает узел ClickHouse для отправки запросов в соответствии с политикой балансировки нагрузки. В общем случае политика балансировки нагрузки отвечает за следующее:

  1. Выбрать узел из списка управляемых узлов.
  2. Управление состоянием узла.
  3. При необходимости запланируйте фоновый процесс обнаружения узлов (если автообнаружение включено) и запуск проверки их работоспособности.

Ниже приведён список параметров для настройки балансировки нагрузки:

СвойствоЗначение по умолчаниюОписание
load_balancing_policy""Политика балансировки нагрузки может иметь одно из следующих значений:
  • firstAlive — запрос отправляется первому работоспособному узлу из списка управляемых узлов
  • random — запрос отправляется случайному узлу из списка управляемых узлов
  • roundRobin — запросы по очереди отправляются на каждый узел из списка управляемых узлов
  • полное имя класса, реализующего интерфейс ClickHouseLoadBalancingPolicy, — пользовательская политика балансировки нагрузки
  • Если политика не указана, запрос отправляется на первый узел из списка управляемых узлов
    load_balancing_tags""Теги балансировки нагрузки для фильтрации узлов. Запросы отправляются только на узлы с указанными тегами.
    health_check_interval0Интервал проверки работоспособности в миллисекундах; нулевое или отрицательное значение означает однократную проверку.
    health_check_methodClickHouseHealthCheckMethod.SELECT_ONEМетод проверки работоспособности. Может быть одним из следующих:
  • ClickHouseHealthCheckMethod.SELECT_ONE - проверка с помощью запроса select 1
  • ClickHouseHealthCheckMethod.PING - проверка на уровне протокола, как правило более быстрая
  • node_check_interval0Интервал проверки узла в миллисекундах, отрицательное значение рассматривается как ноль. Статус узла проверяется, если с момента последней проверки прошло указанное время.
    Разница между health_check_interval и node_check_interval заключается в том, что опция health_check_interval планирует фоновое задание, которое проверяет статус узлов в списке (всех или только проблемных), а node_check_interval задаёт минимальное время, которое должно пройти с момента последней проверки конкретного узла.
    check_all_nodesfalseОпределяет, выполнять ли проверку работоспособности для всех узлов или только для проблемных.

    Отказоустойчивость и повторные попытки

    Java-клиент предоставляет параметры конфигурации для настройки поведения отказоустойчивости и повторных попыток при сбоях запросов:

    СвойствоЗначение по умолчаниюОписание
    failover0Максимальное число переключений (failover) для одного запроса. Нулевое или отрицательное значение означает отсутствие failover. При failover неуспешный запрос отправляется на другой узел (в соответствии с политикой балансировки нагрузки) для восстановления после сбоя.
    retry0Максимальное количество повторных попыток выполнения запроса. Нулевое или отрицательное значение означает, что повторные попытки не выполняются. Повторная отправка запроса выполняется на тот же узел и только в том случае, если сервер ClickHouse возвращает код ошибки NETWORK_ERROR.
    repeat_on_session_locktrueСледует ли повторно выполнять запрос, если сеанс заблокирован до истечения времени ожидания (в соответствии с session_timeout или connect_timeout). Неудачный запрос повторяется, если сервер ClickHouse возвращает код ошибки SESSION_IS_LOCKED

    Добавление пользовательских HTTP-заголовков

    Java-клиент поддерживает транспортный уровень HTTP/S на случай, если нужно добавить пользовательские HTTP-заголовки к запросу. Следует использовать свойство custom_http_headers: заголовки перечисляются через запятую (,), а ключ и значение заголовка разделяются знаком равенства (=).

    Поддержка Java-клиента

    options.put("custom_http_headers", "X-ClickHouse-Quota=test, X-ClickHouse-Test=test");
    

    Драйвер JDBC

    properties.setProperty("custom_http_headers", "X-ClickHouse-Quota=test, X-ClickHouse-Test=test");