Esse artigo faz parte da revista Java Magazine edição 28. Clique aqui para ler todos os artigos desta edição

AN style="FONT-SIZE: 10pt; BACKGROUND: white; COLOR: red; FONT-FAMILY: Verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial">

Atenção: por essa edição ser muito antiga não há arquivo PDF para download.Os artigos dessa edição estão disponíveis somente através do formato HTML.

Java Livre

Persistência com Hibernate

Conhecendo o Mais Popular Framework O/R

Aprenda a escrever aplicações eficientes baseadas no Hibernate: conceitos, mapeamentos comuns, HQL e técnicas para agilizar o acesso a dados

 

O Hibernate está se tornando o framework de persistência objeto-relacional preferido do desenvolvedor Java. Em sua terceira geração (o que para um projeto open source significa um nível de evolução e maturidade que poucos softwares, mesmo proprietários, conseguem atingir) ele é talvez o framework de persistência mais flexível e poderoso d mercado – e seus recursos serviriam de inspiração para as novas especificações EJB 3.0 e JDO 2.0 do JCP. Este artigo apresenta os primeiros passos na construção de aplicações com o Hibernate.

 

Elementos

Antes de falar do Hibernate em si, vale a pena conhecer alguns conceitos e alternativas á persistência objeto-relacional – veja o quadro “Persistência de objetos e bancos relacionados”.

Todo framework de persistência de objetos tem três componentes principais:

• Uma descrição do mapeamento entre o modelo de objetos em memória e seu correspondente em disco (no caso, tabelas de um banco relacional).

• Uma API para armazenamento e recuperação de objetos persistentes.

• Uma linguagem de consultas que permite determinar o subconjunto dos objetos persistentes que devem ser trazidos para a memória.

 

Daqui para frente apresentaremos como estes três componentes funcionam no Hibernate, e depois como compilar e executar uma aplicação baseada nesse framework.

Para manter o foco no framework, todos os exemplos serão aplicações de linha de comando, sem interfaces gráficas sofisticadas. É importante também destacar que a maioria das operações e configurações no Hibernate pode ser feita de diversas formas diferentes, o que permite que o framework seja utilizado na maior variedade possível de situações e seja adaptável aos ambientes mais diversos. Aqui não vamos explorar todas as variações possíveis, mas sim fornecer uma base segura para o leitor iniciar o seu aprendizado e obter resultados rápidos com o framework.

 

Começando o mapeamento O/R

Iniciamos com um modelo de objetos simples, apresentado na Figura 1. Este modelo seria parte de uma aplicação de cadastro de clientes numa empresa de comércio. Os clientes são agrupados em categorias para, por exemplo, receberam tratamento diferenciado em termos de promoções, parcelamento de compras e descontos sobre compras em volume.

 

Figura 1. Modelo de objetos das aplicações de exemplo

 

Observe que normalmente não seria representada a associação de composição entre Cliente e Endereço, pois conceitualmente um Endereço é apenas uma informação sobre um cliente, como nome ou sexo. Mas aqui essa composição foi deixada explícita, para fins de demonstração. Note também que há na classe Cliente um atributo telefones, que é uma coleção, pois cada cliente pode ter vários telefones cadastrados.

O modelo apresentado foi escolhido como exemplo porque expõe duas limitações do modelo relacional: a incapacidade de expressar atributos complexos (objetos com seus próprios atributos, em vez de valores simples) e atributos multivalorados. A representação natural deste modelo de objetos em Java é apresentado na Listagem 1, onde são definidas as classes Cliente, Categoria e Endereço.

Embora não seja obrigatório, recomenda-se seguir o padrão de JavaBeans na definição dos objetos persistentes (ou seja, usar métodos de acesso get/set para os atributos, definir um construtor sem argumentos e tornar todas as classes serializáveis).

A classe Endereço em si não é persistente, pois nunca serão armazenados endereços “soltos”; mas os dados dos endereços o serão, em decorrência do seu vínculo com Cliente. Num modelo relacional, nosso atributo endereço tem que ser “aberto” ou “achatado” (flattened), colocando-se seus atributos na própria tabela de clientes. E o atributo telefone teria que ser transformado ou em uma outra tabela, ou em vários campos no estilo “telefonei”, “telefone2” etc. Optamos pela primeira alternativa. O modelo relacional adotado para o exemplo é apresentado na Figura 2.

 

Figura 2. Modelo relacional para a aplicação de exemplo

 

Os três tipos fundamentais de coleção do J2SE, Listas (List), conjuntas (Set) e mapas (Map), têm características bem diferentes, e o Hibernate é capaz de preservar estas características quando os objetos são salvos e recuperados no banco de dados. Para simplificar, utilizaremos apenas conjuntos (Set), porque, para o nosso sistema, não faz diferença qual é o “primeiro” telefone, nem em que ordem serão recuperados os clientes de uma dada categoria (em todo caso, podemos usar depois a cláusula order by da linguagem HQL, como será visto adiante). Se a ordenação dos elementos for importante para a sua aplicação, deve ser utilizada uma lista (List), e o modelo relacional correspondente necessitará de colunas extras para armazenar a posição de cada elemento na lista.

Como um modelo de objetos é semanticamente mais rico do que um modelo relacional, ou seja, como ele oferece maior variedade de tipos e associações, em muitos casos não será possível gerar automaticamente um modelo relacional otimizado. Então, o mapeamento escolhido irá depender da experiência e gosto do desenvolvedor. Haverá também casos onde não haverá escolha alguma, por exemplo, quando o modelo relacional é parte de um sistema legado que continua em produção.

Aqui a dica é tentar não se influenciar pelo banco de dados legado ao construir uma nova aplicação OO que acesse os mesmos dados. Você pode construir um modelo de objetos do zero, e confiar que será possível com o Hibernate mapeá-lo para o banco legado. Fazer o contrário (gerar um modelo de objetos a partir de um modelo relacional já existente) em geral leva a um modelo de objetos de baixa qualidade, que acaba por prejudicar a manutenção e evolução da aplicação. Apenas em último caso “adapte” seu modelo de objetos ao banco de dados legado.

 

Listagem 1. Classes do modelo de objetos da aplicação

 

jm28/Categoria.Java

 

//...

public class Categoria implements serializable {

    private Long id;

    private String nome;

    private Float desconto;

    private Integer parcelas;

    private Set<Cliente> clients = new HashSet<Cliente>( );

    //… construtor vazio e métodos get/set

}

 

jm28/Endereço.Java

 

//...

public class Endereço implements Serializable {

    private String logradouro;

    private Interger numero;

    private String complemento;

    private String bairro;

    private String municipio;

    //… construtor vazio e métodos get/set

}

 

jm28/Cliente.Java

 

//...

public class Cliente implements Serializable {

    private Long id;

    private String nome;

    private String email;

    private Character sexo;

    private Endereco endereco;

    private Set<String> telephones = new HashSet<String>( );

    private Categoria categoria;

    //... construtor vazio e métodos get/set

}

 

A descrição do mapeamento

Já apresentamos o modelo de classes e o modelo relacional utilizado nos exemplos; resta apresentar a descrição que mapeia um modelo para o outro, na sintaxe do Hibernate. Para isso, são usados arquivos XML, apresentados na Listagem 2.

 

üEmbora seja possível definir o mapeamento para várias classes num único XML, recomenda-se que cada classe tenha seu próprio arquivo de mapeamento. Isso facilita futuras expansões no modelo, como a inclusão de novas classes.

 

Neste e nos próximos subtópicos vamos descrever esses três arquivos de mapeamento e os principais conceitos relacionados. Começamos pela classe Categoria que é a mais simples de mapear.

 

Um arquivo de mapeamento tem que iniciar por um elemento XML <hibernate-mapping>. Dentro dele pode haver diversos elementos <class> ...

Quer ler esse conteúdo completo? Tenha acesso completo