Pular para conteúdo

Persistência e Transações

A persistência mapeia o estado da aplicação para armazenamento durável. Um ORM remove código repetitivo de mapeamento, mas não elimina SQL, transações, índices nem custos de consulta.

Limite da transação

Posicione uma transação ao redor de uma operação coesa da aplicação, normalmente em um método de serviço.

@Service
final class LendingService {
    private final BookRepository books;

    LendingService(BookRepository books) {
        this.books = books;
    }

    @Transactional
    public void markUnavailable(UUID bookId) {
        Book book = books.findById(bookId)
                .orElseThrow(() -> new BookNotFoundException(bookId));
        book.markUnavailable();
    }
}

Transações declarativas imperativas normalmente são baseadas em proxies e vinculadas à thread. Uma chamada dentro do mesmo objeto pode contornar o advice do proxy, e iniciar threads não relacionadas não propaga a transação automaticamente. As regras padrão de rollback dependem da versão e da configuração; declare explicitamente a política desejada quando exceções verificadas forem relevantes.

Projeto de entidades

  • defina identidade e igualdade deliberadamente;
  • proteja invariantes com métodos, não setters públicos;
  • evite identificadores mutáveis gerados na igualdade hash antes da persistência;
  • use versionamento otimista quando atualizações concorrentes precisarem detectar conflitos;
  • mantenha a serialização HTTP separada da navegação da persistência.

Comportamento das consultas

O problema N+1 ocorre quando carregar uma coleção de pais dispara uma consulta adicional por pai para os dados relacionados. Resolva-o por caso de uso com fetch joins, entity graphs, projeções, processamento em lotes ou consultas explícitas — carregamento eager generalizado pode criar outros problemas de desempenho e cardinalidade. O guia de processamento tardio e imediato explica os limites de avaliação e do ciclo de vida dos recursos.

A paginação deve incluir uma ordenação determinística. Buscar uma tabela inteira e depois paginar em memória não é paginação no banco de dados. Inspecione o SQL gerado e os planos de consulta.

Chamadas externas

Evite manter uma transação de banco de dados aberta durante chamadas de rede lentas. Uma transação do banco não pode abranger atomicamente um serviço remoto comum. Para fluxos entre sistemas, estude idempotência, outbox transacional, sagas e reconciliação.

Consulte a documentação de transações declarativas do Spring.