← Voltar ao blog
banco de dadosarquiteturapostgresqlbackend

Quem pode escrever no seu banco

2026-10-10

Quem pode escrever no seu banco

Alguém abre uma tabela, repara que os IDs pulam de 4.812 para 4.931 e manda mensagem no fim da tarde: sumiu registro. Nas duas horas seguintes três pessoas param o que estavam fazendo para procurar cento e dezenove linhas que, quase sempre, nunca existiram.

Vale começar pelo desmentido, porque ele economiza essas duas horas.

A documentação do PostgreSQL é explícita: o valor obtido por nextval não volta para a sequência quando a transação é abortada, e um INSERT com ON CONFLICT calcula a tupla, incluindo a chamada à sequência, antes de detectar o conflito que vai desviar o fluxo. A conclusão está escrita lá em letra seca: objetos de sequência não podem ser usados para obter sequências sem buracos.

O buraco é o preço de não colocar todo mundo que escreve numa fila atrás de um único cadeado. É projeto, não defeito.

O que a frase "o dado está corrompido" costuma querer dizer

Quando um time diz isso, raramente está falando de corrupção de página no disco. Está falando de uma linha que não combina com o resto. Um status que o app não emite. Uma data num formato que nenhuma biblioteca do projeto gera. Um registro sem o espelho que ele deveria ter em outra tabela.

E aí está a informação real, que o buraco na sequência esconde em vez de revelar.

Um id é só um contador. Ele não sabe quem escreveu. A pergunta útil não é se a numeração está contínua, e sim se aquela linha poderia ter saído do seu código. Essa pergunta tem resposta objetiva, e costuma ser respondida em dez minutos.

Todo caminho de escrita de uma aplicação madura deixa rastro além da própria linha. Um registro de auditoria. Um job na fila. Uma chave de cache invalidada. Um contador que mexeu. Um webhook disparado. Se a linha existe e o rastro não existe, ela entrou por outro lugar.

É um teste barato e quase nunca inconclusivo.

O inventário que ninguém tem

A partir daí a investigação vira uma pergunta de inventário: quem tem credencial para escrever nessa tabela?

A maioria dos times responde "a aplicação" e para. Aí alguém lembra do runner de migration. Depois da sync que alimenta o relatório. Do painel interno que um dev fez num fim de semana e que ninguém mais mantém. Do script de restore. Do processo de importação que roda uma vez por mês e tem usuário próprio no banco. Da sessão de psql que alguém abriu durante um incidente em março.

Nenhum desses é malicioso. Nenhum apareceu de surpresa. Cada um foi criado por um motivo legítimo, num dia em que resolver o problema imediato importava mais do que registrar mais um gravador no sistema.

Essa é a tensão de verdade, e ela não é técnica. Um caminho de escrita novo resolve o problema de hoje e cria uma dívida que só aparece meses depois, na forma de uma linha que o time inteiro acha que não deveria existir. Quem criou o atalho raramente é quem paga a conta.

Integridade não é propriedade do seu código. É propriedade de quantos caminhos conseguem escrever, somada às regras que o banco impõe independentemente de quem conecta.

Validação e restrição não protegem da mesma coisa

Essa distinção resolve mais discussão do que parece.

A validação que mora na aplicação existe para proteger você do usuário. Ela trata entrada ruim, mensagem de erro, formulário mal preenchido. Faz isso bem, e é onde deve estar: perto da pessoa, com contexto para explicar o que deu errado.

A restrição que mora no banco existe para proteger você de todo o resto. Dos seus scripts, dos seus colegas, do seu eu de duas da manhã resolvendo um incidente no psql. Ela não é educada e não explica nada. Ela só recusa.

Um NOT NULL, um CHECK, uma chave estrangeira e um UNIQUE valem mais do que qualquer camada de serviço, porque eles valem para todo mundo. A camada de serviço vale só para quem passa por ela.

O erro comum é tratar as duas como redundantes e escolher uma. São respostas a ameaças diferentes.

O critério

O que eu uso hoje, antes de criar qualquer acesso de escrita novo:

  • Esse gravador vai produzir os mesmos efeitos colaterais que a aplicação produz, ou ele vai gerar linhas órfãs de auditoria e de fila?
    • As regras que esse caminho precisa respeitar estão escritas no banco, ou só no código que ele não executa?
      • Se eu sumir por seis meses, alguém consegue descobrir que esse caminho existe sem abrir uma conexão e listar permissão por permissão?

      Se as três respostas não forem confortáveis, o caminho até pode nascer. Só não nasce silencioso: entra na documentação do schema junto com o motivo.

      Quando o oposto é a resposta certa

      Vale dizer com todas as letras, porque o conselho vira dogma rápido.

      Caminho de escrita secundário é frequentemente a decisão correta. Carga em massa que passa pela aplicação é lenta a ponto de inviabilizar o trabalho. Replicação, por definição, escreve sem passar pelo seu código. Migration precisa fazer o que o modelo de domínio proíbe, porque é exatamente isso que ela está lá para fazer. Pipeline analítico escrevendo em tabela própria não ameaça nada.

      Forçar tudo isso por uma única porta não melhora integridade. Cria um gargalo e, pior, incentiva a criação do atalho não documentado que você estava tentando evitar.

      A diferença nunca foi o número de gravadores. É se eles foram desenhados ou descobertos. Um gravador previsto tem dono, restrição no banco e uma linha na documentação. Um gravador descoberto tem só uma linha estranha numa tabela e um time de três pessoas procurando registro que nunca existiu.

      Há também o caso em que o buraco importa de verdade: numeração fiscal, contrato, qualquer sequência que precisa ser contínua por obrigação externa. Aí a resposta não é consertar a sequência do banco. É não usar sequência do banco para isso, e sim uma tabela de controle com a transação segurando o número. Custa concorrência, e nesse caso o custo é o ponto.


      Se alguém perguntasse agora quantos caminhos diferentes conseguem gravar na sua tabela mais importante, você responderia de cabeça ou precisaria abrir uma conexão para descobrir?

      📩 Vamos conversar