Skip to main content
pgx es el controlador de PostgreSQL más utilizado en Go, y pgxpool es su grupo de conexiones. En esta guía, conectará un servicio de Go a ClickHouse Managed Postgres mediante TLS verificado, creará una tabla todos con una migración de golang-migrate y atenderá solicitudes de creación, lectura, actualización y eliminación desde un servidor net/http.

Requisitos previos

  • Go 1.25 o una versión posterior. Esta guía se probó con Go 1.27.1, pgx 5.11.0 y golang-migrate 4.20.1.
  • Una cuenta de ClickHouse Cloud
  • psql, para crear la base de datos. También puede ejecutar la sentencia CREATE DATABASE en la consola SQL.

Crear un servicio de ClickHouse Managed Postgres

En la consola de ClickHouse Cloud, haga clic en New service y seleccione Postgres. La instancia estará lista en unos minutos. Consulte la guía de inicio rápido para ver el proceso paso a paso.

Obtén los detalles de conexión

Haz clic en Conectar en la barra lateral izquierda de tu servicio. Deja seleccionada la opción Directly y activa Use SSL. La URL de conexión de la pestaña url ahora usa el puerto 5432 y termina en sslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem. Haz clic en Download CA certificate. También puedes descargarlo más adelante desde Settings → CA Certificate. El certificado es exclusivo de tu instancia, de modo que pgx puede usarlo para verificar que se está comunicando con tu servidor. Esta guía se conecta directamente a Postgres en el puerto 5432, tanto para las migraciones como para la aplicación. Un servicio en Go es un proceso de larga duración y pgxpool ya mantiene un grupo de conexiones dentro de él, así que no hace falta un segundo agrupador de conexiones. Si ejecutas muchas instancias del servicio y necesitas más conexiones de cliente de las que admite Postgres, usa el PgBouncer incluido (via PgBouncer, puerto 6432) para la aplicación; consulta Usar PgBouncer, que requiere un ajuste de conexión adicional.

Configurar el proyecto

Cree un módulo de Go, añada pgx e instale la CLI migrate con el controlador pgx:
El indicador -tags 'pgx5' compila la CLI migrate con su controlador pgx v5, que utiliza el esquema de URL pgx5://. go install coloca el binary en $GOBIN, o en $(go env GOPATH)/bin si GOBIN no está definido, así que asegúrese de que ese directorio esté incluido en su PATH.
¿Lo va a añadir a una aplicación existente?Omita mkdir y go mod init. En su módulo, ejecute go get github.com/jackc/pgx/v5 y el comando go install anterior, y después continúe con Configurar la conexión. Si su código utiliza database/sql, stdlib.OpenDBFromPool encapsula el mismo grupo como un *sql.DB, lo que le permite migrar las consultas existentes de forma gradual; sustituya los marcadores de posición ? por $1, $2, etc.

Configurar la conexión

Mueva el certificado de CA que descargó al directorio del proyecto y cámbiele el nombre a ca-certificate.pem. Cree una base de datos para la aplicación. Reemplace <PASSWORD> y el host por los valores que aparecen en el cuadro modal Conectar:
Defina dos variables de entorno en su shell. Ambas apuntan a la misma base de datos guide_go y solo se diferencian en el esquema de URL: la aplicación lee DATABASE_URL y la CLI de migrate utiliza MIGRATE_URL:
pgx analiza la URL del mismo modo que libpq. Con sslmode=verify-full, carga el archivo de la CA desde sslrootcert y comprueba tanto la cadena de certificados como el nombre del host, así que no necesita escribir código TLS. La ruta de sslrootcert se resuelve en relación con el directorio desde el que ejecuta los comandos. Si su contraseña contiene caracteres especiales como @, / o #, aplíqueles codificación URL.
Establezca siempre sslmode=verify-fullSi no se especifica sslmode, pgx usa prefer, que no verifica el certificado del servidor, aunque haya configurado sslrootcert. Con sslmode=verify-full y un archivo de CA incorrecto, pgx falla con x509: certificate signed by unknown authority, y si el archivo no existe, falla con unable to read CA file. Si se conecta mediante la dirección IP en lugar del nombre del host, falla con x509: cannot validate certificate for <IP> because it doesn't contain any IP SANs.

Crear el esquema mediante una migración

Cree los archivos de migración:
Completa la migración up:
migrations/000001_create_todos.up.sql
Y la migración down, que la revierte:
migrations/000001_create_todos.down.sql
Aplica la migración:
migrate registra la versión actual en la tabla schema_migrations y, en ejecuciones posteriores, solo aplica las migraciones más recientes. Haga commit del directorio migrations junto con su código.
Ejecute siempre migrate a través de la conexión directa (puerto 5432). Mientras se ejecuta, mantiene un bloqueo consultivo a nivel de sesión para impedir que dos implementaciones migren al mismo tiempo. A través de PgBouncer, el bloqueo y el desbloqueo pueden ejecutarse en conexiones de Postgres distintas: el bloqueo no se libera, y las ejecuciones posteriores de migrate se quedan colgadas o fallan con timeout: can't acquire database lock.

Consultar la base de datos

Cree db.go. Este archivo crea el grupo de conexiones a partir de DATABASE_URL y comprueba la conexión al inicio preguntando a Postgres qué versión de TLS utiliza la sesión:
db.go
Cree todos.go con los handlers HTTP. Cada handler ejecuta una única consulta parametrizada sobre el grupo, y pgx.CollectRows y pgx.CollectExactlyOneRow vuelcan las filas en la estructura Todo según el nombre de columna:
todos.go
Pasar los valores como argumentos ($1) en lugar de formatearlos dentro de la cadena SQL evita la inyección de SQL, ya que pgx los envía por separado del texto de la consulta. No hace falta comprobar por separado el error de pool.Query: pgx.CollectRows y pgx.CollectExactlyOneRow ya lo devuelven. Cree main.go. Este archivo crea un único grupo de conexiones para todo el proceso, sirve las rutas en el puerto 3114 y cierra el grupo al pulsar Ctrl+C. Si se trata de una aplicación existente, llame en su lugar a newPool una sola vez durante el inicio y registre las rutas con registerTodoRoutes en su http.ServeMux:
main.go

Ejecutar y verificar

Agregue las dependencias restantes de pgxpool a go.mod y go.sum y, después, inicie el servidor:
TLSv1.3 proviene de pg_stat_ssl en el servidor, lo que confirma que la sesión está cifrada. Si apunta sslrootcert a cualquier otro certificado, el servidor no se inicia y registra en el log x509: certificate signed by unknown authority, lo que demuestra que el certificado realmente se verifica. En una segunda terminal, cree dos tareas, marque la primera como completada y elimine la segunda:
La solicitud PATCH devuelve la fila actualizada:
Abra http://localhost:3114/todos en su navegador para ver la lista de tareas pendientes. pgx devuelve los valores timestamptz en su zona horaria local. La respuesta tiene este aspecto:
Detenga el servidor con Ctrl+C. Se registra Shutting down en el log y se cierra el grupo. Para ver los datos en la consola, abra consola SQL en la barra lateral izquierda de su servicio, expanda guide_go y luego public, y haga clic en la tabla todos. La tabla schema_migrations, situada junto a ella, almacena la versión de la migración. La tabla todos contiene la fila restante:

Usar PgBouncer

Para enviar las consultas de la aplicación a través del PgBouncer incluido, seleccione via PgBouncer en el modal Conectar, cambie el puerto de DATABASE_URL a 6432 y añada default_query_exec_mode=cache_describe. Mantenga MIGRATE_URL en el puerto 5432:
pgx lee default_query_exec_mode de la URL y no lo envía al servidor. No es necesario modificar el código, y el mismo certificado de CA sigue funcionando. El registro de inicio ahora muestra TLS: none, porque pg_stat_ssl informa sobre la conexión propia de PgBouncer con Postgres. La conexión de su aplicación con PgBouncer sigue verificándose: un certificado de CA incorrecto falla de la misma forma.
No utilice el modo de consulta predeterminado de pgx a través de PgBouncerDe forma predeterminada, pgx prepara cada consulta como una sentencia con nombre una vez por conexión y reutiliza los tipos de columna que recibió. PgBouncer prepara estas sentencias en la conexión de Postgres que ejecute la consulta, sea cual sea, y las comparte entre clientes. Si una migración cambia el tipo de una columna o añade una columna a una tabla consultada con SELECT *, las consultas a través de PgBouncer pueden seguir fallando con cached plan must not change result type, incluso después de reiniciar la aplicación, o bien, con pgx 5.9 y versiones posteriores, devolver valores incorrectos sin ningún error. Por ejemplo, una columna bigint cambiada a double precision se devuelve como los bits sin procesar del valor float64, como 4631178160564600832 para 42.5.cache_describe almacena en caché únicamente los tipos de parámetros y de columnas, ejecuta cada consulta como una sentencia sin nombre en un solo viaje de ida y vuelta y decodifica las filas con los tipos de columna que el servidor devuelve con cada resultado, por lo que no se ve afectado. exec también funciona. No utilice describe_exec a través de PgBouncer: divide cada consulta en dos viajes de ida y vuelta, que PgBouncer puede enviar a conexiones de Postgres distintas. No necesita statement_cache_capacity=0.
PgBouncer se ejecuta en modo de agrupación de transacciones, por lo que cada transacción puede ejecutarse en una conexión de Postgres diferente:
  • Las transacciones con pool.Begin o pgx.BeginFunc funcionan con normalidad.
  • La configuración de sesión establecida con SET no se mantiene en su conexión y puede filtrarse a otros clientes. Utilice en su lugar SET LOCAL dentro de una transacción. PgBouncer también rechaza search_path en la URL de conexión con unsupported startup parameter: search_path; en su lugar, califique los nombres de tabla con el esquema.
  • PREPARE y EXECUTE a nivel de SQL, LISTEN y los bloqueos consultivos de sesión no funcionan.

Próximos pasos

  • Conexión: cadenas de conexión, PgBouncer y TLS
  • Configuración: parámetros de Postgres y PgBouncer, como max_connections
  • Réplicas de lectura: envíe consultas de solo lectura a una réplica mediante un segundo pgxpool.Pool
  • Seguridad: listas de acceso por IP y redes privadas
Última modificación el 14 de octubre de 2026