Hibernate Avancado Guj

download Hibernate Avancado Guj

of 22

Transcript of Hibernate Avancado Guj

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

Hibernate 3 avanado, boas prticas, padres e cachingMaurcio Linhares de Arago JuniorConhea boas prticas comuns no uso do Hibernate, padres de projeto relacionados, o desenvolvimento de uma camada de persistncia, integrao com o Spring e aprenda a aumentar ainda mais a velocidade das suas aplicaes usando o esquema de caching do framework

IntroduoO Hibernate o mais bem sucedido framework de mapeamento objeto/relacional (ORM Object/Relational Mapping) da comunidade Java e o seu sucesso foi to grande que ele influenciou mudanas drsticas em partes da especificao Java EE (antes J2EE) e ainda gerou uma verso para a plataforma .Net, que ainda est em fase beta. O sucesso do framework vem tanto da facilidade de se comear a trabalhar, quanto da quantidade de opes avanadas que melhoram vrios quesitos da aplicao e ns vamos ver um pouco dessas opes e de como us-las eficientemente.

Isto no uma introduoEste artigo no uma introduo, se voc ainda no conhece o Hibernate, veja o artigo Introduo ao Hibernate 3 (http://www.guj.com.br/java.tutorial.artigo.174.1.guj). Se voc j sabe o bsico do framework (instalao, configurao, mapeamentos e busca), pode seguir em frente. Se voc j leu o primeiro artigo, tambm no deve ter dificuldades seguindo esta segunda parte, pois o mesmo conjunto de classes utilizado. Alm das bibliotecas indicadas no primeiro artigo, voc vai precisar adicionar o ehcache.jar e as bibliotecas do framework Spring no seu classpath. Os arquivos de gerao do banco de dados esto disponveis junto com o material em anexo, o banco escolhido para os exemplos foi o MySQL, mas outros bancos relacionais podem ser utilizados, com poucas mudanas do arquivo de criao. O diagrama de classes e de tabelas tambm est disponvel com o material em anexo, alm dos arquivos que os geraram. O modelo das tabelas foi feito com o software DbDesigner e o diagrama de classes com o Jude. Nos exemplos de cdigo no constam os imports nem os packages onde se encontram os arquivos para economizar espao. Nos arquivos deste artigo voc pode encontrar os arquivos fonte originais com os packages e imports.

DicasAlguns costumes se tornaram comuns na comunidade de usurios, tanto por alguns problemas inerentes da maneira como o framework trabalha, como de entendimentos incorretos do funcionamento de alguns servios que so providos. Vejamos alguns deles:

S chame o que voc vai precisarQuando estiver mapeando os seus objetos, defina sempre todos os relacionamentos com o atributo lazy com o valor true. Isso vai fazer com que sempre que voc precisar carregar um objeto, os seus relacionamentos no sejam carregados junto. Se voc tambm precisa receber os objetos relacionados, defina na busca que voc os quer, usando a clusula left join fetch. No nosso modelo de exemplo, Disciplinas possuem Turmas, vejamos como uma query em HQL faria isso:Listagem 1 Exemplo de join em HQL

Grupo de Usurios Java http://www.guj.com.br Pgina 1

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/ from Disciplina d left join fetch d.turmas

Quando voc no define a os relacionamentos como lazy=true ou usa left join fetch, o Hibernate vai fazer uma query para os objetos que voc queria receber e depois vai fazer mais uma query para cada objeto resultante . Quer dizer, em vez de fazer uma query que traz N objetos resultantes, voc vai ter (N +1) buscas no banco, o que com certeza vai ser um tremendo gargalo de desempenho na sua aplicao, j que ele vai fazer um select para cada objeto que foi recebido. Mas claro que isso no uma verdade absoluta, voc pode ter que necessariamente carregar algum relacionamento do seu objeto sempre que ele for carregado. Quando isso for necessrio, defina o atributo lazy como false e o atributo outer-join como true.

Use e abuse do suporte a paginaoO Hibernate oferece um esquema portvel e interessante de paginao de resultados para todos os bancos que ele suporta oficialmente. Em vez de retornar 1000 objetos de uma s vez para o seu usurio (o que no vai ser nem um pouco interessante pra ele), faa paginao dos resultados, vai ser mais interessante pra ele, que no vai ter condies de interpretar milhares de resultados de uma nica vez e tambm vai melhorar a performance do servidor, que no vai precisar instanciar alguns milhares de objetos a cara requisio. Vejamos como fazer isso com HQL:Listagem 2 Paginando resultados Session session = HibernateUtility.getSession(); Query query = session.createQuery( " from Curso " ); query.setFirstResult( 0 ); query.setMaxResults( 10 ); System.out.print( query.list() ); session.close();

No exemplo, criamos a query from Curso e informamos ao objeto Query que queremos apenas os 10 primeiros resultados selecionados (na maioria dos bancos, os resultados se iniciam no 0, como em um Array). Se a busca no dinmica, use Named Queries Quando voc sabe que no vai precisar montar a query dinamicamente e j sabe quais vo ser os parmetros enviados para ela, use uma named query configurada em um dos arquivos de mapeamento do Hibernate. As named queries so compiladas e preparadas no banco de dados assim que o Hibernate se inicializa, o que aumenta a velocidade na qual essas queries executada (pois nem o banco nem o Hibernate precisam compilar elas outra vez). Em um arquivo de mapeamento qualquer:Listagem 3 Exemplo de named query

E chamando em cdigo:Listagem 4 Chamando uma named query Session session = HibernateUtility.getSession(); Query query = session.getNamedQuery( "listar.usuarios.para.login" ); query.setString("nome", "Mauricio"); query.setString("email", "[email protected]"); Grupo de Usurios Java http://www.guj.com.br Pgina 2

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/ System.out.print( query.list() ); session.close();

O cdigo muito parecido com o anterior, mas em vez de chamar createQuery() ns chamamos getNamedQuery() passando como parmetro o nome que foi dado a query no arquivo de mapeamento. A named query pode estar em qualquer dos arquivos de mapeamento do Hibernate, voc pode at mesmo criar um arquivo de mapeamento que s contenha named queries. O importante evitar que queries previsveis sejam montadas a todo o momento. Se a busca dinmica, use Criteria, no HQL Voc aprendeu HQL, achou uma linguagem interessante e simples de se trabalhar, mas o Hibernate tambm oferece buscas em uma API orientada a objetos, onde voc chama mtodos e passa parmetros para montar uma pesquisa e especialmente simples para se montar buscas que so construdas dinamicamente. Muitas vezes por j estar acostumado a trabalhar com HQL, voc simplesmente escreve a query em HQL e sai montando ela, concatenando Strings e inserindo ou retirando parmetros conforme eles so descobertos, o que normalmente traz erros que s so descobertos quando a aplicao comea a funcionar e demonstra comportamentos estranhos (ou queries que no funcionam, porque foram montadas incorretamente). Usando a API de Criteria, voc pode evitar a maioria desses problemas e ainda ter queries dinmicas que podem ser montadas facilmente. As associaes em Java no so bidirecionais Parece estranho ler isso em um primeiro momento, mas isso uma considerao importante. No ltimo artigo recebi vrias dvidas sobre problemas quando as pessoas tentavam executar o seguinte cdigo:Session session = HibernateUtility.getSession(); HibernateUtility.beginTransaction(); Aluno aluno = new Aluno(); Endereco endereco = new Endereco(); aluno.setNome("Maurcio Linhares"); endereco.setCidade("Joo Pessoa"); aluno.setEndereco(endereco); session.save(aluno); HibernateUtility.commitTransaction(); HibernateUtility.closeSession();

O erro lanado pelo Hibernate indicava que o objeto endereco no tinha como ser inserido porque o valor do objeto pessoa relacionado a ele (que no nosso caso uma subclasse, Aluno) era nulo, mas ns colocamos o objeto endereco em pessoa, na chamada do mtodo setEndereco(), porque isso acontece? Como eu disse anteriormente, as associaes em Java no so bidirecionais automaticamente, voc tem que tornar a associao bidirecional explicitamente colocando a pessoa no endereco tambm, porque o relacionamento entre eles no banco de dados entre chaves primrias, no pode existir um endereco sem uma pessoa relacionada a ele. Para o nosso cdigo funcionar, ele deveria estar assim:Session session = HibernateUtility.getSession(); HibernateUtility.beginTransaction(); Aluno aluno = new Aluno(); Endereco endereco = new Endereco(); aluno.setNome("Maurcio Linhares"); endereco.setCidade("Joo Pessoa"); aluno.setEndereco(endereco); endereco.setPessoa(aluno); session.save(aluno); HibernateUtility.commitTransaction(); HibernateUtility.closeSession();

Grupo de Usurios Java http://www.guj.com.br Pgina 3

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

Agora, como ns definimos explicitamente o relacionamento como bidirecional o cdigo funciona normalmente. UPDATES e DELETES em massa utilizando o Hibernate Um dos grandes problemas de se utilizar uma ferramenta de ORM que voc normalmente precisa trazer um objeto para a memria para poder editar ou atualizar algum campo. A coisa fica ainda mais complicada quando voc tem que atualizar vrios objetos de uma s vez, pois sero ainda mais objetos carregados na memria consumindo os recursos da sua mquina, uma coisa simples que em SQL poderia ser resolvida com um simples e rpido UPDATE. Agora com o Hibernate j possvel fazer UPDATES e DELETES em massa sem ter que carregar os objetos para a memria, a sintaxe dos comandos simples e muito parecida com as suas contrapartes em SQL, vejamos o comando: ( update | delete) from nomeDaClasse where As duas palavras em negrito (from e where) so opcionais, obrigatrio mesmo so apenas o comando (update ou delete) e o nome da classe onde esse comando vai ser utilizado. Em um update ou delete no Hibernate voc s pode utilizar apenas uma classe e no pode fazer nenhum join nem utilizar apelidos, apenas acessar as propriedades da classe. Vejamos um exemplo de cdigo onde vamos atualizar os nomes de todos os cursos que tenham o nome DSI:HibernateUtility.beginTransaction(); Session session = HibernateUtility.getSession(); String updateQuery = update Curso set nome = :novoNome where nome = DSI ; Query update = session.createQuery( updateQuery ); update.setString( novoNome, Desenvolvimento de Software); int registrosAtualizados = update.executeUpdate(); HibernateUtility.commitTransaction(); HibernateUtility.closeSession();

Como voc pode ver, montar um update simples e a sintaxe do delete igual (mudando apenas o nome do comando). O mtodo executeUpdate() retorna a quantidade de registros atualizadas pelo comando, assim voc pode saber se ele surtiu efeito ou no no banco de dados.

FerramentasO site http://tools.hibernate.org/ traz as novas ferramentas do Hibernate (para a verso 3.x) para o Eclipse e vrios tasks do Ant. Os novos plugins se conectam ao banco para testar queries, geram arquivos de mapeamento e at mesmo as classes das tabelas do banco de dados. Vale a pena fazer os testes com o seu banco de dados, mas no v com muita sede ao pote, a gerao de arquivos de mapeamento e classes Java ainda no perfeita (e depende muito do suporte a metadata do driver JDBC do seu banco). Quando for utilizlos, faa sempre uma vistoria nos arquivos gerados.

Desenvolvendo uma camada de persistncia simplesUma das partes mais importantes da maioria das aplicaes o acesso as suas fontes de informao (que so muitas vezes bancos de dados relacionais), por isso as camadas de persistncia tambm se configuram como uma parte muito importante de um sistema. Persistncia mal feita pode trazer problemas de performance, incompatibilidade entre bancos de dados e dificuldade para a adio de novos recursos. O Hibernate resolve vrios problemas do desenvolvimento desse tipo de camada, com o mapeamento objeto/relacional, esquemas de cache (que ns vamos ver mais a frente) e linguagens que abstraem oGrupo de Usurios Java http://www.guj.com.br Pgina 4

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

banco de dados que est sendo utilizado, mas ainda existem algumas arestas que devem ser aparadas. Um dos principais que os objetos que utilizam a camada de persistncia (os Actions do seu sistema web ou os formulrios da sua aplicao Swing) no deveriam saber que esto utilizando o Hibernate. Idealmente, eles nem deveriam saber que existe um banco de dados relacional do outro lado, mas isso ainda um sonho distante nos nossos dias. Vamos ento montar uma camada de persistncia com padres de projeto que podem nos ajudar a manter o cdigo de acesso ao banco longe dos objetos que utilizam a camada, aproveitando ao mximo as possibilidades que o Hibernate nos fornece. Data Access Object (DAO) O padro de projeto Data Access Object (daqui pra frente chamado de DAO) um velho conhecido da comunidade Java, seu objetivo principal manter a lgica de acesso a bancos de dados dentro de objetos especializados, que transformam as queries e ResultSets retornados pela API de JDBC em objetos que faam sentido para a aplicao que est fazendo uso dos DAOs. Se ns no estivssemos utilizando o Hibernate, poderamos ter um DAO com um mtodo Collection listarCursos() que criaria um Statement, executaria uma query no banco de dados (algo como select * from Curso), trataria o ResultSet retornado e transformaria cada linha desse ResultSet em um objeto Curso, que seria adicionado a uma coleo qualquer (uma List, por exemplo) que seria ento retornada como resultado da chamada ao mtodo. Mas como estamos usando o Hibernate, todo esse trabalho j feito pelo prprio framework, o que nos indica que os nossos DAOs vo ser mais simples de serem implementados, como tambm podem ser mais poderosos do que os DAOs comuns, j que o Hibernate ns d novas escolhas no acesso ao banco. O primeiro DAO que ns vamos definir um DAO genrico, que vai lidar com as aes conhecidas como CRUD Create/Read/Update/Delete (Criar/Ler/Atualizar/Deletar) que so o bsico de qualquer camada de persistncia. Aqui ns percebemos uma das primeiras vantagens da camada de persistncia montada sobre o Hibernate, porque ns s precisamos de um nico DAO genrico para fazer CRUD de todas as classes mapeadas, j que o prprio Hibernate vai cuidar de fazer a persistncia no banco de dados. Se estivssemos usando JDBC puro, provavelmente teramos um DAO fazendo CRUD para cada classe mapeada para o banco de dados, que s no nosso modelo de exemplo geraria oito classes, enquanto com o Hibernate apenas uma classe necessria. Vejamos a interface que vai definir esse comportamento (e ser implementada por uma classe que use o Hibernate):Listagem 5 interface para o DAO base da aplicao public interface GenericDao { public void save (Object objeto); public void update (Object objeto); public void delete(Object objeto); public List list (Class clazz); public List list (Class clazz, int firstResult, int maxResults); public List listByExample(Object example); public Object getById(Serializable id, Class clazz); }

Definir essa interface vai nos ajudar a desenvolver vrias implementaes do DAO (e at mesmo desenvolver uma que no utilize o Hibernate, por exemplo). A interface no demonstra em momento algum qual o mecanismo de persistncia que ela utiliza, os objetos que fizerem uso dela no vo estar presos a o Hibernate nem a nenhuma implementao especfica dela. Os mtodos que esto definidos so simples: save() Insere o objeto no banco de dados; update() Atualiza um objeto que j tenha sido inserido no banco de dados; delete() Deleta um objeto do banco de dados;Grupo de Usurios Java http://www.guj.com.br Pgina 5

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

list() Retorna todos os objetos da classe passada como parmetro que esto no banco de dados, a segunda verso do mtodo faz a mesma coisa, mas com paginao de resultados; listByExample() Retorna todos os objetos que so parecidos com o objeto que foi passado como parmetro; getById() Retorna o objeto que tenha o identificador indicado e pertena a classe passada como parmetro; Com a interface definida, podemos comear a pensar em uma possvel implementao dela utilizando o Hibernate. Vamos comear por uma classe de apoio que vai nos ajudar a acessar e configurar o Hibernate na nossa aplicao na listagem 6:Listagem 6 Classe utilitria para configurao e acesso ao Hibernate public class HibernateUtility { private static final SessionFactory factory; private static final ThreadLocal sessionThread = new ThreadLocal(); private static final ThreadLocal transactionThread = new ThreadLocal(); static { //Bloco esttico que inicializa o Hibernate, escreve o stack trace se houver algum problema e relana a exceo try { factory = new Configuration().configure().buildSessionFactory(); } catch (RuntimeException e) { e.printStackTrace(); throw e; } }

public static Session getSession() { if ( sessionThread.get() == null ) { Session session = factory.openSession(); sessionThread.set( session ); } return (Session) sessionThread.get(); }

public static void closeSession() { Session session = (Session) sessionThread.get(); if ( session != null && session.isOpen() ) { sessionThread.set(null); session.close(); } } public static void beginTransaction() { Transaction transaction = getSession().beginTransaction(); transactionThread.set(transaction); } public static void commitTransaction() { Transaction transaction = (Transaction) transactionThread.get(); if ( transaction != null && !transaction.wasCommitted() && !transaction.wasRolledBack() ) { transaction.commit(); transactionThread.set(null); } } public static void rollbackTransaction() { Transaction transaction = (Transaction) transactionThread.get(); if ( transaction != null && !transaction.wasCommitted() && !transaction.wasRolledBack() ) { transaction.rollback(); transactionThread.set(null); } } }

Grupo de Usurios Java http://www.guj.com.br Pgina 6

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

O cdigo da listagem 6 a nossa classe utilitria para acessar e configurar o Hibernate no nosso ambiente. Ela se inicia com as declaraes de trs variveis constantes, factory que vai guardar a SessionFactory do Hibernate e dois objetos ThreadLocal que vo guardar os valores da Session e da Transaction do Hibernate.

Blocos estticos e exceesO bloco esttico da listagem 6 pode lanar uma exceo se o Hibernate no for configurado corretamente (ou ocorrer algum erro na sua inicializao), mas o lanamento dessa exceo no vai impedir que a aplicao funcione. Entretanto, quando a session factory do Hibernate for acessada vai lanar uma exceo avisando que ela no foi configurada corretamente, portanto, preste ateno nos logs que vo ser gerados pela aplicao para no ser pego de surpresa.Mas por que utilizar ThreadLocal? Os objetos ThreadLocal vo ser utilizados para guardar os valores das sesses e transaes do Hibernate para que ns possamos garantir que todos os objetos dentro de uma mesma Thread possam acessar o Hibernate sem problemas de concorrncia. Por exemplo, em um ambiente web, onde cada requisio vai necessariamente criar uma nova Thread, ns vamos poder associar essa uma sesso e uma transao nessa Thread no inicio da requisio e esses objetos vo estar disponveis para todos os objetos criados (ou utilizados) dentro da Thread dessa requisio sem nenhum problema (at mesmo se eles forem criados em outras Threads). O cdigo da listagem simples: getSession() procura uma sesso na Thread corrente, se no houver nenhuma ele cria uma nova sesso, associa ela com a Thread corrente e retorna a sesso; closeSession() fecha a sesso da Thread corrente; beginTransaction() inicia uma transao com o banco de dados (veja que o cdigo no procura saber se j existe uma transao, ele sempre abre uma nova); commitTransaction()testa se existe uma transao na Thread corrente e se possvel fazer o commit, se estiver tudo certo, ele chama commit() na transao; rollbackTransaction() testa se existe uma transao na Thread corrente e se possvel fazer o rollback dela, se for a transao corrente sofre um rollback; Agora que j temos uma classe utilitria, podemos desenvolver a nossa primeira implementao do GenericDao utilizando o Hibernate na Listagem 7:Listagem 7 implementao do GenericDao com o Hibernate public class HibernateGenericDao implements GenericDao { public Serializable save(Object objeto) { return HibernateUtility.getSession().save(objeto); } public void update(Object objeto) { HibernateUtility.getSession().update(objeto); } public void delete(Object objeto) { HibernateUtility.getSession().delete(objeto); } public List list(Class clazz) { return HibernateUtility.getSession().createCriteria(clazz).list(); } public List list(Class clazz, int firstResult, int maxResults) { Criteria criteria = HibernateUtility.getSession().createCriteria(clazz); criteria.setFirstResult(firstResult); Grupo de Usurios Java http://www.guj.com.br Pgina 7

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/ criteria.setMaxResults(maxResults); return criteria.list(); } public List listByExample(Object example) { Criteria criteria = HibernateUtility.getSession().createCriteria( example.getClass() ); Example sample = Example.create( example ); sample.enableLike(); sample.excludeZeroes(); criteria.add( sample ); return criteria.list(); } public Object getById(Serializable id, Class clazz) { return HibernateUtility.getSession().get(clazz, id); } }

A implementao do DAO tambm segue a simplicidade que ns espervamos, a maioria dos mtodos conta com apenas uma simples linha de cdigo, apenas dois mtodos fugiram a regra, o mtodo list() com suporte a paginao e o mtodo listByExample() que recebe como parmetro um objeto de exemplo (que seja um objeto mapeado pelo Hibernate, como um objeto Curso no nosso modelo) e utiliza ele como exemplo para fazer uma busca no banco de dados. Voc j deve ter percebido uma coisa estranha no cdigo, em todos os mtodos ns chamamos uma sesso atravs da classe HibernateUtility, mas em nenhum momento ns iniciamos uma transao para nossas sesses e sem transaes no acontecem mudanas no banco de dados. Voc no deveria colocar cdigo de controle de transaes dentro dos seus objetos DAOs, porque pode chegar um momento onde voc precise de dois mtodos no mesmo DAO executem dentro de uma mesma transao (como fazer uma insero e logo aps uma atualizao de algum objeto), como voc no quer que apenas uma das aes tenha sucesso sozinha, necessrio manter tudo dentro de uma nica transao que deve ficar fora dos objetos DAO. Mas onde chamar as transaes? Existem algumas maneiras de se fazer esse controle, uma maneira comum adicionar aos objetos DAO mtodos que iniciem e terminem uma transao (parecidos com aqueles que temos na classe HibernateUtility), mas esse mtodo traz um outro problema, que deixar o controle de transaes aparente no seu cdigo, pois voc vai ter que chamar diretamente os mtodos e definir programaticamente quais so as transaes, o que termina deixando essa soluo at mesmo parecida com o controle de transaes dentro do prprio DAO. Em aplicaes web, uma prtica comum criar uma classe filtro (que implementa a interface javax.servlet.Filter) , essa classe vai abrir uma sesso e iniciar uma transao com o banco de dados para que todas as chamadas na requisio acessem essa sesso e essa transao, alm disso, essa classe tambm vai ser responsvel por fazer o rollback() da transao se alguma exceo for lanada e no fim vai fechar a sesso em todos os casos, liberando o cdigo da aplicao de se preocupar com isso. Vejamos na listagem 8 como esse filtro poderia ser implementado:Listagem 8 filtro para uso do Hibernate em aplicaes web public class FiltroDoHibernate implements Filter { public void init(FilterConfig config) throws ServletException { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HibernateUtility.beginTransaction(); try { chain.doFilter(request, response); HibernateUtility.commitTransaction(); Grupo de Usurios Java http://www.guj.com.br Pgina 8

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

} catch (HibernateException exception) { exception.printStackTrace(); HibernateUtility.rollbackTransaction(); } finally { HibernateUtility.closeSession(); } } public void destroy() { } }

Mas essa implementao tambm apresenta problemas, porque ela pressupe automaticamente que cada requisio feita ao sistema apenas uma transao e em algum momento pode ser necessrio o uso de vrias transaes dentro de uma mesma requisio (mesmo que na maioria dos casos seja mesmo apenas uma requisio por transao). Outro problema que ela provavelmente vai iniciar transaes at mesmo quando elas no so necessrias, o que pode gerar um gasto desnecessrio de recursos da aplicao e do banco de dados.

Filtros e verses de containersPara utilizar filtros em aplicaes web em Java voc necessita de um container de servlets (um servidor web Java) que tenha suporte a especificao Servlet 2.3 ou superior (como por exemplo, o Tomcat 4.x ou 5.x).Se voc no est em um ambiente web ou o filtro no resolve o seu problema por causa de transaes complexas demais, ainda existe uma soluo para o seu problema que ainda melhor do que as anteriores, alm de deixar o cdigo muito mais simples de ser mantido, que utilizar o framework Spring para controlar as suas transaes do Hibernate. E os outros DAOs? Com esse DAO genrico ns j diminumos em muito a quantidade de cdigo envolvida na camada de persistncia, mas sendo genrico, ele tambm no pode ter comportamentos que s funcionem em classes especficas. Para essas classes especficas devem ser criados outros DAOs especficos, vejamos um exemplo com um DAO especfico para cursos (ele tem apenas um mtodo, mas poderiam haver mais se fosse necessrio) nas listagens 9 e 10:Listagem 9 Interface CursoDao public interface CursoDao extends GenericDao { public List listarCursosPorDisciplina (Disciplina disciplina); } Listagem 10 Implementao da interface CursoDAO public class HibernateCursoDao extends HibernateGenericDao implements CursoDao { public List listarCursosPorDisciplina(Disciplina disciplina) { Session session = HibernateUtility.getSession(); Query query = session.getNamedQuery("listar.cursos.por.disciplina"); query.setInteger( "id", disciplina.getId() ); return query.list(); } }

Um ponto importante a ser percebido na nossa implementao que a interface CursoDao extende a interface GenericDao forando a implementao dessa interface pela classe que implementar CursoDao. Isso no uma obrigao, voc pode simplesmente retirar essa necessidade, isso apenas uma

Grupo de Usurios Java http://www.guj.com.br Pgina 9

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

convenincia, pois eu posso simplesmente usar CursoDao quando estiver trabalhando com Cursos, em vez de ter que trabalhar com GenericDao e tambm com CursoDao. Voc no precisa criar DAOs para cada objeto do seu modelo, voc pode ter DAOs de mdulos, que renem comportamentos de mdulos especficos do seu sistema, trabalhando com vrios objetos diferentes. No nosso exemplo poderia existir um DAO especfico para o mdulo de inscrio nas turmas, que englobaria mtodos para lidar com Turmas, Alunos, Professores e Disciplinas. Quando estiver montando a sua aplicao, avalie a quantidade de mtodos e o tamanho dos DAOs, se eles ficarem grandes demais, est na hora de voc comear a dividir as responsabilidades.

O que o framework Spring?O Spring um framework de inverso de controle e de provimento de servios para aplicaes Java. Ele torna o desenvolvimento de aplicaes Java EE e at mesmo Java SE mais simples abstraindo e simplificando acesso a recursos avanados (e complexos) como controle de transaes, disponibilizao de objetos remotos e outras funcionalidades. Ele tambm contm vrias classes de apoio para resolver problemas comuns, inclusive classes para facilitar o uso de frameworks de mapeamento objeto/relacional como o Hibernate, que ns vamos utilizar nesse artigo. Voc pode encontrar material de introduo ao Spring na edio nmero 13 da revista MundoJava ou nesse tutorial do TheServerSide.com. Para fazer os exemplos dessa parte funcionarem, alm dos .JAR do Hibernate, voc precisa colocar os .JAR do Spring e do DBCP (que vem na distribuio do Spring) no seu classpath.

Desenvolvendo uma camada de persistncia com Spring e HibernateVejamos agora como implementar a nossa camada de persistncia utilizando o Spring junto do Hibernate. Utilizando o Spring, ns vamos nos livrar de vez do controle de transaes em cdigo e tudo vai ser feito de forma declarativa, no arquivo de configurao do Spring. E alm disso, ainda vamos utilizar como base as classes de suporte a acesso a banco de dados do Spring, que vo suplantar a nossa classe HibernateUtility e deixar os nossos DAOs ainda mais simples. Antes de passar para a integrao com o Hibernate, vamos entender como o Spring faz o controle de transao das aplicaes.

Nvel de isolamento e comportamento de propagao de transaesO nvel de isolamento de uma transao simboliza o quanto ela segura com relao a outros agentes que estejam acessando (ou tentando acessar) as informaes contidas dentro daquela transao. no nvel de isolamento que voc vai definir o quanto esses agentes externos podem influenciar na sua transao. Voc poderia definir, por exemplo, que ningum pode acessar ou atualizar essas informaes no banco de dados enquanto voc estiver com elas dentro de uma transao, mas isso vai gastar muitos recursos e pode diminuir e muito a performance da sua aplicao, por outro lado, se voc deixar que outras pessoas vejam e atualizem as informaes poderia inserir dados falsos no sistema, o que poderia acarretar problemas maiores ainda. Ento voc deve pensar bem antes de escolher o nvel de isolamento de uma transao. O comportamento de propagao define como ela deve adquirir e lidar com as suas transaes, voc poderia por exemplo ter uma ao que nunca deveria executar dentro de uma transao e outra que s deveria executar se j houvesse uma transao corrente, nunca iniciando uma nova transao.

Grupo de Usurios Java http://www.guj.com.br Pgina 10

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

No Spring voc pode trabalhar dois tipos diferentes de gerncia de transaes: Transaes declarativas: So as transaes que ficam definidas em arquivos de configurao. So o tipo mais simples e mais utilizado, porque deixam o seu cdigo livre de transaes e ainda podem ser trocadas de maneira simples, normalmente apenas editando um arquivo de configurao. Transaes definidas como atributos tambm podem ser consideradas declarativas, mas elas so mais complexas porque exigem a compilao da classes. Transaes programticas: So as transaes que ficam definidas dentro do seu cdigo. No so uma boa escolha porque se houver necessidade de mudar alguma coisa voc vai ter que mexer no seu cdigo, mas podem existir casos onde ela necessria (transaes programticas com o Spring no vo ser vistas nesse artigo). A interface base de suporte a transaes no Spring PlataformTransactionManager, cada plataforma (como JTA, JDBC, JMS e outras) tem uma implementao especfica dessa interface, que rene os servios essenciais para a gerncia de transaes em uma aplicao. As informaes de uma transao (como a propagao, o tempo de espera e o nvel de isolamento) so encapsulados em uma classe que implementa a interface TransactionDefinition. Tambm na interface TransactionDefinition que ns vamos encontrar as constantes que simbolizam o nvel de isolamento e a propagao das transaes vejamos essas constantes: Nvel de isolamento TransactionDefinition.ISOLATION_DEFAULT TransactionDefinition.ISOLATION_READ_UNCOMMITED Descrio o nvel geral definido no PlataformTransactionManager utilizado. Nesse nvel as transaes podem ler informaes que ainda no receberam um commit. Esse nvel no indicado porque voc pode estar trabalhando com informaes que no so confiveis. Esse nvel garante que voc s vai ler informaes que receberam um commit, o nvel mais comum de ser utilizado. Esse nvel garante que voc pode selecionar a mesma informao mais uma vez, mesmo que ela tenha sido alterada durante uma outra transao. Esse nvel garante que todas as transaes so executadas sequencialmente, uma aps a outra, sem que haja nenhuma influncia entre as informaes que eles lidam. o modo mais confivel mas tambm o que exige mais recursos da aplicao.

TransactionDefinition.ISOLATION_READ_COMMITED

TransactionDefinition.ISOLATION_REPEATABLE_READ

TransactionDefinition.ISOLATION_SERIALIZABLE

Comportamento de propagao TransactionDefinition.PROPAGATION_REQUIRED

Descrio Indica que o uso de uma transao obrigatrio. Se j houver uma transao ela utilizada, se no houver nenhuma uma nova criada. Indica que se houver uma transao ela utilizada, se no houver nenhuma a ao executada de forma no-transacional. Indica que a existncia de uma transao obrigatria. Se no houver uma transao acontecendo uma exceo lanada. Indica que a ao deve ser executada sempre fora de uma transao. Se j houver uma transao ela suspendida e a ao

TransactionDefinition.PROPAGATION_SUPPORTS

TransactionDefinition.PROPAGATION_MANDATORY

TransactionDefinition.PROPAGATION_NOT_SUPPORTED

Grupo de Usurios Java http://www.guj.com.br Pgina 11

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

executada e forma no-transacional. TransactionDefinition.PROPAGATION_REQUIRES_NEW Indica que uma nova transao sempre vai ser iniciada. Se j houver uma transao ocorrendo ela suspensa. Indica que nunca vai ser executado dentro de transaes. Se houver uma transao corrente uma exceo lanada. Executa em transaes aninhadas (uma transao acontecendo dentro de outra transao). Se no houver nenhuma transao ocorrendo se comporta de forma igual a PROPAGATION_REQUIRED

TransactionDefinition.PROPAGATION_NEVER

TransactionDefinition.PROPAGATION_NESTED

Agora que voc j entendeu a base do controle de transaes do Spring, vamos voltar para a nossa camada de persistncia, implementando a interface GenericDao com o Spring na listagem 11:Listagem 11 Implementao da interface GenericDao com o Spring e Hibernate public class HibernateGenericDao extends HibernateDaoSupport implements GenericDao { public Serializable save(Object objeto) { return this.getHibernateTemplate().save(objeto); } public void update(Object objeto) { this.getHibernateTemplate().update(objeto); } public void delete(Object objeto) { this.getHibernateTemplate().delete(objeto); } public List list(Class clazz) { return this.getHibernateTemplate().loadAll(clazz); }

public List list(Class clazz, int firstResult, int maxResults) { return this.getHibernateTemplate() .executeFind( new CriteriaListCallback(clazz, firstResult, maxResults) ); } public List listByExample(Object example) { return this.getHibernateTemplate().findByExample(example); } public Object getById(Serializable id, Class clazz) { return this.getHibernateTemplate().get(clazz, id); } private class CriteriaListCallback implements HibernateCallback { private Class clazz; private Integer inicio; private Integer quantidade; public CriteriaListCallback(Class clazz, Integer inicio, Integer quantidade) { this.clazz = clazz; this.inicio = inicio; this.quantidade = quantidade; } public Object doInHibernate(Session session) throws HibernateException, Grupo de Usurios Java http://www.guj.com.br Pgina 12

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/ SQLException { Criteria criteria = session.createCriteria(clazz); criteria.setFirstResult(inicio); criteria.setMaxResults(quantidade); return criteria.list(); } } }

A nova implementao da interface GenericDao tambm quase to simples quanto a anterior, utilizando a classe utilitria HibernateUtility, mas ela tem algumas diferenas muito importantes. Uma das principais que ela extende uma classe do Spring, HibernateDaoSupport, que fornece vrios mtodos e objetos utilitrios para se trabalhar com o Hibernate. Uma das principais caractersticas da classe HibernateDaoSupport o objeto HibernateTemplate, que pode ser acessado atravs to mtodo getHibernateTemplate(), ele oferece atalhos para vrios mtodos da Session do Hibernate, sem acessar a Session diretamente, como save(), update() e delete(). O HibernateTemplate tambm executa objetos que implementem a interface HibernateCallback, que serve para se definir lgicas mais complexas que necessitem realmente de acesso a um objeto Session. No nosso exemplo, criamos um objeto que implementa a interface HibernateCallback para executar a listagem de objetos com paginao. Veja que o objeto CriteriaListCallback tem trs propriedades, que so a classe que vai ser listada, o resultado inicial e a quantidade mxima de resultado, usando essa classe ns acessamos um objeto Session sem correr nenhum risco de atrapalhar o controle de transaes, j que ele vai ser chamado atravs do objeto HibernateCallback. Sempre que voc necessitar de uma lgica complexa nas suas queries do Hibernate, monte um objeto que implemente a interface HibernateCallback para fazer o servio. Agora que ns j temos uma implementao com o Hibernate, vamos ver como ficaria a configurao do Spring para controlar a transao do nosso DAO:Listagem 12 Configurao do Spring

br/edu/cefetpb/Curso.hbm.xml, br/edu/cefetpb/Disciplina.hbm.xml, br/edu/cefetpb/Turma.hbm.xml, br/edu/cefetpb/Pessoa.hbm.xml, br/edu/cefetpb/Aluno.hbm.xml, br/edu/cefetpb/Professor.hbm.xml, br/edu/cefetpb/Endereco.hbm.xml org.hibernate.dialect.MySQLDialectGrupo de Usurios Java http://www.guj.com.br Pgina 13

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

true true true jdbc:mysql://localhost/hibernate?autoReconnect=true root com.mysql.jdbc.Driver 5 20 5 true

Grupo de Usurios Java http://www.guj.com.br Pgina 14

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED PROPAGATION_SUPPORTS, readOnly PROPAGATION_SUPPORTS, readOnly Na nossa configurao do Spring, foram definidos 5 objetos, que vo ser utilizados para o nosso controle de transaes, vejamos um grfico de relacionamentos entre eles:Imagem 1 Beans do Spring

Grupo de Usurios Java http://www.guj.com.br Pgina 15

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

Agora vamos entender o que cada um desses objetos no arquivo de configurao do Spring: dataSource: o objeto que faz conexo com o banco e utilizado pela SessionFactory do Hibernate para criar novas conexes JDBC, no nosso exemplo foi escolhido o data source do projeto Jakarta Commons DBCP (o mesmo data source utilizado pelo Tomcat); sessionFactory: a SessionFactory do Hibernate, mas configurada por uma classe do Spring, a classe org.springframework.orm.hibernate3.LocalSessionFactoryBean. Voc pode at utilizar a prpria SessionFactory do Hibernate, mas vai perder muito das facilidades que o Spring lhe fornece. Alm das configuraes normais do Hibernate, esse objeto tambm recebe um dataSource para obter conexes JDBC. transactionManager: aqui ns j estamos chegando no controle de transao. O transactionManager escolhido foi o HibernateTransactionManager, que a implementao da interface PlatformTransactionManager (citada acima) que lida com as transaes do Hibernate. Esse recebe como dependncias a sessionFactory do Hibernate e (opcionalmente) o dataSource que est sendo utilizado. daoAlvo: a nossa implementao do Spring para o GenericDao, como dependncia ele recebe a sessionFactory do Hibernate. No esse o objeto que ns vamos utilizar, porque ele ainda no transacional, ele s est aqui para ser transformado em um objeto transacional. Por ltimo temos o daoGenericoTransacional. Esse o mais complicado dos nossos objetos, ele um objeto proxy (um objeto que serve de acesso para outro objeto ou alguma outra coisa). esse objeto proxy que faz todo o controle de transaes no nosso objeto daoAlvo e esse objeto que ns vamos utilizar na nossa aplicao.

Grupo de Usurios Java http://www.guj.com.br Pgina 16

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

Ele encapsula o nosso objeto DAO e usa o transactionManager para montar as transaes conforme ele est configurado na propriedade transactionAtributes. Essa propriedade um objeto Properties onde as chaves so os nomes dos mtodos e os valores so as definies de isolamento e do comportamento de propagao das transaes, como por exemplo na propriedade seguinte:

PROPAGATION_SUPPORTS, readOnly Esse valor do objeto Properties indica que todos os mtodos que comearem com list no nome usam a propagao PROPAGATION_SUPPORTS e o nvel de isolamento readOnly (no vimos esse isolamento anteriormente, mas ele indica que somente-leitura, no existe mudana no banco de dados). Como o objeto daoGenericoTransacional um proxy, a nossa aplicao nunca vai saber onde fica o cdigo de gerncia de transaes, porque para ela o objeto que est sendo utilizado um GenericDao, ela no sabe que est acessando um objeto proxy que faz todo o controle de transaes. Vejamos um cdigo que faz uso desse objeto na listagem 12:Listagem 12 Teste do JUnit que demonstra o uso do proxy public class SpringTestExemplos extends TestCase { private ApplicationContext context;

protected void setUp() throws Exception { super.setUp(); context = new ClassPathXmlApplicationContext("applicationContext.xml"); } public void testInserirCurso() { GenericDao dao = (GenericDao) context.getBean("daoGenericoTransacional"); Integer quantidadeAnterior = dao.list(Curso.class).size(); Curso curso = new Curso(); curso.setNome("DSI"); curso.setDescricao("Desenvolvimento de Software Para internet"); dao.save(curso); if ( quantidadeAnterior.equals( dao.list(Curso.class) ) ) { this.fail("A quantidade de cursos deveria ter sido aumentada"); } }

}

Como voc percebeu, no existe nada de estranho no cdigo, apenas pegamos o bean do Spring e chamamos os mtodos nele, em nenhum momento o cdigo cliente (o do teste do JUnit) soube que estava trabalhando com um objeto proxy, nem mesmo com um banco de dados e exatamente esse nvel de abstrao que ns estamos procurando. A gerncia de transaes continua no DAO? No nosso exemplo, o DAO se tornou um objeto transacional, mas nada impede que qualquer outro objeto torne-se transacional, o DAO foi escolhido apenas por simplicidade. Voc poderia ter, por exemplo, um objeto GerenciadorDeTransferncias com um mtodo parecido com o da listagem 13:Listagem 13 mtodo de transferncia de contas public void transferir (ContaCorrente sacado, ContaCorrente beneficiado, Double valor) { sacado.remover(valor); beneficiado.adicionar(valor); this.getGenericDao().update(sacado); this.getGenericDao().update(beneficiado); }

Grupo de Usurios Java http://www.guj.com.br Pgina 17

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

E claro que voc quer que ele execute todo dentro de uma nica transao, porque seno voc pode retirar dinheiro do sacado e no depositar no beneficiado, o que seria um grande problema pro seu banco e pro seu emprego tambm! Bastaria configurar o objeto GerenciadorDeTransfncias como um proxy, do mesmo jeito que foi configurado o daoGenericoTransacional, como ns vamos ver na listagem 14:Listagem 14 parte da configurao do Spring para o GerenciadorDeTransferncias transacional

PROPAGATION_REQUIRED, ISOLATION_SERIALIZABLE Como voc pode perceber, o caminho foi o mesmo, s que em vez de criar um proxy com base no DAO, ns criamos um proxy com base no GerenciadorDeTransferencias, alm disso, ns colocamos o DAO que no transacional no gerenciador, porque se ns colocssemos o transacional poderamos perder informaes (e voc perder o emprego =] ). No fim, voc deve escolher onde o seu controle de transaes deve ficar e voc tem toda a liberdade pra isso utilizando o Spring, pois apenas editando o arquivo de configurao dele voc pode mudar completamente o controle de transaes da sua aplicao, sem ter que recompilar nem uma linha de cdigo. Spring em aplicaes web Trabalhando com aplicaes web junto com o esquema de gerncia de transaes do Spring, voc tem ainda um filtro que mantm sempre uma sesso aberta para cada requisio as suas pginas JSP. Com essa sesso aberta voc evita problemas de carregamento de objetos e vai ter sempre uma sesso aberta para fazer o lazy-load dos seus objetos, evitando assim algumas das mais chatas excees lanadas pelo Hibernate, como LazyInitializationException (que acontece quando voc tenta acessar uma coleo ou objeto no carregado sem uma sesso aberta) e NonUniqueObjectException (que acontece quando voc adiciona o mesmo objeto duas vezes a mesma Session). O filtro o org.springframework.orm.hibernate3.support.OpenSessionInViewFilter, basta adicionar ele com filtro no seu web.xml para todas as pginas que precisem de uma sesso do Hibernate.

Cache de objetos no HibernateSempre que voc encontra algum falando mal de frameworks que facilitam trabalhar com bancos de dados (especialmente frameworks de mapeamento objeto/relacional (ORM Object/Relational Mapping) como o Hibernate) uma das principais crticas a performance da aplicao que usa essas ferramentas.

Grupo de Usurios Java http://www.guj.com.br Pgina 18

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

Realmente, a performance que pode ser conseguida com acesso direto via JDBC realmente maior se compararmos diretamente com a performance de uma aplicao que use um desses mecanismos. Mas claro que as ferramentas de ORM se preocupam com performance, uma das principais demonstraes disso que praticamente todas elas tem um esquema de cache de objetos, para evitar idas desnecessrias ao banco de dados. Os caches de objetos, quando bem montados, podem tornar a aplicao ainda mais rpida do que a mesma aplicao feita com JDBC, que dificilmente vai ser capaz de lidar com caches de objetos de maneira satisfatria (a no ser que alm de fazer a camada de persistncia na mo voc ainda v montar um esquema de cache, quando voc terminar tudo, ser que ainda vai ter prazo pra fazer a aplicao?). O Hibernate tem um sistema de cache automtico e no-desligvel, que o cache de primeiro nvel. O cache de primeiro nvel um cache relacionado a uma nica sesso (Session) do Hibernate, esse cache garante que voc vai acessar sempre os mesmos objetos dentro de uma nica sesso. Por exemplo, se voc fizer um load() em uma sesso passando o mesmo identificador e a mesma classe duas vezes o Hibernate deve retornar o mesmo objeto, isso garante que voc no vai trabalhar com objetos que tenham valores invlidos dentro de uma mesma sesso. Esse cache no tem nenhuma preocupao com performance, o seu objetivo garantir a integridade das informaes dentro de uma mesma Session. O outro sistema de cache, que opcional e o que ns vamos ver aqui, o cache de segundo nvel, que o cache de objetos do Hibernate. O cache de segundo nvel pode ser em cluster ou por SessionFactory (ou por processo). O que ns vamos ver aqui o cache por SessionFactory (tambm existe o cache de queries, mas no vamos v-lo neste artigo). Antes de comear a planejar o cache da sua aplicao voc deve levar algumas coisas em considerao e uma das mais importantes que se houverem outras aplicaes fazendo inseres e atualizaes no mesmo banco de dados que o Hibernate est conectado, melhor nem utilizar o cache, porque a outra aplicao pode atualizar informaes que podem no ser percebidas pelo Hibernate por elas estarem em cache. Outro porm se a sua aplicao tem mais inseres e atualizaes do que leituras, nesse caso o cache pode at mesmo diminuir a performance da aplicao. Pense bem antes de resolver que a sua aplicao precisa de um cache e escolha os objetos que devem ficar no cache, algumas indicaes sobre bons candidatos: Objetos que contm apenas meta-informao, como por exemplo um Caderno em um jornal, os cadernos normalmente simplesmente indicam qual o tipo do assunto abordado; Objetos pouco atualizados e lidos com muita freqncia. Mais um exemplo jornalstico so as notcias, voc no vai ver uma notcia ser atualizada vrias vezes depois que ela foi inserida (a no ser em casos bem especficos); Objetos onde a incoerncia de informaes no vai causar danos ao funcionamento da aplicao; Se voc tem objetos que so atualizados com muita freqncia ou onde muito importante que eles estejam sempre atualizados, no os coloque no cache, isso pode lhe dar muita dor de cabea. Esse cache mantm os objetos utilizados na memria ou em disco e extremamente simples de ser utilizado. No seu mapeamento, basta adicionar um novo n, o , como no nosso exemplo na listagem 15:Listagem 15 Exemplo de mapeamento com configurao de cache

Grupo de Usurios Java http://www.guj.com.br Pgina 19

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

A configurao do cache extremamente simples, voc indica o modo de utilizao (usage) e a regio onde os objetos vo ser encontrados (region). Uma regio um espao de cache que vai ser utilizado para guardar os objetos, voc pode ter todos os seus objetos em uma nica regio ou pode ter uma regio diferente para cada objeto que vai para o cache. O melhor trabalhar com uma regio para cara objeto, pois assim se voc precisar retirar todos os objetos de um certo tipo do seu cache, pode simplesmente fazer um evict() na regio onde ele est e todos os objetos vo ser retirados do cache.

Modos de utilizao do cache do HibernateOs modos de utilizao so a maneira pela qual o Hibernate vai controlar o acesso e o comportamento dos objetos que esto no cache, eles so definidos no atributo usage do elemento nos arquivos de mapeamento do Hibernate. Existem quatro tipos de modos de utilizao: - read-only utilizado quando a aplicao no atualiza as informaes, ela apenas as l; - read-write deve ser utilizado quando a aplicao faz atualizaes nos objetos que esto no cache, mas no deve ser utilizado se o nvel de isolamento das transaes for ISOLATION_SERIALIZABLE; - nonstrict-read-write deve ser utilizado quando a quantidade de atualizaes dos objetos pequena e quando pouco provvel que duas transaes vo tentar atualizar o mesmo objeto; - transactional s pode ser utilizado em um ambiente com suporte a JTA (como um servidor de aplicaes completo como o JBoss). Esse tipo de cache totalmente transacional e pode ser utilizado com qualquer nvel de isolamento das transaes. O nico cache suportado oficialmente pelo Hibernate 3.x o JBoss TreeCache; Na maioria das vezes voc vai trabalhar com os modos read-write ou nonstrict-readwrite, mas antes de definir isso, avalie o comportamento de transaes do seu sistema e as possibilidades de perda ou uso de informaes incorretas. Se voc encontrar problemas, melhor no usar o cache.

Para habilitar o cache na nossa aplicao, ns precisamos escolher uma implementao da interface CacheProvider e adicionar ela a configurao do Hibernate. Ns vamos utilizar a implementao EhCacheProvider que uma implementao no-clusterizvel da interface CacheProvider para o Hibernate (isso significa que ela funciona como cache de processo, mas no deveria ser utilizada em um ambiente de cluster). Para indicar isso, vamos adicionar uma linha na nossa configurao do Hibernate no Spring (ela tambm pode ser adicionada da mesma forma a configurao normal do Hibernate):org.hibernate.cache.EhCacheProvider

Essa configurao indica que ns vamos utilzar o EhCache como implementao de cache para a nossa aplicao. Agora que j indicamos qual a implementao, temos que definir as configuraes do EhCache para a nossa aplicao na listagem 16 (o arquivo deve se chamar ehcache.xml e estar na raiz do classpath da sua aplicao):Listagem 16 Exemplo de configurao do EhCache

Grupo de Usurios Java http://www.guj.com.br Pgina 20

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

O arquivo de configurao do EhCache tambm simples, o primeiro elemento, contm a localizao de onde deve ficar o arquivo que contm o cache (se algum objeto no for ser guardado na memria). Voc pode indicar um diretrio ou usar os apelidos: user.home indica o diretrio raiz do usurio; user.dir indica o diretrio corrente para aplicao; java.io.tmpdir indica o diretrio temporrio pra a mquina virtual; O segundo elemento, , indica as configuraes gerais para o cache na aplicao, ele s vai ser utilizado se o objeto enviado para o cache no estiver relacionado a nenhuma regio. Os atributos so: maxElementsInMemory a quantidade mxima de objetos que vo ficar em memria, alm disso, o cache comea a enviar os objetos para o disco (apenas se o valor de overflowToDisk for true); eternal indica se o conjunto eterno. Conjuntos eternos no levam e condio o tempo de vida nem o tempo se uso. Esse modo normalmente utilizado para objetos que tenham a utilizao no cache de read-write ou read-only. timeToIdleSecons indica a quantidade de segundos que um objeto pode passar no cache sem ser utilzado, aps o limite ele retirado; timeToLiveSeconds indica a quantidade de segundos que um objeto pode passar no cache, aps o limite ele retirado; overflowToDisk indica se os objetos devem ou no ser enviados para um arquivo no disco quando a quantidade mxima de objetos em memria for alcanada; O terceiro (e ltimo) elemento o , que contm as informaes especficas de cada regio de cache. Alm dos atributos de , esse elemento tambm contm o atributo name, que o nome da regio que identifica esse cache (no nosso exemplo ns demos o nome curso que o mesmo nome definido na regio do mapeamento da classe Curso).

Mais detalhesSites: Hibernate http://www.hibernate.org/ Spring http://www.springframework.org/ EhCahe - http://ehcache.sourceforge.net/ Referncias: Pro Spring. Harrop, Rob; Machacek, Jan. Editora Apress, 2005. Hibernate In Action. Bauer, Christian; King, Gavin. Editora Manning, 2004.

Grupo de Usurios Java http://www.guj.com.br Pgina 21

Grupo de Usurios GNU/Linux da Parabahttp://www.glugpb.org.br/

ConclusoAgora voc j sabe como montar uma camada de persistncia com o Hibernate, como integrar ele com o Spring e ainda como configurar o cache para aumentar ainda mais a performance da sua aplicao. O Hibernate continua sendo a ferramenta de mapeamento objeto/relacional mais utilizada na comunidade Java, mas sempre importante ficar de olhos abertos para as novidades do mercado. A especificao EJB 3.0 est praticamente pronta e segundo os seus defensores ela vai funcionar normalmente fora dos servidores de aplicao. Se a promessa se tornar realidade (o Hibernate j tem uma implementao da verso atual da implementao, o EntityManager) podemos esperar por uma verdadeira guerra entre os fornecedores de ferramentas para entrar no mercado e com essa concorrncia ns s temos a ganhar. Outro fator interessante a configurao do Hibernate atravs de annotations, que ainda est em fase de testes mas que em pouco tempo deve ser tornar uma maneira mais simples de se lidar com os quilos de configurao necessrios para se utilizar em uma aplicao com o Hibernate (e aplicaes Java em geral). Annotations ajudam mas continuam sendo apenas uma mudana de lugar para a configurao, que saiu dos arquivos XML e foi parar dentro do cdigo Java, trazendo mais uma complicao, que ter sempre que recompilar a aplicao quando mudanas ocorrerem, alm de ser mais complicado adicionar named queries em arquivos de classes, pois elas realmente misturam cdigo de acesso a banco de dados dentro das suas classes de modelo. O exagero e o cansao dos desenvolvedores com a edio de tantos arquivos XML to grande que novos frameworks simplesmente aboliram o uso de configurao e buscam informaes do prprio cdigo e organizao da aplicao, o movimento de conveno sobre configurao que est tomando invadindo os desenvolvedores cansados com tantos arquivos para manter. Vamos esperar que esse movimento realmente cresa na comunidade Java pra podermos diminuir a quantidade de configurao e nos preocuparmos mais com o que as aplicaes devem realmente fazer.Maurcio Linhares de Arago Junior ([email protected]) graduando em Desenvolvimento de Software para Internet no CEFET-PB e Comunicao Social (habilitao Jornalismo) na UFPB. membro do Paraba Java Users Group (PBJUG), do Grupo de Usurios GNU/Linux da Paraba (GLUG-PB) e moderador dos fruns do Grupo de Usurios Java (GUJ).

Grupo de Usurios Java http://www.guj.com.br Pgina 22