Acesso a Dados em Go: database/sql como Base
Go mantém o acesso a banco de dados explícito.
Busque em todas as páginas da documentação
Go mantém o acesso a banco de dados explícito.
O pacote database/sql da biblioteca padrão define como as aplicações se comunicam com bancos de dados SQL, e drivers separados (Postgres, MySQL, SQLite e outros) implementam o protocolo real.
ORMs como GORM e auxiliares como sqlx ficam sobre essa mesma base - eles não substituem o pool, as transações ou as APIs cientes de contexto.
Noções Básicas de Banco de Dados coleta snippets executáveis; artigos irmãos cobrem pooling, transações, migrações, cache e convenções de equipe.
database/sql é uma API pequena e agnóstica de driver para pooling de conexões, consultas, transações e prepared statements. Seu código importa um driver com um import em branco e chama sql.Open.database/sql mantém você portátil entre drivers, testável com fakes e alinhado com como as pilhas HTTP e gRPC do Go propagam context.Context para chamadas de armazenamento.sql.Null* são verbosos; o comportamento do driver difere para cancelamento e cache de prepared statement; riscos N+1 se movem para camadas ORM se você não for cuidadoso.Imagine seu serviço como camadas: manipulador HTTP, serviço de domínio, repositório de armazenamento, então *sql.DB.
O manipulador analisa a requisição e passa r.Context() para baixo.
O repositório é o dono das strings SQL (ou SQL gerado) e mapeia linhas para tipos de domínio.
*sql.DB é um pool de conexões, não um único socket.
sql.Open("postgres", dsn) registra o nome do driver e retorna um handle de pool.
A primeira conexão real frequentemente aparece em Ping, Query ou Exec.
Drivers vivem em módulos separados:
import (
"database/sql"
_ "github.com/jackc/pgx/v5/stdlib" // Postgres
)O import em branco executa o init() do driver para que sql.Open possa resolver "pgx".
Trocar de bancos de dados significa trocar o import do driver e o DSN, não reescrever os tipos da aplicação se os repositórios ocultarem os detalhes do SQL.
O caminho de leitura idiomático:
func GetUser(ctx context.Context, db *sql.DB, id int64) (User, error) {
var u User
err := db.QueryRowContext(ctx,
`SELECT id, email FROM users WHERE id = $1`, id,
).Scan(&u.ID, &u.Email)
if errors.Is(err, sql.ErrNoRows) {
return User{}, ErrNotFound
}
return u, err
}QueryRowContext espera no máximo uma linha.
Scan copia os valores das colunas para variáveis Go e reporta incompatibilidades de tipo imediatamente.
Leituras de múltiplas linhas usam QueryContext, iteram rows.Next(), e sempre rows.Close().
Escritas usam ExecContext; jobs em lote podem usar transações via BeginTx.
| Camada | Responsabilidade | Pacote Típico |
|---|---|---|
| Manipulador | Autenticação, vinculação, códigos de status | chi, gin, echo |
| Serviço | Regras de negócio, orquestração | internal/order |
| Repositório | SQL, mapeamento, transações | internal/storage |
| Pool | Conexões, limites, saúde | database/sql |
| Driver | Protocolo de comunicação, cancelamento | pgx, go-sql-driver/mysql |
Frameworks (chi, gin, echo) não mudam o contrato de armazenamento: repositórios ainda aceitam ctx e *sql.DB (ou uma interface que os envolva).
Serviços google.golang.org/grpc passam o contexto RPC para métodos de repositório da mesma forma que manipuladores HTTP fazem.
Serviços de produção combinam configurações de pool com contexto por consulta:
SetMaxOpenConns limita conexões simultâneas ao banco de dados.SetMaxIdleConns mantém conexões aquecidas para tráfego intermitente.SetConnMaxLifetime rotaciona conexões atrás de balanceadores de carga.QueryContext vincula o trabalho ao desconectamento do cliente e aos deadlines do serviço.ORMs (GORM) geram SQL e gerenciam associações; sqlx adiciona helpers de scan de struct, mantendo-se próximo ao SQL bruto.
Equipes frequentemente escolhem:
| Abordagem | Força | Fraqueza | Melhor Encaixe |
|---|---|---|---|
database/sql bruto | Controle total, sem mágica | Mais boilerplate | SQL crítico para performance |
| sqlx | Scan ergonômico | Ainda esquema manual | Serviços com SQL moderado |
| GORM | Migrações, hooks, associações | Consultas ocultas, tags mágicas | APIs de administração focadas em CRUD |
| sqlc / codegen | Verificações de consulta em tempo de compilação | Pipeline de build necessário | Grandes equipes com esquemas estáveis |
Observabilidade pertence ao limite do repositório: registre o nome da consulta, latência e o deadline restante do ctx; exponha estatísticas do pool (db.Stats()) para métricas.
Reconciliadores do controller-runtime devem passar o contexto de reconciliação para chamadas de repositório para que o trabalho do banco de dados pare quando o gerenciador for desligado.
sql.Open conecta imediatamente" - Ele aloca um pool; erros frequentemente aparecem no primeiro uso. Sempre use PingContext na inicialização.*sql.DB global é um anti-padrão" - Um único pool por processo é normal; o anti-padrão é a lógica de init() oculta sem testes.sql.Rows" - Retorne tipos de domínio ou slices; mantenha Rows dentro do repositório.Prepare genericamente.Drivers se registram em init().
Sem o import, sql.Open falha com "unknown driver".
Mantenha o SQL em repositórios para que os manipuladores permaneçam finos e os testes possam simular o armazenamento.
Mapeie para um sentinela de domínio ErrNotFound.
Não vaze sql.ErrNoRows para camadas HTTP sem tradução.
Não - um *sql.DB por processo (ou por banco de dados lógico) é o padrão.
Requisições pegam conexões emprestadas do pool.
GORM moderno suporta WithContext(ctx).
Ainda verifique o SQL gerado e as configurações do pool em produção.
Use interfaces na fronteira do serviço, sqlmock, ou contêineres efêmeros para testes de integração.
Testes unitários não devem precisar de Docker para regras de negócio.
Esta seção foca em SQL via database/sql.
Armazenamentos de documentos usam diferentes SDKs de cliente com seus próprios padrões de pooling.
Cada processo de serviço possui seu pool.
Compartilhar um pool entre serviços acopla domínios de falha.
pgx oferece uma API nativa e um driver database/sql via stdlib.
A maioria das aplicações usa a camada de compatibilidade da stdlib.
Quando a mudança de esquema, associações e hooks de soft-delete dominam o tempo do desenvolvedor mais do que o ajuste de consultas.
Reavalie quando a performance se torna o gargalo.
Versões da Stack: Esta página foi escrita para Go 1.26.x (padrão Green Tea GC, go fix modernizers - verifique o patch na compilação), chi (latest - verifique na compilação), gin (latest - verifique na compilação), echo (latest - verifique na compilação), google.golang.org/grpc (latest - verifique na compilação), sigs.k8s.io/controller-runtime (latest - verifique na compilação), kubebuilder (latest - verifique na compilação), tinygo (latest - verifique os alvos de placa na compilação), wazero (latest - verifique na compilação) e golangci-lint (latest - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026