Skip to main content
sqlx é um kit de ferramentas SQL assíncrono, escrito inteiramente em Rust, com pool de conexões e migrations integrados. Neste guia, você cria uma tabela todos com uma migration do sqlx-cli e atende a consultas de criação, leitura, atualização e exclusão a partir de um pequeno servidor axum. Todas as conexões usam TLS com verificação de certificados completa.

Pré-requisitos

  • Rust 1.94 ou superior. Este guia foi testado com Rust 1.98.1, sqlx 0.9.0, sqlx-cli 0.9.0 e axum 0.8.9.
  • Uma conta no 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 estará 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 terminar com sslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem, e a porta é 5432. Clique em Download CA certificate. Você também pode baixá-lo depois em Settings → CA Certificate. O certificado é exclusivo da sua instância, o que permite ao driver usá-lo para confirmar que está se comunicando com o seu servidor. Este guia se conecta diretamente ao Postgres na porta 5432, tanto na aplicação quanto no sqlx-cli. Um servidor axum é um processo de longa duração, e o PgPool mantém seu próprio pool de conexões; portanto, não é necessário um segundo pooler à frente do Postgres. As migrations devem sempre usar a conexão direta. Se você executa muitas instâncias da aplicação, consulte Usar o PgBouncer.

Configure o projeto

Crie um projeto e adicione o sqlx com o driver do Postgres, o tempo de execução do Tokio e o backend TLS rustls, além do axum e de alguns crates auxiliares:
Instale o sqlx-cli com o mesmo backend TLS:
No macOS, use rustls em vez de native-tlsO ClickHouse Managed Postgres aceita apenas TLS 1.3. No macOS, o backend native-tls usa a biblioteca Secure Transport do sistema, que não oferece suporte a TLS 1.3. Um cargo install sqlx-cli sem opções adicionais usa native-tls, e todos os comandos passam a falhar com error occurred while attempting to establish a TLS connection: One or more parameters passed to a function were not valid. (ou bad protocol version). O mesmo vale para uma aplicação compilada com a feature tls-native-tls. No Linux, o native-tls usa o OpenSSL e consegue se conectar, mas carrega apenas o primeiro certificado de ca-certificate.pem. O rustls oferece suporte a TLS 1.3 em todas as plataformas e carrega todos os certificados do arquivo.
Vai adicionar a uma aplicação existente?Pule o cargo new. No seu projeto, execute os comandos cargo add e cargo install acima e prossiga para Configure a conexão. Se a aplicação usa sqlx com SQLite:
  • Remova sqlite das features do sqlx em Cargo.toml e substitua SqlitePool por PgPool.
  • Troque os placeholders ? por $1, $2 e assim por diante.
  • Reescreva suas migrations na sintaxe do Postgres, por exemplo, bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY em vez de INTEGER PRIMARY KEY AUTOINCREMENT.

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:
Crie um arquivo .env na raiz do projeto, ou atualize a DATABASE_URL no seu arquivo existente, para que ela aponte para o banco de dados guide_rust. Tanto a aplicação quanto o sqlx-cli leem a DATABASE_URL desse arquivo:
.env
O sqlx lê sslmode e sslrootcert da URL. Com verify-full, ele verifica se o certificado do servidor foi assinado pela CA da sua instância e se corresponde ao hostname. O caminho de sslrootcert é resolvido em relação ao diretório a partir do qual você executa os comandos. Mantenha o .env fora do controle de versão e, se a sua senha contiver caracteres como @, / ou #, codifique-os com percent-encoding.
Sempre defina sslmode=verify-fullSem sslmode, o sqlx usa prefer: ele criptografa a conexão, mas aceita qualquer certificado, mesmo com sslrootcert definido. Com verify-full, um certificado de CA ausente ou incorreto gera o erro UnknownIssuer, e um host que não corresponde ao certificado (por exemplo, um endereço IP) gera o erro NotValidForNameContext (certificate not valid for name no sqlx-cli). Um caminho de sslrootcert incorreto gera o erro No such file or directory.

Crie a tabela com uma migration

Crie um arquivo de migration:
Abra o novo arquivo no diretório migrations e adicione a definição da tabela:
migrations/<timestamp>_create_todos.sql
Aplique-a:
sqlx migrate run registra as migrations aplicadas na tabela _sqlx_migrations e, nas chamadas seguintes, executa apenas as novas. Faça commit do diretório migrations junto com o seu código. Se preferir aplicar as migrations na inicialização da aplicação, chame sqlx::migrate!().run(&pool).await? em main, desde que o pool use a conexão direta.

Crie a API

Substitua o src/main.rs por um pequeno servidor axum que executa uma consulta por rota. Em uma aplicação existente, crie o pool da mesma forma que em main e adicione a struct Todo, os handlers e as rotas ao seu próprio router:
src/main.rs
Os valores são sempre passados com .bind como parâmetros ($1) e nunca formatados diretamente na string SQL. Cada string SQL distinta é preparada uma única vez por conexão e mantida em um cache de instruções com capacidade para 100 instruções, que o sqlx fecha ao removê-las do cache.
Consultas verificadas em tempo de compilaçãoEste guia usa a função query_as, que verifica o SQL em tempo de execução, então o cargo build não precisa de um banco de dados. Já as macros query! e query_as! verificam o SQL e os tipos de coluna no banco de dados em tempo de compilação. Elas leem DATABASE_URL do .env durante a compilação, por isso mantenha essa variável apontando para a conexão direta. Para compilar sem um banco de dados, por exemplo em CI, execute cargo sqlx prepare, faça commit do diretório .sqlx gerado e defina SQLX_OFFLINE=true.

Executar e verificar

Inicie o servidor:
A primeira linha vem de pg_stat_ssl e confirma que a sessão está criptografada. Em um segundo terminal, crie dois todos, marque o primeiro como concluído e exclua o segundo:
Cada requisição retorna a linha afetada. A opção -w '\n' serve apenas para adicionar uma quebra de linha após cada resposta:
Abra http://localhost:3117/todos no navegador para listar as tarefas restantes:
Para ver os dados no console, abra o SQL Console na barra lateral esquerda do seu serviço, expanda guide_rust e, em seguida, public, e clique na tabela todos. A tabela _sqlx_migrations, logo ao lado, armazena o histórico de migrations. A tabela todos contém a linha restante:

Usar o PgBouncer

Para conectar a aplicação por meio do PgBouncer incluído, selecione via PgBouncer no modal Connect e use a porta 6432 na DATABASE_URL da aplicação. O mesmo certificado de CA continua válido. Por exemplo, mantenha o .env apontando para a conexão direta, usada pelo sqlx-cli, e defina a variável ao iniciar a aplicação:
Por meio do PgBouncer, pg_stat_ssl informa a conexão do próprio PgBouncer com o Postgres, por isso a verificação exibe none. A conexão da sua aplicação com o PgBouncer continua sendo verificada: um certificado de CA incorreto falha com UnknownIssuer da mesma forma. O PgBouncer é executado no modo de pooling de transações, portanto cada transação pode ser executada em uma conexão diferente com o Postgres. Com o sqlx:
  • Conectar exige .extra_float_digits(None), como em main.rs. Por padrão, o sqlx envia extra_float_digits como parâmetro de inicialização, e o PgBouncer rejeita a conexão com unsupported startup parameter: extra_float_digits. Pelo mesmo motivo, PgConnectOptions::options falha com unsupported startup parameter in options.
  • Prepared statements funcionam com as configurações padrão. O sqlx libera as instruções que remove do cache por meio de uma mensagem Close no nível do protocolo, que o PgBouncer processa, inclusive dentro de transações. Não defina statement_cache_capacity(0): isso não é necessário e, com o cache desativado, o sqlx continua preparando instruções nomeadas, mas nunca as fecha.
  • Não use .persistent(false) em consultas executadas fora de uma transação. Nesse caso, o sqlx prepara uma instrução sem nome e a executa em uma segunda ida e volta (round trip), que o PgBouncer pode encaminhar para uma conexão diferente com o Postgres. A consulta pode falhar com unnamed prepared statement does not exist ou executar silenciosamente a instrução de outro cliente e retornar resultados incorretos.
  • Configurações de sessão definidas com SET, inclusive no hook after_connect de um pool, não permanecem na sua conexão e podem vazar para outros clientes. Em vez disso, use SET LOCAL dentro de uma transação.
  • Migrations devem usar a conexão direta. O sqlx-cli e as macros query! não conseguem se conectar por meio do PgBouncer, pois sempre enviam extra_float_digits. O sqlx::migrate! adquire um advisory lock no nível da sessão (pg_advisory_lock) e, por meio do PgBouncer, a liberação pode chegar a outra conexão com o Postgres. Com isso, o bloqueio continua retido em uma conexão do pool, e as migrations seguintes, inclusive pela conexão direta, ficam travadas até que o PgBouncer feche essa conexão.

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 PgPool
  • Segurança: listas de acesso por IP e rede privada
Última modificação em 14 de outubro de 2026