-
Lazy loading ?
-
Cache ?
-
Herança ?
-
Não ter que fazer os selects na mão ?
-
Referencia cruzada ?
Por que usar Hibernate é melhor do que DAO + JDBC?
43 Respostas
E desde quando usar Hibernate impede você de usar DAO?
O correto não seria perguntar “Porque usar Hibernate é melhor do que JDBC?”?
E desde quando usar Hibernate impede você de usar DAO?O correto não seria perguntar “Porque usar Hibernate é melhor do que JDBC?”?
exatamente o que eu ia falar
uso um DAO para esconder a tecnologia de acesso a dados, o resto do meu sistema não tem que saber se eu uso JDBC ou Hibernate, a unica coisa que entra e sai destes daos são objetos do dominio da aplicação, e de vez em quando uma exceção de acesso a dados (estas o spring mascara pra mim, e faz com que também seja transparente a tecnologia que estou trabalhando
) 
Eh.
Maurício te pegou!
Sergio,
Eu tenho um certo domínio de JDBC. Mas acho trabalhoso demais.
O Hibernate tem uma proposta legal de mapeamento O/R. E por isso eu ando estudando essa porra!!! size=9[/size]
Mas ambos nao usam JDBC?
:roll:
Mas ambos nao usam JDBC?:roll:
Sim, ambos usam.
Quando citaram usar JDBC referiam-se em utilizar a API diretamente invéz de utilizando um Frame Work de persistência o qual habistrai ela.
Sim, vc pode usar DAO com Hibernate. Verdade.
A pergunta então é porque DAO + HIBERNATE ou HIBERNATE puro é melhor do que DAO + JDBC.
PS: Mudei o título do tópico !
Agora sim! 
O que o Hibernate tem a oferecer que é melhor que DAO+JDBC.
Achei um tutorial (tambem fiquei curioso e fui atras) falando dos propositos
do hibernate acho que isso da uma esclarecida em porque usar hibernate é legal…
:arrow: http://www.laliluna.de/what-is-hibernate.html
Até… :thumbup:
[s]
Dao não serve exatamente pra isso ?
Depois que vc tem o trabalho inicial de fazer o DAO, vc pode usá-lo exatamente como vc usa a session do hibernate.
Acho que aqui que está o ponto importante. Funções avançadas.
Caches podem se tornar complicados, principalmente se vc tem concorrencia acessando o cache, transações, timeout, etc. Mas eu diria que em 80% dos casos um cache para evitar que o seu DAO vá ao banco de dados não é nenhum bicho de sete cabeças. Um artigo muito bom sobre isso foi comentado aqui: http://www.guj.com.br/posts/list/26589.java
As outras featues avançadas como transaction, lazy loading, não são nem um pouco avançadas e podem ser obtidas facilmente.
Conclusão (provavelmente errada): Hibernate te ajuda no cache e te economiza ter que escrever os selects dos seus beans.
Sei lá, eu consigo escrever rapidamente os DAOs dos meus beans usando JDBC. Isso pq já estou acostumado com isso. Por isso que não usei Hibernate no mybooks do Mentawai. E não me arrependi até agora…
Por isso tb que o mentawai tem um pacote não documentado chamado org.mentawai.cache, com vários tipos de cache… 
Implemente Lazy Loading e queries OO (principalmente polimórficas) facilmente.
LazyLoading de verdade. Tipo todas as ligações telefônicas de uma empresa no ano associadas ao objeto empresa.
Implementar um cache é a maior perda de tempo que existe. Eu diria que em 90% das vezes que tive que depurar bugs relacionados a OOM em uma aplicação Java era porque alguém achou que caching era algo trivial.
Fora isso que um software de cache só é viavel de ser desenvolvido se ele for não-transacional, não-coerente e somente leitura.
Caching eu acho que é um das maiores qualidade do hibernate, tenho usado com resultados incríveis cache de entidades, colections e queries.
Figura !!!

Empresa Oi tem 3 bilhões de ligação.
Nem vc nem o Hibernate vão poder carregar todas essas ligações numa lista. Seja Lazy Loading, ou seja o que for.
Isso é um problema de tunning de banco de dados, já que terá que haver um belo índice que te permita pegar subsets dessa mundo sem distruir a máquina e/ou parar o banco.
No Oracle tu teria que fazer algo assim:
select * from (select id, from, to, date, duration from calls
where id_empresa = 2 and date <= sysdate - 10 order by date) where rownum <= 1000;
Daí na próxima paginação tu faria assim:
select * from (select id, from, to, date, duration from calls
where id_empresa = 2 and date <= sysdate - 10 and date > ULTIMA DATA order by date) where rownum <= 1000;
Tu vai ter que fazer isso na mão para ir pegando de 1000 em 1000.
Como o Hibernate resolve isso ??? Provavelmente em estado padrão, sem maiories configurações, na primeira chamada a getCalls() ele vai tentar puxar tudo do banco e morrer…
hehehehehehe (se não for isso que acontece me perdoem a piadinha…)
Isso é mais uma questão de banco de dados do que de framework de persistencia !!!
Lazy loading não é taao dificil assim shoes, o que eu acho zuado é implementar eager loading, decodificar um resultset com alguns inner e outer join é muito massante.
O que é eager loading ???
Qualquer inner join e outer join é pentelho de se fazer. Seja na hora de construir a query seja na hora de pegar os resultados.
Se o Hibernate faz isso automático pra vc então realmente é uma vantagem… o problema são os efeitos colaterais:
geralmente para inner e outer joins saber usar o índice certo é muito importante. Se vc faz isso na mão vc pode facilmente melhorar sua query, forçando o uso de um índice ou outro, etc. Se tu deixa o hibernate fazer isso, então vc ficou na mão do hibernate e/ou terá que partir para configurações avançadas do bicho e/ou comprar o Hibernate bible e/ou contratar do Gavin para te ajudar. (claro que exagerei um pouco, mas o meu medo é esse…)
O que é eager loading ???
Qualquer inner join e outer join é pentelho de se fazer. Seja na hora de construir a query seja na hora de pegar os resultados.
Se o Hibernate faz isso automático pra vc então realmente é uma vantagem… o problema são os efeitos colaterais:
geralmente para inner e outer joins saber usar o índice certo é muito importante. Se vc faz isso na mão vc pode facilmente melhorar sua query, forçando o uso de um índice ou outro, etc. Se tu deixa o hibernate fazer isso, então vc ficou na mão do hibernate e/ou terá que partir para configurações avançadas do bicho e/ou comprar o Hibernate bible e/ou contratar do Gavin para te ajudar. (claro que exagerei um pouco, mas o meu medo é esse…)
Eager loading é o contrario de lazy loading. E só é necessario se preocupar com indicar os índices nas queries se o teu banco de dados for mongoloide e gerar planos muito ruins. DBAs acefalos também vale. Até hoje as únicas vezes que ví precisarem colocar hints de índices nas queries foi quando o modelo de dados era estrupiado além do imaginavel.
Na minha opiniao, implementação bem rápida de operações CRUD, lazy loading sem macumba e cache fácil são as maiores vantagens (e mais genericas) do Hibernate.
Verdade, já que o meu caso está no extremo oposto. Muito campos, muitos índices, muito peso no banco na hora de fazer as queries. Solução encontrada: replicação de banco em bases read-only de 10 em 10 minutos, ou algo assim que o DBA inventou. Não me lembro. (Isso era a busca do ParPerfeito e o cupido, isto é, pega esses 10 milhões de usuários e me diz quem combina comigo…)
Bom, essa discussão não vai ter fim. O Hibernate é soda, mas eu não sei usar direito e não tenho saco para aprender, principalmente se estiver na secura de terminar logo um projeto.
Alguma alma caridosa (vai ser difícil), poderia migrar o mybooks para Hibernate. Só para se ter um comparativo mais prático entre uma coisa e outra. O mybooks é simples mais tem seus inner joins, e espaço para um cachezinho na busca por livros / usuários…
Eu tou com uma aplicação aqui que gera 3 milhões de consultas em 40minutos, isso de uma máquina apenas, com hibernade reduzi isso para algo em torno de 200mil, e agora ela faz o que foi prometido.
Por causa do cache ? No início eu já falava que o cache do Hibernate deve ser o principal motivo para usá-lo…
:
No Oracle tu teria que fazer algo assim:select * from (select id, from, to, date, duration from calls where id_empresa = 2 and date <= sysdate - 10 order by date) where rownum <= 1000;Daí na próxima paginação tu faria assim:
select * from (select id, from, to, date, duration from calls where id_empresa = 2 and date <= sysdate - 10 and date > ULTIMA DATA order by date) where rownum <= 1000;Tu vai ter que fazer isso na mão para ir pegando de 1000 em 1000.
Como o Hibernate resolve isso ??? Provavelmente em estado padrão, sem maiories configurações, na primeira chamada a getCalls() ele vai tentar puxar tudo do banco e morrer…
1º:
s.createCriteria(Call.class)
.add(Restrictions.eq("empresa.id", 2))
.add(Restrictions.lt("data", new Date())
.setMaxResults(1000)
.list();
Então:
s.createCriteria(Call.class)
.add(Restrictions.eq("empresa.id", 2))
.add(Restrictions.lt("data", new Date())
setFirstResult(1001)
.setMaxResults(1000)
.list();
Okay.
Verdade, já que o meu caso está no extremo oposto. Muito campos, muitos índices, muito peso no banco na hora de fazer as queries. Solução encontrada: replicação de banco em bases read-only de 10 em 10 minutos, ou algo assim que o DBA inventou. Não me lembro. (Isso era a busca do ParPerfeito e o cupido, isto é, pega esses 10 milhões de usuários e me diz quem combina comigo…)Bom, essa discussão não vai ter fim. O Hibernate é soda, mas eu não sei usar direito e não tenho saco para aprender, principalmente se estiver na secura de terminar logo um projeto.
Alguma alma caridosa (vai ser difícil), poderia migrar o mybooks para Hibernate. Só para se ter um comparativo mais prático entre uma coisa e outra. O mybooks é simples mais tem seus inner joins, e espaço para um cachezinho na busca por livros / usuários…
Concordo que Hibernate é chato de aprender, bem mais que JDBC. Se entregar o resultado for o mais importante, por espaço com ele.
Valeu Peleteiro… Já gostei do que vi…
Pena que tu esqueceu do order by.
Me responde também se o Hibernate primeiro ordena para depois limitar (SQLServer) ou primeiro limita para depois ordenar (Oracle).
Isso vai fazer toda a diferença. Isso vai automático de acordo com o banco que está por trás ??? Se for maravilha…
Me responde também se o Hibernate primeiro ordena para depois limitar (SQLServer) ou primeiro limita para depois ordenar (Oracle).Isso vai fazer toda a diferença. Isso vai automático de acordo com o banco que está por trás ??? Se for maravilha…
Isso é automático, cada dialeto de banco de dados define o seu próprio comportamento.
No oracle eu posso fazer:
select id, date from profiles where date >= sysdate - 10 and rownum <= 100 order by date;
Pega os primeiros 100 que aparecer e ordena eles.
select id, date from (select id, date from profiles where date >= sysdate - 10 order by date) where rownum <= 100;
Pega tudo primeiro, ordena, e me passa os primeiros 100 da lista.
Como vc vai ter esse nível de controle usando o Hibernate eu não tenho idéia. Até porque sou leigo em Hibernate. :roll:
Escrevendo o SQL nativo do seu banco e mandando o Hibernate executar :thumbup:
O Hibernate tem n facilidades. É mais fácil fazer session.save do que ficar se matando para colocar as props do seu objeto um statement (ou PreparedStatement).
Também é bem mais fácil trabalhar com relacionamentos no Hibernate.
E a Criteria API é excelente para buscas! Um dos pontos altos do Hibernate.
As vezes, com coisas não tão trivais assim, é chato trabalhar com Hibernate e vc talvez tenha um overhead a mais no seu sistema. Mas os casos são minoria. Acredito que qq overhead que o Hibernate gere é compensado pelo que vc talvez fizesse de errado com SQL na mão.
nossa e td começou com um singelo post meu =D hahaha
pena que ainda não achei solução 
Well, eu nao entendo quase nada de BD mas lah na empresa tinhamos um problema classico, comecamos a usar EJB e nao fizemos nenhum relacionamento no banco de dados (o relacionamento tenicamente ficava no codigo Java), isso foi uma pessima ideia (ainda bem que nao fui eu a dar ela, eu nem estava no projeto ainda), entao um companheiro foi contratado para ser o arquiteto pq nao tinhamos esse papel definido, o cara eh muito bom, e uma das primeiras coisas que ele fez foi desenvolver um fwzinho de acesso a JDBC (bem interessante) e implementar o padrao DAO pra nos, perfeito pq conseguimos manter a coexistencia entre DAO e EJB relativamente pacifica, mas daih ele quer usar hibernate, mas pelo que entendi nao podemos ainda pois o hibernate nao tem flexibilidade suficiente para uma coexistencia pacifica com EJBs, entao soh usaremos hibernate quando nao tiver mais uso de EJB no sistema (estamos atualizando aos poucos, retirando os EJBs quando mexemos em algo antigo).
Eh exatamente nesse caso que a pergunta do titulo nao se torna retorica, correto?
No oracle eu posso fazer:select id, date from profiles where date >= sysdate - 10 and rownum <= 100 order by date;
Pega os primeiros 100 que aparecer e ordena eles.
select id, date from (select id, date from profiles where date >= sysdate - 10 order by date) where rownum <= 100;
Pega tudo primeiro, ordena, e me passa os primeiros 100 da lista.
Como vc vai ter esse nível de controle usando o Hibernate eu não tenho idéia. Até porque sou leigo em Hibernate. :roll:
Sergio, as duas DMLs são possível com Hibernate/HSQL
E para mim, a grande vantagem de usar HSQL é a possibilidade de trocar de banco a hora que eu quiser, sem mudar nada, mas nada mesmo, na aplicação, e minha aplicação hoje roda em vários clientes diferentes, com Oracle, SQL-Server, MySQL e Postgres.
Outra vantagem que gosto no hibernate é o SchemaExport para gerar a base de dados à partir dos arquivos de mapeamento do hibernate. Eu adoro esta funcionalidade! 
Têm uma coisa que têm que ser levada em conta no uso do Hibernate, e que é responsável por pelo menos 50% do problemas na utilização do Hibernate que encontro por ai. O fluxo de utilização dele é completamente diferente do fluxo utilizado quando se têm JDBC.
Em JDBC você cria um DAO com create() save() e delete(), por que esse é o fluxo, você cria um object, você atualiza um objeto e você deleta um objeto.
Mas no Hibernate, 2.1 pra cima, você torna um objeto persistente e torna um objeto transitório (trasient). Você não atualiza um objeto explicitamente.
O que existe é o contexto da sessão (do hibernate). Todo objeto que estiver nesse contexto terá seu estado sincronizado com o seu registro no banco, sem que você tenha que dizer ao HB para fazê-lo.
Exêmplo: O código abaixo vai atualizar o campo nome, na tabela cliente.
Transaction t = session.beginTransation();
Cliente c = session.get(Cliente.class, 1);
c.setNome("Novo valor");
t.commit();
s.close();
Eu não preciso, e nem devo, chamar o session.update(). O update() não serve para atualizar o objeto no banco. Ele serve para colocar o objeto devolva ao contexto da session, e como nesse caso ele nunca saiu da sessão não deveria nem estar utilizando esse método.
** Todo objeto carregado pelo Hibernate, por default (você pode alterar o comportamente em alguns casos), está no contexto da sessao do Hibernate. **
Vamos supor que você queira fazer um wizard, colocando o objeto na HTTPSession, e editando aos poucos? Como você já deve ter percebido isso não vai funcionar por que se o indivíduo deixar o processo no meio babau, as alterações feitas nas telas anteriores foram salvas né? Segue abaixo um pseudo-código executado nesse processo:
// 1º Tela
Session s = openSession();
Cliente c = httpSession.get(Cliente.class, 1);
httpSession.setAttribute("cliente", c);
c.setNome(valorNovo);
s.close(); // <-- Auto-commit, o nome foi gravado no banco
// e a instância "c" foi retirada do contexto.
// 2º tela
Cliente c = (Cliente) httpSession.getAttribute("cliente");
c.setIdade(12); // Você nem usou hibernate aqui, então tudo bem.
// 3º Tela
Cliente c = (Cliente) httpSession.getAttribute("cliente");
c.setEndereco(valorNovo);
Session s = openSession();
s.update(c); // Ele está colocando o objeto no contexto e atualizando o
// registro no banco. Na verdade, seria melhor utilizar "merge" aqui.
s.close();
Nesse código a primeira tela é salva e não deveria ser salva. Como resolver isso?
1) Carregue o objeto e feche a sessão logo em seguida.
Session s = openSession();
Cliente c = session.get(Cliente.class, 1);
s.close();
httpSession.setAttribute("cliente", c);
c.setNome(valorNovo);
A solução (1) não resolve o problema se você quiser reutilizar essa session e/ou você estiver utilizando um PicoContainer ou Spring da vida que gerêncie a session para você.
2) Carregue e retira o objeto do contexto logo em seguida.
Session s = openSession();
Cliente c = httpSession.get(Cliente.class, 1);
s.evict(c);
httpSession.setAttribute("cliente", c);
c.setNome(valorNovo);
s.close();
A solução (2) resolve, porém bye bye LazyLoading.
3) Utilize session-per-conversation
Basicamente um session por processo, (no caso haveria uma mesma Session para todo o conversa do wirzard).
[small]* Processo "conversa" (conversation), um processo que é maior que apenas um request, porém não é longo.[/small]
Antes que me atirem pedras, eu não disse um conexão com o banco ativa durante a toda a conversa, eu disse uma sessão.
Esse é inclusive o padrão utilizado pelo Steam, jBMP... (BTW, Estou tentando utilizar isso no Spring de forma mais automática, alguem sabe como? Spring Web Flow?)
Segue um pseudo-codigo que como seria isso:
// 1º Tela
Session s = openSession();
s.setFlushMode(FlushMode.NEVER);
httpSession.setAttribute("s", s);
Cliente c = session.get(Cliente.class, 1);
httpSession.setAttribute("cliente", c);
c.setNome(valorNovo);
s.disconect(); // Não é close.
// 2º tela
Cliente c = (Cliente) httpSession.getAttribute("cliente");
c.setIdade(12); // Você nem usou hibernate aqui, então tudo bem.
// 3º Tela
Cliente c = (Cliente) httpSession.getAttribute("cliente");
c.setEndereco(valorNovo);
Session s = (Session) httpSession.getAttribute("s");
s.setFlushMode(FlushMode.AUTO);
s.reconnect();
s.close();
Pronto, você acaba de utilizar o Hibernate (e no futuro EJB3, que funciona da mesma maneira) de forma correta.
Poxa, comecei a escrever e não parei mais... hehehe... desculpem aew a menssagem um pouco grande. :D
Os código acima foram feitos sem ajuda de uma IDE e escondido do meu chefe, e como sou meio depedênde de IDE, podem haver erros.
Apenas umas ultimas dicas:
1) Leia com atenção o javadoc, especiamente do Session, e tenha certeza que você sabe para que serve cada método daquele. Os nomes não são os melhores, então não deduza, leia.
// Re-associa apenas.
sess.lock(obj, LockMode.NONE);
// Verifica a versão do objeto, então re-associa.
sess.lock(obj, LockMode.READ);
// Verifica a versão do objeto usando SELECT ... FOR UPDATE, então re-associa.
sess.lock(obj, LockMode.UPGRADE);
3) Leia todos os método da classe Criteria, em uma query você dizer ao HB para retorna todos os objeto fora do contexto.
4) ATENÇÂO! ATENÇÂO! ATENÇÂO! ATENÇÂO! ATENÇÂO! ATENÇÂO!
O método merge()/update()/save()/saveOrUpdate() do Session serve para fazer update de um objeto que não esteja no contexto da session. De fato, ele apenas coloca o objeto denovo no contexto. Por favor, leia a documentação atenciosamente.
juzepeleteiro , Parabéns por seu post 5 estrelas pra ele, estou iniciando em hibernate e suas informações foram muito úteis.
Abraço
juzepeleteiro , Parabéns por seu post 5 estrelas pra ele, estou iniciando em hibernate e suas informações foram muito úteis.
Abraço
Obrigado 
Parabéns mesmo. Meio complicado esse hibernate, mas com essa sua explicação bem-detalhada e clara, vai facilitar a vida de quem está começando agora com ele e/ou tentando migrar de JDBC para Hibernate (meu caso).
Bom, aproveitando o assunto Hibernate + DAO.
Dada as classes:
public class Pessoa{
public Collection getDependentes();
public void setDependentes(Collection col);
//Outros gets and sets
}
public class Dependente{
//gets and sets
}
Imaginem a seguinte situação. Implemento um DAO com o hibernate. Imaginem que seja a seguinte interface.
interface PessoaDAO
{
Pessoa getPessoaById(Long id);
}
Dai minha logica de negócio usa da seguinte maneira:
Pessoa pessoa = pessoaDAO.getPessoaById(1);
Collection dependentes = pessoa.getDependentes();
//Faz algo com cada dependente, alterando os atributos do dependente
Ok… Tudo funciona legal com hibernate, no fim da sessão tudo é atualizado ok…
Agora ESQUECAM O HIBERNATE! Alguma alma infeliz implementa SÓ a camada de persistência (i.e DAO´s) usando JDBC puro mas no método PessoaDAO.getPessoaById ele não pré-carrega os dependentes (porque deveria?) e nem modifica a classe Pessoa nem Dependente que são POJO´s. Resultado: getDependetes retorna null e minha lógica de negócio se quebra. Uma alteração na camada inferior resulta em problemas na superior.
Então minha dúvida e observação é essa. Ao utilizar hibernate, EJB ou outra coisa que têm esse mecanismo de persistência “automático”, ficamos amarrados a outro semelhante mesmo ou eu desconheço algo??? Mas a interface de DAO não devria supostamente abstrair o mecanismo de persistência??? Ou talvez minha interface também deva especificar eager-loading?
Por favor, discutam sobre esse assunto, acredito que é algo interessante e que pode acrescentar.
Valew!
Quem implementar o DAO vai ter que garantir o contrato, que é “trazer” (seja com Lazy loading ou não) as dependências, problema de quem vai implementar com JDBC.
Ninguém disse que ia ser fácil 
Empresa Oi tem 3 bilhões de ligação.Nem vc nem o Hibernate vão poder carregar todas essas ligações numa lista. Seja Lazy Loading, ou seja o que for.
Isso é um problema de tunning de banco de dados, já que terá que haver um belo índice que te permita pegar subsets dessa mundo sem distruir a máquina e/ou parar o banco.
Não senhor. Eu não falei que queria ter todas estas ligações, muito pelo contrário.
Para dar contexto eu já trabalhei numa aplicação com o seguinte cenário:
Ligação*—1 Assinante *—1 Grupo
Com casos de uso do tipo:
Listar todos os assinantes do grupo, depois o usuário seleciona um destes para ver suas ligações.
Sem lazy loading:
1 - Traz a lista de assinantes do banco de dados
2 - Exibe a lista
3 - Faz outra query pedindo todas as ligações do usuário
4 - Exibe a lista
Com lazy loading:
1 - grupoEscolhido.listarAssinantes();
2 - Exibe a lista
3 - usuarioEscolhido.listarLigacoes();
4 - Exibe a lista
Isso parece besteira, mas não é. Lazy loading te permite parcialmente esquecer que existe um banco de dados envolvido.
Quando você possui métodos que fazem a mesma coisa o bicho pega.
Imagine que no exemplo temos um método no DAO que faz uma consulta recuperando apenas os assinantes, sem suas ligações, do grupo:
class Dao{
public Set<Assinante> listarAssinantes(Grupo grupo){...}
}
Agora imagine que você tem outro caso de uso que exige que voce traga do grupo os assinantes e suas ligações.
class Dao{
public Set<Assinante> listarApenasAssinantes(Grupo grupo){...}
public Set<Assinante> listarAssinantesComLigacoes(Grupo grupo){...}
}
Baseado no seu caso de uso você escolhe um ou outro e eu poderia afirmar que 70% destes métodos é código repetido.
Falando em Caso, agora eu quero saber quanto de credito um usuario tem. O credito é dado por:
Crédito = Limite do Grupo - Gasto pelo grupo
Gasto pelo grupo = SOMA(Gasto assinantes)
Então eu tenho mais um método:
class Dao{
public Set<Assinante> listarApenasAssinantes(Grupo grupo){...}
public Set<Assinante> listarAssinantesComLigacoes(Grupo grupo){...}
public Grupo getGrupoDo(Usuario u){...}
}
Isso pode até estar desnormalizado no banco de dados para performance, mas estamos lidando com objetos e não falando sobre manipulação de dados em si 9que eu também posso fazer com Hibernate, aliás), fora que eu posso estar utilizando um banco de dados sem stored procedures (como antigos MySQL).
O que acontece quando nosso sistema precisa informar que o usuário gastou algo? Teria no DAO algo assim:
class Dao{
public Set<Assinante> listarApenasAssinantes(Grupo grupo){...}
public Set<Assinante> listarAssinantesComLigacoes(Grupo grupo){...}
public Grupo getGrupoDo(Usuario u){...}
public void adicionarLigacao(Usuario u, Ligaçao l){...}
}
A tendência é ter muitos métodos repetidos, uns trazem uma relação, outros não. COmo dito, muitos deles têm mais de 70% de código exatamente igual.
Utilizando Hibernate você só precisa de um método que retorne a lista de assinantes.
Quer saber todos os assinantes?
Set<assinante> assinantes = dao.listarAssinantes();
for(Assinante a:assinantes) System.out.println(a.getNome());
Precisa das ligações de um assinante da lista?
Set<assinante> assinantes = dao.listarAssinantes();
//NOTA: eu sei que set não tem get, mas ignore isso para facilitar
Assinante a = assinantes.get(0);
System.out.println(a.getLigações());
Crédito dele?
Set<assinante> assinantes = dao.listarAssinantes();
//NOTA: eu sei que set não tem get, mas ignore isso para facilitar
Assinante a = assinantes.get(0);
System.out.println(a.getCredito());
Informar gasto?
Set<assinante> assinantes = dao.listarAssinantes();
//NOTA: eu sei que set não tem get, mas ignore isso para facilitar
Assinante a = assinantes.get(0);
a.adicionarLigacao(ligação);
Sem repetiçãod e código, o Hibernate cuida das idas ao banco de dados. Com minha experiência em ambos os lados tenho que dizer que tende inclusive a ser mais performático, não porque é tããão otimizado mas sim porque em nome de ‘performance’ os programadores acabam fazendo besteiras incríveis e piorando ainda mais as coisas, como os tais cache caseiros.
JDBC é bom quando o que te importa é o banco de dados. Hibernate é bom quando o que te importa são objetos de negócio. Para o meio de um processo de negócio para chamar o método no DAO e preencher um buraco no objeto é matar a transparência da persistência (lembre-se: objetos de negócio não sabem o que é persistência), e na maioria das vezes suas regras de negócio vão incluir idas ao banco de dados para repopular objetos que estão pela metade.
Todos os exemplos acima mais ou menos fazem parte de um sistema gigantesco que eu participei (e que tinha uma hierarquia de usuarios, grupos e perfis muito mais complexa que a do exemplo) utilizando JDBC puro. Eu só fui entender o quanto lazy loading é maravilhosos depois de repetir muitas vezes os métodos e olhar nome como:
getUsuarioComPerfil
getUsuarioSemPerfil
getUsuarioComPerfilELigacoes
getUsuarioComPerfilEGrupo
Isso proque não entrei nas atualizações, só falei de consultas. Quando você tem uma atualização em um objeto de negócio é complicado. A quantidade de NullPointerExceptions é enorme porque muitas vezes você vai mantêr um objeto em sessão que não está completo e precisa atualizar algo que não foi trazido.
pcalcado, ótimo post. Concordo que é muito bom e prático o lazy loading. Mas refaço minha pergunta então: se você confia num eager ou lazy loading de determinada implementação, o DAO não perdeu o sentido no que se refere à esconder a implemenção do mecanismo de persistência. Repare que a sua listarAssinantes não diz nada sobre ter que carregar outras relações em conjunto.
E se é deste modo então, para que o DAO neste caso? Eu entendo que uma das principais vantagens do DAO é você poder “trocar” a implementação da persistência “SEM” afetar a lógica de negócio que a utiliza.
Por favor me esclareça esse ponto.
pcalcado, ótimo post. Concordo que é muito bom e prático o lazy loading. Mas refaço minha pergunta então: se você confia num eager ou lazy loading de determinada implementação, o DAO não perdeu o sentido no que se refere à esconder a implemenção do mecanismo de persistência. Repare que a sua listarAssinantes não diz nada sobre ter que carregar outras relações em conjunto.
E se é deste modo então, para que o DAO neste caso? Eu entendo que uma das principais vantagens do DAO é você poder “trocar” a implementação da persistência “SEM” afetar a lógica de negócio que a utiliza.Por favor me esclareça esse ponto.
Ah, agora eu entendi sua pergunta 
Utilizando Hibernate+DAO (encapsulado num Repository) você poderia trocar de persistência desde que a nova opção tenha as mesmas funcionalidades, como EJB3 (não conheço outras a ponto de mencionar aqui, mas acredito que existam. TopLink? JDO?).
Eu entendi sua preocupação mas não vejo como, sem um framework por trás, mantêr objetos de negócio que usem as vantagens de persistência transparente e ainda possam funcionar sem problema com persistência intrusiva, como a que se tem com JDBC direto.
O framework cumpre seu papel de tornar tarefas repetitivas e comuns (caching, lazy, eager) fáceis e razoavelmente padronizadas. Assim como qualquer outro framework você não rpecisa dele para isso mas… que trabalho vai dar!
Com a persistência padronizada do EJB 3.0 você pode ter como premissa o uso de EJB para persistência e ainda variar de implementação, mas voltar para JDBC é muito complicado.
Antes eu recomendaria Hibernate/EJB3.0 apenas para domínios complexos, agora eu recomendaria JDBC apenas para projetos muito simples ou para trechos de código que realmente precisam estar vinculados à bancos relacionais. Na maioria das vezes utilizar um framework trás vantagens desde o momento que se aprende a utiliza-lo.
Uma resposta mais concisa: O DAO permite que você isole o framework do seu código de aplicação. Você pdoe substituir o framework, mas o novo deve ter ao menos as funcionalidades que você já está usando.
O mecanismo de persistencia tem que abstrair isso do modelo. Ai esta a dificuldade em desenhar um modelo OO “puro” e ter que persisti-lo sem apoio de frameworks sofisticados como o Hibernate. A camada de persistencia tem que lidar “no braco” com coisas como lazy-loading, cache, locks, atualizacao em cascata, etc, o que nao eh trivial, definitivamente.
O que acaba acontecendo eh um modelo “hibrido”, em que voce tem que tomar cuidade com os NullPointerException, sem saber se o dado esta na base e ainda nao foi carregado ou se realmente a entidade nao tem aquele dado. 
Marcio Kuchma

Obrigado pela resposta!! É exatamente o que eu penso a respeito.
hibernate consegue acessar tabelas de sistema do oracle?
Conheço pouco de hibernate, por causa de um projeto que trabalhei, mas depois que você ja tem algum conecimnento, a manutencoa fica mais facil que no metodo tradicional DAO.