As novidades do Hibernate 4
Postado em 07. fev, 2012 por Hanneli Tavante em Java
Um dos mais badalados frameworks de ORM no mundo Java (e popular também no .NET), o Hibernate recentemente ganhou sua versão 4.0 Final, que chega para arrebentar de novidades. O framework surgiu em 2001, por iniciativa de Gavin King, e logo se tornou amplamente utilizado devido a uma grande diversidade de recursos para mapeamento objeto relacional. Com a especificação da JPA (Java Persistence API), solidificou-se como a implementação mais utilizada. Diversos projetos também passaram a ser desenvolvidos pela equipe do Hibernate a fim de aprimorar os recursos existentes no framework. Muitos deles, em vez de serem anexados ao projeto Core, tornaram-se plugins, tais como Hibernate Search, o Hibernate OGM e o Hibernate Validator. Este último, inclusive, teve fortes influências para a criação de uma nova especificação, a Bean Validation (JSR 303).
A partir da versão 3.5, o Hibernate tornou-se uma implementação certificada para a JPA2 (JSR 317), lançada oficialmente no final de 2009. Várias annotations surgiram e muitos recursos foram aprimorados. Em dezembro de 2011, a versão 4.0 Final veio à tona, trazendo algumas importantes novidades que gostaríamos de destacar:
Redesign da SessionFactory
Possivelmente essa é uma das grandes mudanças no Hibernate 4. Estávamos habituados a obter uma SessionFactory da seguinte forma:
private static final SessionFactory sessionFactory =
new Configuration().configure().buildSessionFactory();
Entretanto, agora o método buildSessionFactory() está listado como deprecated, bem como as classes de Configuration: org.hibernate.cfg.Configuration e AnnotationConfiguration. A nova forma de se obter uma SessionFactory é através do ServiceRegistry, que explicaremos adiante, lançado para esta versão 4:
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.configure().buildServiceRegistry();
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addResource("algum.hbm.xml")
.addAnnotatedClass(SuaEntidade.class);
Metadata metadata = metadataSources.buildMetadata();
SessionFactory sessionFactory = metadata.buildSessionFactory();
Para que possamos obter uma SessionFactory, precisamos de um ServiceRegistry, seguido de um MetadataSources (eventualmente podemos adicionar recursos, classes anotadas, entre outros, de forma similar ao Configuration); a partir deste obtemos um Metadata e então finalmente conseguimos uma SessionFactory.
Para obter uma EntityManagerFactory nada muda, podemos usufruir da classe javax.persistence.Persistence.
ServiceRegistry
Uma nova forma foi implementada para que o Hibernate gerencie seus serviços. Services são classes que fornecem ao Hibernate diversos tipos de funcionalidades, tais como ClassLoader, conexão com o banco (ConnectionProvider), descoberta de dialetos apropriados, entre outros. Você deve estar se perguntando por que isso é um ponto interessante. O fato chave é que agora todos os serviços possuem uma interface. Caso queira, você pode mudar a forma com que o Hibernate realiza algumas funcionalidades de uma maneira muito simples, apenas fazendo com que suas classes implementem a interface de serviço do Hibernate. É uma forma de desacoplar seu código interno e se tornar mais maleável.
Suporte a Multi-Tenancy
Para que não conhece o termo, aí vai um pequeno resumo – em um modelo multi-tenant, é possível compartilhar os mesmos recursos físicos para clientes/empresas diferentes, mas ao mesmo tempo permite-se que fiquem logicamente isolados. A frase anterior pode parecer abstrata, então imagine diversas aplicações de e-commerce. Muitas delas possuem um core muito similar e diferem apenas em questões de layout e UI. Imagine então que fosse criada uma base de código igual para todas essas lógicas de e-commerce e apenas o design de cada loja diferente fosse mudado; cada uma delas teria seu próprio namespace e um endereço na web; contudo a base de código seria a mesma. Esses websites de lojas de e-commerce seriam cada um, um tenant.
Podemos implementar o Multi-Tenancy de algumas formas: Instâncias de bancos separadas (cada tenant possui sua prórpia instância de banco); Schema separados (os tenants compartilham o mesmo banco físico, entretanto cada um deles possui um schema); e também podemos implementar o Multi-Tenancy através de Particionamento (usamos o mesmo banco físico e o mesmo Schema), onde os tenants são particionados de acordo com algum discriminator value (uma chave que apareceria em toda as tabelas) e uma única tabela guarda os dados de cada um deles. O Hibernate 4 dá suporte a esta última opção de maneira fácil. Para este caso, tomemos como exemplo uma tabela no banco denominada Cliente:
CLIENTE ( ID BIGINT, NOME VARCHAR, ... TENANT_ID VARCHAR (ou uma chave estrangeira) )
Note que precisamos do campo TENANT_ID, pois ele define a qual tenant nos referimos. Em um exemplo real, esse ID vai dizer a qual loja pertence determinado produto, por exemplo. Essa abordagem via Particionamento ainda dá suporte a cache de segundo nível.
Mas será que sempre precisaremos nos lembrar de criar um TENANT_ID em nossas tabelas? Como poderíamos ter algo como:
CLIENTE ( ID BIGINT, NOME VARCHAR, ... )
sem termos um TENANT_ID? Poderíamos ter schemas separados e criarmos uma SessionFactory para cada tenant. Entretanto, isso seria inviável se tivéssemos muitos tenants, pois muitas SessionFactories podem ser extremamente custosas para a memória. Uma outra ideia seria utilizarmos uma abordagem conhecida como application-supplied connections, onde abrimos uma Session em cada SessionFactory através de uma Connection específica que fornecemos. Podemos dizer ao Hibernate qual Connection utilizar em cada contexto. Lembra-se de quando explicamos o ServiceRegistry? Um dos Services, é o ConnectionProvider. Separando os schemas evitamos a necessidade de um TENANT_ID em cada tabela, mas perdemos a possibilidade de usar o cache de segundo nível de maneira fácil, além de ser mais trabalhoso realizar relatórios e estatísticas com mais de um cliente.
O Hibernate 4 fornece essas alternativas básicas para o cenário multi-tenant, de forma quase transparente.
Usando o Hibernate 4
Quer ver o Hibernate 4 em ação? A maneira mais fácil de colocá-lo em seu projeto é através do Maven:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.6-Final</version>
</dependency>
Se você utiliza alguma outra ferramenta de build, aqui você encontra todas as dependências necessárias declaradas para Ivy, Gradle, SBT, entre outros.
Você também pode baixar os jars necessários para usá-los diretamente. Caso você use o JBoss AS 7 (conheça mais sobre essa nova versão do servidor), a versão 7.1 (ainda em Beta) já vem com o Hibernate 4 Final. Se você preferir o cloud, pode experimentar o Hibernate 4 no Openshift (aqui há um tutorial no blog da Caelum).
Gostou? Há muito mais nos links abaixo:
Webinar de Hibernate 4 – link
Hibernate 4 – post oficial do in.relation.to
Multi-Tenancy – mais informações (tutorial introdutório)
Multi-Tenancy e Hibernate 4 – Perguntas e Respostas
Também não deixe de visitar os vários posts da Caelum sobre Hibernate, inclusive o conhecido 7 hábitos dos desenvolvedores Hibernate e JPA altamente eficazes. Esperamos você no nosso curso de Hibernate e JPA!
ASSINE NOSSO RSS
Rogério Megna
07. fev, 2012
Ótimo post! parabéns!
Jean Fernandes
07. fev, 2012
Gostei da materia, achei que teria mais mudanças do que as que apontou, mesmo assim ótimo post.
André Moriya
07. fev, 2012
otima materia….
era disso que estava precisando
parabens
Diego
08. fev, 2012
Espero uma materia sobre a integração do Hibernate 4 + Spring 3.1 usando anotações nas classes de dominio. Seria uma ótima abordagem sobre as diferenças.
renato
09. fev, 2012
eu queria saber o q eu coloco no arquivo xml q esta pedindo no codigo dado de exemplo:
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.configure().buildServiceRegistry();
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addResource(“algum.hbm.xml”)
.addAnnotatedClass(SuaEntidade.class);
Metadata metadata = metadataSources.buildMetadata();
SessionFactory sessionFactory = metadata.buildSessionFactory();
Na parte metadataSources.addResource(“algum.hbm.xml”) o q é este xml?? onde eu acho ele? o q tem nele?
Hanneli Tavante
09. fev, 2012
Olá, Renato! Este xml não é mndatório. XMLs de hbm consistem apenas em arquivos de mapeamento específico. Você pode te-los ou não; aplicações mais antigas usando Hibernate puro às vezes tem.
Édion Torres
11. fev, 2012
Boa noite.
Só complementando o questionamento do Renato esse hmb contém as configurações para mapeamento da sua classe. Pode-se utilizar tanto arquivos hmb ou anotações nas próprias classes.
Uma observaçõa é que na documentação do hibernate 4 na seção 1.1.6. Startup and helpers ainda indica a configuração antiga.
Quem seguir a documentação oficial para começar com hibernate 4 vai ter problemas.
Paulo Silveira
12. fev, 2012
Édlon, a documentação dessa versão realmente deixa a desejar. Na parte de multi tenancy praticamente não há nada documentado
Édion Torres
12. fev, 2012
Verdade. Inclusive o exemplo utilizado no blog não vai funcionar. MetadataSources e Metadata estão em desenvolvimento e o pessoal que mantém não indica para utilização nesse momento.
Quem precisar pode utilizar:
public class HibernateUtil { private static SessionFactory sessionFactory; private static ServiceRegistry serviceRegistry; private static SessionFactory configureSessionFactory() throws HibernateException { Configuration configuration = new Configuration(); configuration.configure(); serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); return sessionFactory; } public static SessionFactory getSessionFactory() { return configureSessionFactory(); } }Registrando os hbms ou indicando as classes anotadas no hibernate.cfg.xml
Abraço.
Hanneli Tavante
12. fev, 2012
Oi Édion! Realmente, como o Paulo disse, a documentação está ruim! Isso atrapalha bastante a nossa vida!
Muito bacana essa outra solução, tinha visto algo parecido no StackOverflow
Veja que nessa thread já tem muita gente reclamando da documentação!
Sobre o MetadataSources, ele já está estável na versão 4.0 final! Eventualmente funciona; o único caso que vi no StackOverflow que pode dar problemas é quando você tiver um – Veja este link
Pelo que entendi vendo o fórum e a lista de issues do Hibernate 4 é que não usar o MetadataSources e usar o configuration será uma solução provisória. Veja esta issue
Ou seja, eles colocaram Configuration como deprecated (no Alpha – https://hibernate.onjira.com/browse/HHH-6183 ), voltaram pra não-deprecated e pretendem colocá-la como deprecated novamente (https://hibernate.onjira.com/browse/HHH-6586 – veja o comentário “Remove deprecation from Configuration until after new metamodel completely in place”). Meio confuso, né? Espero que no 4.1 as coisas melhores na documentação!
Felipe Saab
15. fev, 2012
Multi-Tenancy default no hibernate agora! Show!!!
Dennys
21. fev, 2012
O código disponibilizado pelo amigo Édion Torres caiu como uma luva, porém “aparentemente” o Cache de Segundo Nível (ehcache-2.5.1) não esta compatível com o Hibernate 4.
Ao tentar acessar a aplicação ocorre a mensagem de erro:
Second-level cache is not enabled for usage [hibernate.cache.use_second_level_cache | hibernate.cache.use_query_cache]
Os parâmetros acima estão marcados como true no hibernate.cfg.xml e só funcionam se coloco como false.
Alguém teria uma solução rápida ?
Vinicius Roberto
29. mai, 2012
Eu também só encontrei a documentação para a versão antiga. Gostaria de saber se existe um meio de configurar o Hibernate, iniciando da forma do post, sem utilizar o XML, hibernate.cfg.xml.
jaabax
05. jun, 2012
e sobre multitenancy com bases de dados diferentes? nao curto multitenancy usando uma coluna para separar as coisas
Edivando
20. jun, 2012
Estou apreendendo sobre hibernate, mas não esta funcionado aqui. Não estou encontrado esse método recebendo um serviceRegistry.
configuration.buildSessionFactory(serviceRegistry);
Sé tem esse método:
configuration.buildSessionFactory();