Biblioteca cliente de Java para comunicarse con un servidor de base de datos a través de sus protocolos. La implementación actual solo admite la interfaz HTTP.
La biblioteca ofrece su propia API para enviar solicitudes a un servidor, y también incluye herramientas para trabajar con distintos formatos de datos binarios (RowBinary* & Native*).
La autenticación mediante un token de acceso requiere establecer el token de acceso llamando a La autenticación mediante un certificado de cliente SSL requiere configurar el nombre de usuario, habilitar la autenticación SSL, y establecer un certificado de cliente y una clave de cliente mediante las llamadas a
dará como resultado el siguiente valor de La aplicación puede establecer su propio encabezado HTTP ⚠️ Cuando las opciones se configuran mediante el método Cuando las opciones se configuran mediante el método ParámetrosParámetrosParámetrosParámetrosParámetrosParámetrosParámetrosParámetrosMétodos de V2 Insertar datos con formato TSV.
Configuración
- Maven Central (página web del proyecto): https://mvnrepository.com/artifact/com.clickhouse/client-v2
- Versiones nocturnas (enlace al repositorio): https://central.sonatype.com/repository/maven-snapshots/
- Artifactory de compilaciones Nightly anteriores (enlace al repositorio): https://s01.oss.sonatype.org/content/repositories/snapshots/
- Maven
- Gradle (Kotlin)
- Gradle
Inicialización
El objeto Client se inicializa mediantecom.clickhouse.client.api.Client.Builder#build(). Cada cliente tiene su propio contexto y no se comparten objetos entre ellos.
El Builder dispone de métodos de configuración para simplificar la configuración.Ejemplo:showLineNumbers
Client es AutoCloseable y debe cerrarse cuando ya no se necesite.Autenticación
La autenticación se configura por cliente en la fase de inicialización. Se admiten tres métodos de autenticación: por contraseña, por token de acceso y por certificado de cliente SSL.La autenticación mediante contraseña requiere configurar el nombre de usuario y la contraseña llamando asetUsername(String) y setPassword(String):showLineNumbers
setAccessToken(String):showLineNumbers
setUsername(String), useSSLAuthentication(boolean), setClientCertificate(String) y setClientKey(String) respectivamente:showLineNumbers
La autenticación SSL puede ser difícil de diagnosticar en producción porque muchos errores de las bibliotecas SSL no proporcionan información suficiente. Por ejemplo, si el certificado del cliente y la clave no coinciden, el servidor cerrará la conexión de inmediato (en el caso de HTTP, esto ocurrirá durante la fase de inicio de la conexión, cuando no se envía ninguna solicitud HTTP, por lo que no se envía ninguna respuesta).Utilice herramientas como openssl para verificar certificados y claves:
- comprobar la integridad de la clave:
openssl rsa -in [key-file.key] -check -noout - comprobar que el certificado del cliente tenga un CN que coincida con un usuario:
- obtener el CN de un certificado de usuario:
openssl x509 -noout -subject -in [user.cert] - verificar que el mismo valor esté establecido en la base de datos
select name, auth_type, auth_params from system.users where auth_type = 'ssl_certificate'(la consulta mostraráauth_paramscon algo como{"common_names":["some_user"]})
- obtener el CN de un certificado de usuario:
Configuración
Todas las configuraciones se definen mediante métodos de instancia (también conocidos como métodos de configuración) que hacen explícitos el alcance y el contexto de cada valor. Los principales parámetros de configuración se definen en un único ámbito (cliente u operación) y no se sobrescriben entre sí.La configuración se define durante la creación del cliente. Consultecom.clickhouse.client.api.Client.Builder.Configuración del cliente
- Conexión & endpoints
- Autenticación
- Tiempos de espera & reintentos
- Opciones de socket
- Compresión
- SSL/Seguridad
- Proxy
- HTTP & Encabezados
- Configuración del servidor
- Zona horaria
- Avanzado
Identificación del cliente
Hay dos campos en el log de consultas que identifican la aplicación que originó una solicitud:client_name y http_user_agent. El protocolo TCP nativo utiliza
client_name para identificar la aplicación. El protocolo HTTP utiliza http_user_agent para identificar la aplicación. El constructor del cliente dispone del método setClientName para establecer los valores correctos
en ambos protocolos.
El campo http_user_agent se establece según el formato común del header User-Agent: application-name[/version] [(operating-system; architecture; ...)].
Este conjunto de valores se repite para cada capa: aplicación, biblioteca cliente y biblioteca cliente HTTP. Lo que establece el método setClientName aparece primero en la lista.Por ejemplo:showLineNumbers
http_user_agent:User-Agent para identificarse. No obstante, el fragmento clickhouse-java-v2/0.9.6-SNAPSHOT se añadirá al final del encabezado.Identificación de operaciones
El registro de consultas cuenta con otros dos campos,query_id y log_comment, que pueden utilizarse para identificar una operación y agregar información adicional al registro de consultas.query_id es un identificador único de una operación. La aplicación puede establecerlo llamando al método setQueryId de la clase QuerySettings.showLineNumbers
log_comment es un comentario que se puede añadir al registro de consultas. Las aplicaciones pueden establecerlo llamando al método logComment de la clase QuerySettings.showLineNumbers
Configuración del servidor
Los ajustes del lado del servidor pueden configurarse a nivel de cliente una sola vez durante la creación (consulte el métodoserverSetting de Builder) y a nivel de operación (consulte serverSetting en la clase de ajustes de operación).showLineNumbers
setOption (ya sea en Client.Builder o en la clase de configuración de operaciones), el nombre de los server settings debe ir precedido del prefijo clickhouse_setting_. En este caso, com.clickhouse.client.api.ClientConfigProperties#serverSetting() puede resultar de utilidad.Encabezado HTTP personalizado
Se pueden configurar HTTP headers personalizados para todas las operaciones (nivel de cliente) o para una sola (nivel de operación).showLineNumbers
setOption (ya sea en Client.Builder o en la clase de configuración de operaciones), el nombre del encabezado personalizado debe llevar el prefijo http_header_. El método com.clickhouse.client.api.ClientConfigProperties#httpHeader() puede ser de utilidad en este caso.Definiciones comunes
ClickHouseFormat
Enum de formatos compatibles. Incluye todos los formatos admitidos por ClickHouse.raw- el usuario debe transcodificar los datos sin procesarfull- el cliente puede transcodificar datos por su cuenta y acepta un flujo de datos sin procesar-- operación no admitida por ClickHouse para este formato
API de inserción
insert(String tableName, InputStream data, ClickHouseFormat format)
Acepta datos como unInputStream de bytes en el formato especificado. Se espera que data esté codificado en el format.FirmastableName - nombre de la tabla de destino.data - un flujo de entrada de datos codificados.format - un formato en el que se codifican los datos.settings - parámetros de la solicitud.Valor de retornoFuture del tipo InsertResponse: resultado de la operación e información adicional como las métricas del lado del servidor.EjemplosshowLineNumbers
insert(String tableName, List<?> data, InsertSettings settings)
Envía una solicitud de escritura a la base de datos. La lista de objetos se convierte a un formato eficiente y luego se envía al servidor. La clase de los elementos de la lista debe registrarse de antemano mediante el métodoregister(Class, TableSchema).FirmastableName - nombre de la tabla de destino.data - objetos DTO (Data Transfer Object) de colección.settings - parámetros de la solicitud.Valor de retornoFuture del tipo InsertResponse: el resultado de la operación e información adicional como las métricas del lado del servidor.EjemplosshowLineNumbers
InsertSettings
Opciones de configuración para operaciones de inserción.Métodos de configuraciónInsertResponse
Objeto de respuesta que contiene el resultado de la operación de inserción. Solo está disponible si el cliente recibió una respuesta del servidor.Este objeto debe cerrarse lo antes posible para liberar una conexión, ya que esta no puede reutilizarse hasta que se hayan leído por completo todos los datos de la respuesta anterior.
API de consultas
query(String sqlQuery)
EnvíasqlQuery tal cual. El formato de respuesta se determina mediante la configuración de la consulta. QueryResponse contendrá una referencia al flujo de respuesta que debe ser consumido por un lector para el formato compatible.FirmassqlQuery - una única sentencia SQL. La consulta se envía tal como está al servidor.settings - parámetros de la solicitud.Valor de retornoFuture del tipo QueryResponse: un conjunto de datos de resultado e información adicional como las métricas del lado del servidor. El objeto Response debe cerrarse tras consumir el conjunto de datos.Ejemplosquery(String sqlQuery, Map<String, Object> queryParams, QuerySettings settings)
EnvíasqlQuery tal cual. Además, enviará los parámetros de consulta para que el servidor pueda compilar la expresión SQL.FirmassqlQuery - expresión SQL con marcadores de posición {}.queryParams - mapa de variables para completar la expresión SQL en el servidor.settings - parámetros de la solicitud.Valor de retornoFuture del tipo QueryResponse: un conjunto de datos de resultado e información adicional como las métricas del lado del servidor. El objeto Response debe cerrarse tras consumir el conjunto de datos.EjemplosshowLineNumbers
queryAll(String sqlQuery)
Consulta datos en formatoRowBinaryWithNamesAndTypes. Devuelve el resultado como una colección. El rendimiento de lectura es el mismo que con el lector, pero se necesita más memoria para almacenar el conjunto de datos completo.FirmassqlQuery - expresión SQL para consultar datos desde un servidor.Valor de retornoConjunto de datos completo representado por una lista de objetos GenericRecord que proporcionan acceso por filas a los datos del resultado.EjemplosshowLineNumbers
QuerySettings
Opciones de configuración para operaciones de consulta.Métodos de configuraciónQueryResponse
Objeto de respuesta que contiene el resultado de la ejecución de la consulta. Solo está disponible si el cliente recibió una respuesta del servidor.Este objeto debe cerrarse lo antes posible para liberar una conexión, ya que esta no puede reutilizarse hasta que se hayan leído por completo todos los datos de la respuesta anterior.
Ejemplos
- El código de ejemplo está disponible en el repositorio
- Servicio de Spring de referencia implementación
API común
getTableSchema(String table)
Obtiene el esquema de la tabla paratable.Firmastable - nombre de la tabla de la que se deben obtener los datos del esquema.database - base de datos donde se define la tabla de destino.Valor de retornoDevuelve un objeto TableSchema con la lista de columnas de la tabla.getTableSchemaFromQuery(String sql)
Obtiene el esquema a partir de una instrucción SQL.Firmassql - Sentencia SQL “SELECT” cuyo esquema se desea obtener.Valor de retornoDevuelve un objeto TableSchema con columnas que coinciden con la expresión sql.TableSchema
register(Class<?> clazz, TableSchema schema)
Compila la capa de serialización y deserialización para la clase Java que se utilizará para escribir y leer datos conschema. El método creará un serializador y un deserializador para el par getter/setter y la columna correspondiente.
La coincidencia de columna se determina extrayendo su nombre a partir del nombre del método. Por ejemplo, getFirstName corresponderá a la columna first_name o firstname.Firmasclazz - Clase que representa el POJO utilizado para leer/escribir datos.schema - Esquema de datos que se usará para hacer coincidir con las propiedades POJO.EjemplosshowLineNumbers
Ejemplos de uso
El código de ejemplos completo está almacenado en el repositorio en la carpeta ‘example`:- client-v2 - colección principal de ejemplos.
- demo-service - ejemplo de cómo utilizar el cliente en una aplicación Spring Boot.
- demo-kotlin-service - ejemplo de cómo usar el cliente en una aplicación de Ktor (Kotlin).
Lectura de datos
Hay dos formas comunes de leer datos:- método
query()que devuelve un objetoQueryResponsede bajo nivel que contiene unInputStreamcon datos. Normalmente se combina conClickHouseBinaryFormatReaderpara lecturas en streaming, pero puede utilizarse con cualquier otra implementación personalizada de lector.QueryResponsetambién proporciona acceso a los metadatos del conjunto de resultados y a las métricas. - método
queryAll()y uso deGenericRecordpara acceder cómodamente a las filas. En este caso, todo el conjunto de resultados se carga en memoria. - método
queryRecords()que devuelvecom.clickhouse.client.api.query.Records: un iterador de objetosGenericRecord. Este método utiliza un enfoque de streaming (no se cargan datos en memoria) y usaGenericRecordpara acceder a los datos.
Lectura de Arrays
Métodos deClickHouseBinaryFormatReadergetList(...)- lee cualquierArray(...)comoList<T>. Es una buena opción predeterminada para lecturas flexibles con tipado. Admite arrays anidados.getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)- mejor para arrays 1D de valores compatibles con tipos primitivos.getStringArray(...)- paraArray(String)(y valores deenumrepresentados por nombres).getObjectArray(...)- opción genérica para cualquier tipo de elemento deArray(...), incluidos los arrays anidados. Úselo para leer arrays con valores anulables y arrays anidados.
GenericRecordgetList(...)- lee cualquierArray(...)comoList<T>. Buena opción predeterminada para lecturas flexibles con tipado. Admite arrays anidados.getByteArray(...),getShortArray(...),getIntArray(...),getLongArray(...),getFloatArray(...),getDoubleArray(...),getBooleanArray(...)- ideal para arrays unidimensionales de valores compatibles con tipos primitivos.getStringArray(...)- paraArray(String)(y valores deenumrepresentados por nombres).getObjectArray(...)- opción genérica para cualquier tipo de elemento deArray(...), incluidos los arrays anidados. Úsela para leer arrays con valores que admiten NULL y arrays anidados.
Guía de migración
El cliente antiguo (V1) utilizabacom.clickhouse.client.ClickHouseClient#builder como punto de partida. El nuevo cliente (V2) usa un patrón similar con com.clickhouse.client.api.Client.Builder. Las principales
diferencias son:- no se utiliza ningún cargador de servicios para obtener la implementación.
com.clickhouse.client.api.Clientes una clase fachada para todo tipo de implementaciones futuras. - menos fuentes de configuración: una se proporciona al builder y otra se encuentra en la configuración de operación (
QuerySettings,InsertSettings). La versión anterior tenía una configuración por nodo y, en algunos casos, cargaba variables de entorno.
Coincidencia de parámetros de configuración
Hay 3 clases enum relacionadas con la configuración en V1:com.clickhouse.client.config.ClickHouseDefaults- parámetros de configuración que suelen establecerse en la mayoría de los casos de uso, comoUSERyPASSWORD.com.clickhouse.client.config.ClickHouseClientOption- parámetros de configuración específicos para el cliente, comoHEALTH_CHECK_INTERVAL.com.clickhouse.client.http.config.ClickHouseHttpOption- parámetros de configuración específicos de la interfaz HTTP, comoRECEIVE_QUERY_PROGRESS.
com.clickhouse.client.config.ClickHouseDefaults#ASYNC y
com.clickhouse.client.config.ClickHouseClientOption#ASYNC?). El nuevo cliente V2 utiliza com.clickhouse.client.api.Client.Builder como diccionario único de todas las opciones de configuración posibles del cliente. En com.clickhouse.client.api.ClientConfigProperties se encuentran listados todos los nombres de parámetros de configuración.La siguiente tabla muestra qué opciones antiguas son compatibles con el nuevo cliente y su nuevo significado.Leyenda: ✔ = compatible, ✗ = eliminado- Conexión y autenticación
- SSL y seguridad
- Opciones de socket
- Compresión
- Proxy
- Timeouts & reintentos
- Zona horaria
- Búferes & rendimiento
- Hilos & asincronía
- HTTP & Encabezados
- Formato & Consulta
- Descubrimiento de nodos & balanceo de carga
- Miscelánea
Diferencias generales
- Client V2 utiliza menos clases propietarias para aumentar la portabilidad. Por ejemplo, V2 funciona con cualquier implementación de
java.io.InputStreampara escribir datos en un servidor. - La configuración
asyncde Client V2 estáoffde forma predeterminada. Esto significa que no hay hilos adicionales y que la aplicación tiene un mayor control sobre el cliente. Esta configuración debería estaroffen la mayoría de los casos de uso. Al habilitarasync, se creará un hilo independiente para cada solicitud. Solo tiene sentido cuando se usa un executor controlado por la aplicación (consultecom.clickhouse.client.api.Client.Builder#setSharedOperationExecutor)
Escritura de datos
- usa cualquier implementación de
java.io.InputStream. Se admite V1com.clickhouse.data.ClickHouseInputStream, pero NO se recomienda. - Una vez detectado el final del flujo de entrada, se actúa en consecuencia. Antes, debe cerrarse el flujo de salida de una solicitud.
- solo hay que llamar a un único método. No es necesario crear un objeto de solicitud adicional.
- el flujo del cuerpo de la solicitud se cierra automáticamente cuando se copian todos los datos.
- hay una nueva API de bajo nivel disponible:
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.DataStreamWriterestá diseñada para implementar lógica personalizada de escritura de datos. Por ejemplo, leer datos de una cola.
Lectura de datos
- Los datos se leen en el formato
RowBinaryWithNamesAndTypesde forma predeterminada. Actualmente, solo se admite este formato cuando se requiere el enlace de datos. - Los datos pueden leerse como una colección de registros mediante el método
List<GenericRecord> com.clickhouse.client.api.Client#queryAll(java.lang.String). Este método lee los datos en memoria y libera la conexión. No requiere ninguna gestión adicional.GenericRecordproporciona acceso a los datos e implementa algunas conversiones.