Saltar al contenido principal
clickhouse-jdbc implementa la interfaz estándar de JDBC con el cliente de Java más reciente. Recomendamos usar directamente el cliente de Java más reciente si el rendimiento o el acceso directo son críticos.

Requisitos del entorno

Setup

Si utiliza el JDBC driver en una aplicación que requiere añadir el jar al classpath, debe descargar el jar desde:

Configuración

Clase del driver: com.clickhouse.jdbc.ClickHouseDriver
com.clickhouse.jdbc.ClickHouseDriver es una clase de fachada para las implementaciones JDBC nueva y antigua. Usa la implementación JDBC nueva de forma predeterminada. Puede usar la implementación JDBC antigua estableciendo en true la propiedad del sistema clickhouse.jdbc.v1. Esta propiedad debe establecerse antes de invocar la clase Driver.Una forma alternativa de cambiar entre versiones es usar directamente las clases Driver de cada versión:
  • com.clickhouse.jdbc.Driver es la implementación JDBC nueva (V2).
  • com.clickhouse.jdbc.DriverV1 es la implementación JDBC antigua (V1).
Sintaxis de URL: jdbc:(ch|clickhouse)[:<protocol>]://endpoint[:port][/<database>][?param1=value1&param2=value2][#tag1,tag2,...], por ejemplo:
  • jdbc:clickhouse:http://localhost:8123
  • jdbc:clickhouse:https://localhost:8443?ssl=true
Hay algunos aspectos que conviene tener en cuenta sobre la sintaxis de la URL:
  • solo se permite un único endpoint en la URL
  • se debe especificar el protocolo cuando no sea el predeterminado - ‘HTTP’
  • se debe especificar el puerto cuando no sea el predeterminado ‘8123’
  • el driver no infiere el protocolo a partir del puerto, debe especificarlo explícitamente
  • El parámetro ssl no se requiere cuando se especifica el protocolo.

Propiedades de conexión

Los principales parámetros de configuración se definen en el cliente de Java. Deben pasarse tal cual al driver. El driver tiene algunas propiedades propias que no forman parte de la configuración del cliente; estas se enumeran a continuación.Propiedades del driver:
Configuración del servidorToda la configuración del servidor debe llevar el prefijo clickhouse_setting_ (igual que en la configuración del cliente).
Ejemplo de configuración:
lo que será equivalente a la siguiente URL JDBC:
Nota: no es necesario codificar en URL la URL JDBC ni las propiedades; se codificarán automáticamente.Perfiles de solo lecturaEvitamos deliberadamente añadir configuraciones predeterminadas a las propiedades de conexión para evitar problemas con los perfiles de solo lectura. Sin embargo, algunos usuarios necesitan pasar configuraciones de formato (por ejemplo, para leer JSON como String) y recomendamos usar el perfil readonly=2. Lea más sobre los perfiles de solo lectura aquí.

Identificación del cliente

Existen dos formas de identificar la aplicación que originó una solicitud: establecer com.clickhouse.client.api.ClientConfigProperties#CLIENT_NAME mediante las propiedades de conexión o utilizar el método java.sql.Connection#setClientInfo(String name, String value).
showLineNumbers
showLineNumbers
Ambas formas producirán el siguiente valor de http_user_agent en el registro de consultas:
Nota: Recomendamos usar el formato app_name/version para la propiedad client_name, ya que facilita la identificación de la aplicación en el registro de consultas.

Identificación de operaciones

El controlador JDBC genera un query_id para cada operación (actualmente se incluye en las excepciones del servidor).Para establecer log_comment en una operación, utilice el método com.clickhouse.jdbc.StatementImpl#getLocalSettings. Para ello, es necesario hacer un cast de Statement o PreparedStatement a com.clickhouse.jdbc.StatementImpl primero.
showLineNumbers
Nota: este enfoque funciona para usos de sentencias en un solo hilo porque localSettings se comparte entre hilos.

Tipos de datos compatibles

El JDBC driver admite los mismos formatos de datos que el java client subyacente.

Correspondencia de tipos JDBC

La siguiente correspondencia se aplica a:
  • ResultSet#getObject(columnIndex) - el método devuelve un objeto de la clase Java correspondiente. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
  • ResultSetMetaData#getColumnType(columnIndex) - el método devuelve el tipo JDBC correspondiente. (Int8 -> java.lang.Byte, Int16 -> java.lang.Short, etc.)
Hay varias formas de cambiar la correspondencia:
  • ResultSet#getObject(columnIndex, class) - el método intentará convertir el valor al tipo class. Hay algunas limitaciones de conversión. Consulta cada sección para ver más detalles.
Tipos numéricos
  • los tipos numéricos son convertibles entre sí. Así, Int8 se puede obtener como Float64 y viceversa.:
    • rs.getObject(1, Float64.class) devolverá un valor Float64 de la columna Int8.
    • rs.getLong(1) devolverá un valor Long de la columna Int8.
    • rs.getByte(1) puede devolver un valor Byte de la columna Int16 si cabe en Byte.
  • no se recomienda la conversión de un tipo de mayor capacidad a uno de menor capacidad debido al riesgo de corrupción de datos.
  • El tipo Bool también funciona como número.
  • Todos los tipos numéricos pueden leerse como java.lang.String.
  • Almacenar Float.MAX_VALUE de Java como Float presenta un problema (https://github.com/ClickHouse/clickhouse-java/issues/809). Guardar ese mismo valor como Double lo resuelve.
Tipos de cadena
  • String solo se puede leer como java.lang.String o byte[].
  • FixedString se lee tal cual y se rellena con ceros hasta alcanzar la longitud de la columna. (Por ejemplo, FixedString(10) para 'John' se leerá como 'John\0\0\0\0\0\0\0\0\0'.)
Tipos enum
  • Enum8 y Enum16 se asignan a java.lang.String de manera predeterminada.
  • Los valores enum pueden leerse como valores numéricos mediante el método getter correspondiente o el método getObject(columnIndex, Integer.class).
  • Enum16 se mapea internamente a short y Enum8 se mapea a byte. Debe evitarse leer Enum16 como byte debido al riesgo de corrupción de datos.
  • Los valores de enum pueden establecerse como una cadena o un valor numérico en PreparedStatement.
Tipos de fecha/hora
  • Los tipos Date / Time se asignan a tipos java.sql para lograr una mejor compatibilidad con JDBC. Sin embargo, es posible obtener java.time.LocalDate, java.time.LocalDateTime y java.time.LocalTime mediante ResultSet#getObject(columnIndex, Class<T>), usando la clase correspondiente como segundo argumento.
    • rs.getObject(1, java.time.LocalDate.class) devolverá un valor java.time.LocalDate de la columna Date.
    • rs.getObject(1, java.time.LocalDateTime.class) devolverá un valor java.time.LocalDateTime de la columna DateTime.
    • rs.getObject(1, java.time.LocalTime.class) devolverá un valor java.time.LocalTime de la columna Time.
  • Date, Date32, Time, Time64 no se ven afectados por la zona horaria del servidor.
  • DateTime y DateTime64 se ven afectados por la zona horaria del servidor o de la sesión.
  • DateTime y DateTime64 se pueden recuperar como ZonedDateTime mediante getObject(colIndex, ZonedDateTime.class).
Tipos anidados
  • Array se asigna a java.sql.Array de forma predeterminada para mantener la compatibilidad con JDBC. Esto también se hace para proporcionar más información sobre el valor de array devuelto. Resulta útil para la inferencia de tipos.
  • Array implementa el método getResultSet() para devolver un java.sql.ResultSet con el mismo contenido que el array original.
  • Los tipos de colección no deberían interpretarse como java.lang.String, ya que no es una forma válida de representar los datos (p. ej., en un array no se usan comillas para los valores de cadena).
  • Map se asigna a OTHER porque el valor solo puede leerse mediante el método getObject(columnIndex, Class<T>).
    • Map no es un java.sql.Struct porque no tiene columnas con nombres.
  • Tuple se mapea a Object[] porque puede contener distintos tipos y no es válido usar List.
  • Tuple puede leerse como Array mediante el método getObject(columnIndex, Array.class). En este caso, Array#baseTypeName devolverá la definición de la columna Tuple.
Metadatos del tipo de elemento de ArrayArray.getBaseTypeName() devuelve el nombre del tipo de elemento de ClickHouse; Array.getBaseType() devuelve el código de tipo JDBC. JDBC V2 conserva las firmas de tipo completas (tipos envoltorio, parámetros de tipo) que V1 elimina.Las reglas generales de correspondencia para los arrays son:Notas sobre las reglas anteriores:
  • Los tipos de envoltorio (Nullable, LowCardinality) se conservan en getBaseTypeName(), pero getBaseType() se resuelve como el código JDBC del tipo interno.
  • Los arrays anidados se aplanan en los metadatos: getBaseTypeName() devuelve el tipo del elemento más interno que no sea un array, no el hijo inmediato.
  • Los tipos parametrizados (FixedString(N), definiciones completas de Enum/Tuple) conservan sus parámetros en getBaseTypeName().
Ejemplos:
  • En V2, getBaseTypeName() conserva la firma de tipo completa, incluidos los tipos envoltorio (Nullable, LowCardinality) y los parámetros de tipo (FixedString(8), las definiciones completas de Enum y Tuple). V1 los elimina y devuelve solo el nombre del tipo base.
  • Los arrays de Tuple usan OTHER (1111) en V2 en lugar de STRUCT (2002) porque las tuplas de ClickHouse tienen campos con nombre, algo que java.sql.Struct no admite.
  • Los arrays de UUID usan OTHER (1111) en V2, en consonancia con la asignación escalar de UUID.
  • Los valores Enum se asignan a VARCHAR: los miembros de enum se identifican por su nombre de cadena, independientemente de su codificación numérica subyacente.
Escritura de ArraysUse java.sql.Connection#createArrayOf para instanciar el objeto java.sql.Array. Este objeto está diseñado para unificar el manejo de arrays en distintas bases de datos. Se necesita una conexión para pasar la configuración al método de fábrica de Array.El método acepta dos argumentos:
  • typeName - nombre del tipo de los elementos del array. Por ejemplo, Array(Int32) -> "Int32".
  • elements - los elementos reales del array. Por ejemplo [[1, 2, 3], [4, 5, 6]] -> new Integer[][] {{1, 2, 3}, {4, 5, 6}}.
Tuple puede representarse como Object[] o como java.sql.Struct (consulte cómo escribir tuples más adelante).Ejemplo
Lectura de ArraysUse ResultSet#getArray(columnIndex) para leer un objeto Array. El objeto puede utilizarse para acceder a arrays de cualquier profundidad de anidamiento. El método Array#getResultSet() puede emplearse para leer los elementos del array de forma más uniforme como java.sql.ResultSet. Resulta útil cuando se desconoce el tipo exacto de los elementos del array.Ejemplo
Escritura de TuplesLos Tuples se mapean al objeto com.clickhouse.data.Tuple y deben escribirse como dicho objeto mediante una llamada al método setObject(columnIndex, tuple). Es posible usar el objeto java.sql.Struct para escribir tuples con mayor portabilidad.Ejemplo
Lectura de TuplesEl método getObject(columnIndex) devolverá Object[]. Los Tuples pueden leerse como java.sql.Array mediante el método getObject(columnIndex, Array.class).Ejemplo
Escritura de MapsMap solo puede escribirse como un objeto java.collections.Map porque este tipo requiere pares clave-valor (java.sql.Struct no admite pares clave-valor).Ejemplo
Lectura de mapasMap puede leerse como un objeto java.collections.Map utilizando el método getObject(columnIndex, Map.class).Ejemplo
Escritura de NestedUtilice java.sql.Connection#createStruct para instanciar el objeto java.sql.Struct. Este objeto está diseñado para unificar el manejo de estructuras anidadas en distintas bases de datos. Se necesita una conexión para pasar la configuración al método de fábrica de Struct.El método acepta dos argumentos:
  • typeName - nombre del tipo de los elementos anidados. Por ejemplo, Nested(Tuple(Int32, String)) -> "Nested(Tuple(Int32, String))".
  • elements - los elementos anidados propiamente dichos. Por ejemplo [1, 'test'] -> new Object[] {1, 'test'}.
Ejemplo
Lectura de NestedUse ResultSet#getStruct(columnIndex, StructDescriptor) para leer el objeto Nested. El objeto puede utilizarse para acceder a elementos anidados de cualquier nivel de profundidad. El método Struct#getResultSet() puede emplearse para leer elementos anidados de forma más uniforme, como java.sql.ResultSet. Resulta útil cuando el tipo exacto de los elementos anidados es desconocido.Ejemplo
Geo TypesTipos Nullable y LowCardinality
  • Nullable y LowCardinality son tipos especiales que envuelven otros tipos.
  • Nullable afecta a la forma en que se devuelven los nombres de tipo en ResultSetMetaData
Tipos especiales
  • UUID no es un tipo estándar de JDBC. Sin embargo, forma parte del JDK. De forma predeterminada, el método getObject() devuelve java.util.UUID.
  • UUID puede leerse y escribirse como String mediante el método getObject(columnIndex, String.class).
  • IPv4 e IPv6 no son tipos estándar de JDBC. Sin embargo, forman parte del JDK. De forma predeterminada, el método getObject() devuelve java.net.Inet4Address y java.net.Inet6Address.
  • IPv4 y IPv6 se pueden leer y escribir como String mediante el método getObject(columnIndex, String.class).
Tipo JSONEl tipo JSON se asigna a Map<String, Object> de forma predeterminada, donde las claves son las claves del objeto JSON y los valores son los valores del objeto JSON. Por ejemplo:
se asignará a:
Existe una opción más conveniente para leer JSON como String pasando la configuración del servidor jdbc_read_json_as_string=true a las propiedades de conexión. Esto hace que el driver devuelva los valores JSON como String y permite procesarlos con cualquier biblioteca JSON.
A partir de la versión 25.8 de ClickHouse, los números ya no se entrecomillan de forma predeterminada. Para versiones anteriores, puede deshabilitar el entrecomillado pasando la configuración del servidor a las propiedades de conexión:

Manejo de fechas, horas y zonas horarias

Lea la Guía de Date/Time, que explica los errores más comunes y la lógica del driver al gestionar valores de Date/Time y timestamps.

Creación de conexión

Suministro de credenciales y configuración

showLineNumbers

Instrucción simple

showLineNumbers

Insert

showLineNumbers

HikariCP

showLineNumbers

Más información

Para más información, consulte nuestro repositorio de GitHub y la documentación del cliente de Java.

Solución de problemas

Registro

El driver utiliza slf4j para el logging y usará la primera implementación disponible en el classpath.

Resolución de timeout de JDBC en inserts de gran volumen

Al realizar inserciones grandes en ClickHouse con tiempos de ejecución prolongados, es posible que encuentre errores de timeout de JDBC como los siguientes:
Estos errores pueden interrumpir el proceso de inserción de datos y afectar la estabilidad del sistema. Para resolver este problema, es posible que necesite ajustar algunas configuraciones de timeout en el sistema operativo del cliente.

Mac OS

En Mac OS, se pueden ajustar los siguientes parámetros para resolver el problema:
  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1

Linux

En Linux, la configuración equivalente por sí sola puede no resolver el problema. Se requieren pasos adicionales debido a las diferencias en la forma en que Linux gestiona la configuración de keep-alive de los sockets. Siga estos pasos:
  1. Ajuste los siguientes parámetros del kernel de Linux en /etc/sysctl.conf o en un archivo de configuración relacionado:
  • net.inet.tcp.keepidle: 60000
  • net.inet.tcp.keepintvl: 45000
  • net.inet.tcp.keepinit: 45000
  • net.inet.tcp.keepcnt: 8
  • net.inet.tcp.always_keepalive: 1
  • net.ipv4.tcp_keepalive_intvl: 75
  • net.ipv4.tcp_keepalive_probes: 9
  • net.ipv4.tcp_keepalive_time: 60 (Puede considerar reducir este valor desde el valor predeterminado de 300 segundos)
  1. Después de modificar los parámetros del kernel, aplique los cambios ejecutando el siguiente comando:
Tras configurar estos parámetros, debe asegurarse de que su cliente tenga habilitada la opción Keep Alive en el socket:

Guía de migración

Cambios principales

  • JDBC V2 se ha implementado para que sea más ligero y se han eliminado algunas funcionalidades.
    • El streaming de datos no es compatible con JDBC V2 porque no forma parte de la especificación de JDBC ni de Java.
  • JDBC V2 requiere una configuración explícita. No hay valores predeterminados para failover.
    • El protocolo debe especificarse en la URL. No se detecta implícitamente a partir de los números de puerto.

Cambios de configuración

Solo hay dos enums:
  • com.clickhouse.jdbc.DriverProperties - las propiedades de configuración del propio driver.
  • com.clickhouse.client.api.ClientConfigProperties - las propiedades de configuración del cliente. Los cambios en la configuración del cliente se describen en la documentación del cliente Java.
Las propiedades de conexión se procesan de la siguiente manera:
  • La URL se procesa primero para extraer las propiedades. Estas prevalecen sobre todas las demás propiedades.
  • Las propiedades del driver no se pasan al cliente.
  • Los endpoints (host, port, protocol) se extraen de la URL.
Ejemplo:

Cambios en los tipos de datos

Tipos numéricos
  • La principal diferencia es que los tipos sin signo se corresponden con tipos de Java para mejorar la portabilidad.
Tipos de cadena
  • FixedString se lee tal cual en ambas versiones. Por ejemplo, FixedString(10) para 'John' se leerá como 'John\0\0\0\0\0\0\0\0\0'.
  • Cuando se utiliza PreparedStatement#setBytes, se convierte en unhex('<hex_string>') y luego se interpreta como String.
  • Las cadenas se almacenan con codificación UTF-8.
Tipos de fecha/hora
  • Time y Time64 solo son compatibles en V2 como tipos nuevos.
  • DateTime y DateTime64 se asignan a java.sql.Timestamp para mejorar la compatibilidad con JDBC.
Tipos enumTipos anidados
  • En V2, Array se asigna a java.sql.Array de forma predeterminada para ser compatible con JDBC. Esto también se hace para proporcionar más información sobre el valor de array devuelto. Útil para la inferencia de tipos.
  • En V2, Array implementa el método getResultSet() para devolver un java.sql.ResultSet con el mismo contenido que el array original.
  • V1 usa STRUCT para Map, pero siempre devuelve un objeto java.util.Map. V2 corrige esto al mapear Map a JAVA_OBJECT.
  • V1 usa STRUCT para Tuple, pero siempre devuelve un objeto List<Object>. V2 asigna Tuple a OTHER y devuelve Object[] de forma predeterminada.
  • V2 introduce com.clickhouse.data.Tuple#Tuple para escribir tuplas. Simplifica la tarea de determinar si un valor es una tupla o un Array.
  • PreparedStatement#setBytes y ResultSet#getBytes no pueden usarse con tipos de colección. Estos métodos están diseñados para trabajar con cadenas binarias.
  • Normalmente, java.sql.Array se utiliza para escribir y leer tipos Array. El controlador JDBC ofrece compatibilidad total con ello.
  • V2 asigna Nested a Array y lo presenta como un array de tuplas.
  • V2 ofrece compatibilidad parcial con java.sql.Struct porque es muy similar al tipo Array y no admite pares clave-valor. Struct puede utilizarse para escribir valores Tuple.
Geo TypesTipos Nullable y LowCardinality
  • Nullable y LowCardinality son tipos especiales que encapsulan otros tipos.
  • No se realizan cambios en estos tipos en la V2.
Tipos especiales
  • V1 usa VARCHAR para UUID, pero siempre devuelve un objeto java.util.UUID. V2 corrige esto al mapear UUID a OTHER y devuelve un objeto java.util.UUID.
  • V1 usa VARCHAR para IPv4 e IPv6, pero siempre devuelve objetos java.net.Inet4Address y java.net.Inet6Address. V2 corrige esto asignando IPv4 e IPv6 a OTHER y devuelve objetos java.net.Inet4Address y java.net.Inet6Address.
  • Dynamic y Variant son tipos nuevos en V2. No se admiten en V1.
  • JSON se basa en el tipo Dynamic. Por ello, solo se admite en V2.
  • Los valores IPv4 e IPv6 pueden leerse como byte[] mediante el método getBytes(columnIndex). Sin embargo, se recomienda usar las clases específicas para estos tipos.
  • V2 no admite la lectura de direcciones IP como valores numéricos porque la conversión está mejor implementada en las clases InetAddress.

Cambios en los metadatos de la base de datos

  • V2 usa únicamente el término Schema para referirse a las bases de datos. El término Catalog queda reservado para usos futuros.
  • V2 devuelve false para DatabaseMetaData.supportsTransactions() y DatabaseMetaData.supportsSavepoints(). Esto cambiará en el futuro.
  • En DatabaseMetaData.getTypeInfo(), las columnas LITERAL_PREFIX y LITERAL_SUFFIX ahora devuelven null para los tipos de datos en los que no se esperan prefijos ni sufijos (por ejemplo, los tipos numéricos). En V1, estas columnas devolvían valores no nulos para esos tipos. Estas columnas deben usarse al generar consultas SQL para entrecomillar correctamente los valores literales según su tipo de dato.
Última modificación el 25 de junio de 2026