DAO - Data Access Object
Definição
Seção intitulada “Definição”Embora popularizado pelo Core J2EE Patterns, o DAO é o parente pragmático dos padrões de mapeamento de dados de Fowler (Data Mapper, Gateway). Sua intenção:
Abstrair e encapsular todo acesso à fonte de dados, gerenciando a conexão e as operações de leitura/escrita, expondo uma interface de acesso independente da tecnologia.
Problema que resolve
Seção intitulada “Problema que resolve”Sem um DAO, código SQL/JDBC se espalha pela aplicação, acoplando lógica a detalhes de persistência e prejudicando a testabilidade. O DAO centraliza esse acesso e permite trocar a implementação (JDBC → JPA, ou um banco por outro) sem afetar clientes.
Quando usar
Seção intitulada “Quando usar”- Acesso a dados orientado a CRUD por tabela/entidade.
- Camadas de dados de aplicações Transaction Script ou serviços simples.
- Quando você quer uma abstração fina e direta sobre a persistência, sem a semântica de agregados.
Trade-offs
Seção intitulada “Trade-offs”| Vantagem | Custo |
|---|---|
| Isola detalhes de persistência | Tende a espelhar tabelas, não o domínio |
| Fácil de mockar em testes | Interface CRUD “genérica” pode vazar por toda parte |
| Baixo acoplamento à tecnologia | Não impõe fronteira de agregado/consistência |
Ponto-chave: DAO vs Repository
Seção intitulada “Ponto-chave: DAO vs Repository”Esta é a distinção central da nota.
| Aspecto | DAO | Repository |
|---|---|---|
| Orientação | Tabela / linha | Coleção de Agregados |
| Linguagem | Do armazenamento (CRUD) | Do domínio (ubíqua) |
| Granularidade | Uma entidade/tabela | Raiz de agregado |
| API típica | insert, update, delete, findById |
add, findBy..., remove (semântica de coleção) |
| Consistência | Não define fronteira | Respeita a fronteira do agregado |
| Origem | Core J2EE / camada de dados | Domain-Driven Design |
graph LR
subgraph "Orientado a tabela"
S1[Serviço] --> D[ContaDao]
D --> T1[(tabela conta)]
end
subgraph "Orientado a domínio"
S2[Serviço] --> R[ContaRepository]
R --> AG[Agregado Conta + Movimentos]
AG --> T2[(persistência)]
end
Exemplo Java/Spring
Seção intitulada “Exemplo Java/Spring”public interface ContaDao { Optional<ContaRow> findById(Long id); List<ContaRow> findAll(); void insert(ContaRow conta); void update(ContaRow conta); void deleteById(Long id);}public record ContaRow(Long id, BigDecimal saldo, String status) {}
@Repositorypublic class JdbcContaDao implements ContaDao {
private final JdbcTemplate jdbc;
public JdbcContaDao(JdbcTemplate jdbc) { this.jdbc = jdbc; }
private static final RowMapper<ContaRow> MAPPER = (rs, n) -> new ContaRow(rs.getLong("id"), rs.getBigDecimal("saldo"), rs.getString("status"));
@Override public Optional<ContaRow> findById(Long id) { return jdbc.query("SELECT id, saldo, status FROM conta WHERE id = ?", MAPPER, id) .stream().findFirst(); }
@Override public List<ContaRow> findAll() { return jdbc.query("SELECT id, saldo, status FROM conta", MAPPER); }
@Override public void insert(ContaRow c) { jdbc.update("INSERT INTO conta (id, saldo, status) VALUES (?, ?, ?)", c.id(), c.saldo(), c.status()); }
@Override public void update(ContaRow c) { jdbc.update("UPDATE conta SET saldo = ?, status = ? WHERE id = ?", c.saldo(), c.status(), c.id()); }
@Override public void deleteById(Long id) { jdbc.update("DELETE FROM conta WHERE id = ?", id); }}A API é CRUD sobre linhas (ContaRow), sem comportamento nem fronteira de agregado — exatamente o que caracteriza o DAO frente a um Repository.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- DAO genérico onipresente: um
GenericDao<T>usado em todo o sistema, escondendo consultas específicas e vazando semântica CRUD para o domínio. - Chamar DAO de Repository: renomear a interface não muda a orientação a tabela; se a API é CRUD por linha, é DAO.
- Regra de negócio no DAO: acesso a dados deve ser fino; lógica pertence ao domínio/serviço.
- N+1 e falta de fronteira: sem agregado, é fácil carregar entidades relacionadas em laços.
- Vazar
ResultSet/detalhes JDBC através da interface.
Relações
Seção intitulada “Relações”- Contraste central com Repositórios (orientado a agregados/domínio).
- Parente pragmático do Gateway (especialmente Table Data Gateway).
- Usado por Transaction Script e Service Layer.
- Melhora a Testabilidade e Arquitetura via interface.
- Índice: PoEAA.
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. Qual é a diferença fundamental entre DAO e Repository?
Resposta
O DAO é orientado a tabela/linha e fala a linguagem do armazenamento (CRUD); o Repository é orientado a coleção de agregados e fala a linguagem do domínio, respeitando fronteiras de consistência.
2. Em que estilo de arquitetura o DAO é mais natural?
Resposta
Sobre um Transaction Script ou serviços simples com acesso CRUD por tabela. Sobre um Domain Model rico, prefere-se o Repository.
3. Por que um GenericDao<T> pode ser um problema?
Resposta
Porque generaliza a semântica CRUD e a espalha por todo o sistema, escondendo consultas específicas e incentivando o vazamento de detalhes de persistência e a ausência de fronteiras de agregado.
4. Renomear um DAO para Repository o torna um Repository?
Resposta
Não. O que define é a orientação: se a API continua sendo CRUD sobre linhas/tabelas, ainda é um DAO, independentemente do nome.