Skip to main content
pgx é o driver PostgreSQL mais usado em Go, e pgxpool é o seu pool de conexões. Neste guia, você vai conectar um serviço Go ao ClickHouse Managed Postgres por TLS verificado, criar uma tabela todos com uma migração do golang-migrate e atender a requisições de criação, leitura, atualização e exclusão em um servidor net/http.

Pré-requisitos

  • Go 1.25 ou superior. Este guia foi testado com Go 1.27.1, pgx 5.11.0 e golang-migrate 4.20.1.
  • Uma conta do ClickHouse Cloud
  • psql, para criar o banco de dados. Você também pode executar a instrução CREATE DATABASE no SQL Console.

Crie um serviço ClickHouse Managed Postgres

No console do ClickHouse Cloud, clique em New service e selecione Postgres. A instância fica pronta em poucos minutos. Para um passo a passo completo, consulte o guia de início rápido.

Obtenha os detalhes de conexão

Clique em Connect na barra lateral esquerda do seu serviço. Mantenha Directly selecionado e ative Use SSL. A URL de conexão na aba url passa a usar a porta 5432 e termina com sslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem. Clique em Download CA certificate. Você também pode baixá-lo mais tarde em Settings → CA Certificate. O certificado é exclusivo da sua instância, o que permite que o pgx o use para verificar se está se comunicando com o seu servidor. Este guia se conecta diretamente ao Postgres na porta 5432, tanto para as migrações quanto para a aplicação. Um serviço em Go é um processo de longa duração, e o pgxpool já mantém um pool de conexões dentro dele, portanto não é necessário um segundo pooler. Se você executar muitas instâncias do serviço e precisar de mais conexões de cliente do que o Postgres permite, use o PgBouncer incluído (via PgBouncer, porta 6432) na aplicação; consulte Usar o PgBouncer, que exige uma configuração de conexão adicional.

Configure o projeto

Crie um módulo Go, adicione o pgx e instale a CLI migrate com o driver do pgx:
A flag -tags 'pgx5' compila a CLI migrate com o driver pgx v5, que usa o esquema de URL pgx5://. O go install coloca o binary em $GOBIN, ou em $(go env GOPATH)/bin se GOBIN não estiver definido; portanto, verifique se esse diretório está no seu PATH.
Vai adicionar a uma aplicação existente?Ignore o mkdir e o go mod init. No seu módulo, execute go get github.com/jackc/pgx/v5 e o comando go install acima e, em seguida, siga para Configurar a conexão. Se o seu código usa database/sql, stdlib.OpenDBFromPool encapsula o mesmo pool como um *sql.DB, o que permite migrar as consultas existentes aos poucos; substitua os placeholders ? por $1, $2 e assim por diante.

Configure a conexão

Mova o certificado da CA que você baixou para o diretório do projeto e renomeie-o para ca-certificate.pem. Crie um banco de dados para a aplicação. Substitua <PASSWORD> e o host pelos valores exibidos no modal Connect:
Defina duas variáveis de ambiente no seu shell. Ambas apontam para o mesmo banco de dados guide_go e diferem apenas no esquema da URL: a aplicação lê DATABASE_URL, enquanto a CLI do migrate usa MIGRATE_URL:
O pgx interpreta a URL da mesma forma que a libpq. Com sslmode=verify-full, ele carrega o arquivo da CA indicado em sslrootcert e verifica tanto a cadeia de certificados quanto o hostname, então você não precisa escrever nenhum código de TLS. O caminho em sslrootcert é resolvido em relação ao diretório a partir do qual você executa os comandos. Se a sua senha contiver caracteres especiais, como @, / ou #, aplique a codificação de URL a eles.
Sempre defina sslmode=verify-fullSem sslmode, o pgx usa prefer, que não verifica o certificado do servidor, mesmo que você defina sslrootcert. Com sslmode=verify-full e um arquivo de CA incorreto, o pgx falha com x509: certificate signed by unknown authority e, se o arquivo não existir, falha com unable to read CA file. Se você se conectar pelo endereço IP em vez do hostname, a conexão falha com x509: cannot validate certificate for <IP> because it doesn't contain any IP SANs.

Crie o schema com uma migração

Crie os arquivos de migração:
Preencha a migração up:
migrations/000001_create_todos.up.sql
E a migração down, que a desfaz:
migrations/000001_create_todos.down.sql
Aplique a migração:
O migrate registra a versão atual na tabela schema_migrations e, nas execuções seguintes, aplica apenas as migrações mais recentes. Faça commit do diretório migrations junto com o seu código.
Sempre execute o migrate pela conexão direta (porta 5432). Durante a execução, ele mantém um bloqueio consultivo (advisory lock) no nível da sessão, para que duas implantações não executem a migração ao mesmo tempo. Pelo PgBouncer, o bloqueio e o desbloqueio podem acontecer em conexões Postgres diferentes. Com isso, o bloqueio permanece ativo, e as execuções posteriores do migrate travam ou falham com timeout: can't acquire database lock.

Consultar o banco de dados

Crie o arquivo db.go. Ele cria o pool a partir de DATABASE_URL e verifica a conexão na inicialização, consultando o Postgres sobre qual versão do TLS a sessão está usando:
db.go
Crie o arquivo todos.go com os handlers HTTP. Cada handler executa uma única consulta parametrizada no pool, e pgx.CollectRows e pgx.CollectExactlyOneRow mapeiam as linhas para a struct Todo com base no nome da coluna:
todos.go
Passar valores como argumentos ($1), em vez de formatá-los na string SQL, evita injeção de SQL. O pgx os envia separadamente do texto da consulta. Não é preciso verificar separadamente o erro de pool.Query: pgx.CollectRows e pgx.CollectExactlyOneRow já o retornam. Crie o arquivo main.go. Ele cria um único pool para todo o processo, atende às rotas na porta 3114 e fecha o pool ao pressionar Ctrl+C. Em uma aplicação existente, chame newPool uma única vez na inicialização e, em vez disso, registerTodoRoutes no seu http.ServeMux:
main.go

Executar e verificar

Adicione as dependências restantes do pgxpool ao go.mod e ao go.sum e, em seguida, inicie o servidor:
TLSv1.3 vem de pg_stat_ssl no servidor, o que confirma que a sessão está criptografada. Se você apontar sslrootcert para qualquer outro certificado, o servidor não inicia e registra x509: certificate signed by unknown authority nos logs, o que mostra que o certificado é realmente verificado. Em um segundo terminal, crie duas tarefas, marque a primeira como concluída e exclua a segunda:
A requisição PATCH retorna a linha atualizada:
Abra http://localhost:3114/todos no navegador para listar as tarefas restantes. O pgx retorna valores timestamptz no fuso horário local. A resposta será semelhante a esta:
Pare o servidor com Ctrl+C. Ele registra Shutting down no log e fecha o pool. Para ver os dados no console, abra o SQL Console na barra lateral esquerda do seu serviço, expanda guide_go e depois public e clique na tabela todos. A tabela schema_migrations, logo ao lado, armazena a versão da migração. A tabela todos contém a linha restante:

Use o PgBouncer

Para enviar as consultas do aplicativo pelo PgBouncer incluído, selecione via PgBouncer no modal Connect, altere a porta em DATABASE_URL para 6432 e adicione default_query_exec_mode=cache_describe. Mantenha a MIGRATE_URL na porta 5432:
O pgx lê default_query_exec_mode da URL e não o envia ao servidor. Nenhuma alteração de código é necessária, e o mesmo certificado CA continua funcionando. O log de inicialização agora mostra TLS: none, porque pg_stat_ssl reporta a conexão do próprio PgBouncer com o Postgres. A conexão da sua aplicação com o PgBouncer continua sendo verificada: um certificado CA incorreto falha da mesma forma.
Não use o modo de consulta padrão do pgx com o PgBouncerPor padrão, o pgx prepara cada consulta como uma instrução nomeada uma vez por conexão e reutiliza os tipos de coluna recebidos. O PgBouncer prepara essas instruções na conexão do Postgres que estiver executando a consulta e as compartilha entre clientes. Depois que uma migração altera o tipo de uma coluna, ou adiciona uma coluna a uma tabela consultada com SELECT *, as consultas via PgBouncer podem continuar falhando com cached plan must not change result type, mesmo após reiniciar a aplicação, ou, a partir do pgx 5.9, retornar valores incorretos sem nenhum erro. Por exemplo, uma coluna bigint alterada para double precision retorna os bits brutos do valor float64, como 4631178160564600832 para 42.5.O cache_describe armazena em cache apenas os tipos de parâmetro e de coluna, executa cada consulta como uma instrução sem nome em uma única ida e volta e decodifica as linhas usando os tipos de coluna que o servidor retorna junto com cada resultado; por isso, não é afetado. O exec também funciona. Não use describe_exec com o PgBouncer: ele divide cada consulta em duas idas e voltas, que o PgBouncer pode encaminhar para conexões diferentes do Postgres. Não é necessário definir statement_cache_capacity=0.
O PgBouncer opera em modo de pooling de transações, portanto cada transação pode ser executada em uma conexão diferente do Postgres:
  • Transações com pool.Begin ou pgx.BeginFunc funcionam normalmente.
  • Configurações de sessão definidas com SET não permanecem na sua conexão e podem vazar para outros clientes. Use SET LOCAL dentro de uma transação. O PgBouncer também rejeita search_path na URL de conexão com o erro unsupported startup parameter: search_path; em vez disso, qualifique os nomes de tabela com o schema.
  • PREPARE e EXECUTE em nível de SQL, LISTEN e bloqueios consultivos de sessão não funcionam.

Próximos passos

  • Conexão: strings de conexão, PgBouncer e TLS
  • Configurações: parâmetros do Postgres e do PgBouncer, como max_connections
  • Réplicas de leitura: envie consultas read-only para uma réplica usando um segundo pgxpool.Pool
  • Segurança: listas de acesso por IP e rede privada
Última modificação em 14 de outubro de 2026