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!

Hanneli Tavante

Mais sobre o autor

Tags: , ,

15 Respostas para “As novidades do Hibernate 4”

  1. Rogério Megna

    07. fev, 2012

    Ótimo post! parabéns!

  2. Jean Fernandes

    07. fev, 2012

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

  3. André Moriya

    07. fev, 2012

    otima materia….
    era disso que estava precisando
    parabens

  4. 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.

  5. 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?

  6. 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.

  7. É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.

  8. 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 :(

  9. É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.

  10. 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!

  11. Felipe Saab

    15. fev, 2012

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

  12. 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 ?

  13. 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.

  14. jaabax

    05. jun, 2012

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

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

Deixar uma Resposta