As novidades do Hibernate 4

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!

20 Comentários

  1. Rogério Megna 07/02/2012 at 11:51 #

    Ótimo post! parabéns!

  2. Jean Fernandes 07/02/2012 at 14:21 #

    Gostei da materia, achei que teria mais mudanças do que as que apontou, mesmo assim ótimo post.

  3. André Moriya 07/02/2012 at 19:24 #

    otima materia….
    era disso que estava precisando
    parabens

  4. Diego 08/02/2012 at 11:12 #

    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.

  5. renato 09/02/2012 at 13:58 #

    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?

  6. Hanneli Tavante 09/02/2012 at 14:14 #

    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.

  7. Édion Torres 11/02/2012 at 22:51 #

    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.

  8. Paulo Silveira 12/02/2012 at 02:10 #

    Édlon, a documentação dessa versão realmente deixa a desejar. Na parte de multi tenancy praticamente não há nada documentado 🙁

  9. Édion Torres 12/02/2012 at 03:01 #

    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.

  10. Hanneli Tavante 12/02/2012 at 21:00 #

    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!

  11. Felipe Saab 15/02/2012 at 17:54 #

    Multi-Tenancy default no hibernate agora! Show!!!

  12. Dennys 21/02/2012 at 23:11 #

    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 ?

  13. Vinicius Roberto 29/05/2012 at 12:03 #

    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.

  14. jaabax 05/06/2012 at 23:47 #

    e sobre multitenancy com bases de dados diferentes? nao curto multitenancy usando uma coluna para separar as coisas

  15. Edivando 20/06/2012 at 20:55 #

    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();

  16. Adriano Braga 24/05/2013 at 15:34 #

    No exemplo acima foi utilizado mapeamento xml.
    E como ficaria sem usar xml, usando annotations sem xml?

  17. Verdade 11/06/2013 at 23:23 #

    Bom o suporte a multiplo tenório. Chupa JPA.

  18. Giordano Menezes 25/09/2013 at 23:36 #

    Só uma curiosidade sobre a solução do Edion Torres:

    Como o hibernate descobre o arquivo Hibernate.cfg.xml, uma vez que não citamos mais ele no novo HibernateUtil?

    Como entao ele é carregado?

Deixe uma resposta