Breve Introdução sobre Hibernate com Anotações

por:
 

Raphaela Galhardo (raphaela@jeebrasil.com.br)
Gleydson Lima (gleydson@jeebrasil.com.br)
 

Este artigo trata de uma introdução à utilização do framework Hibernate com anotações. Será apresentada uma breve introdução sobre anotações, bem como um exemplo simples de mapeamento objeto relacional com anotações Hibernate.

 

1. Introdução

Recentemente, o mapeamento objeto relacional utilizando Hibernate passou a ser feito também a partir de anotações, de forma que se tornou mais simples, possibilitando uma maior produtividade no desenvolvimento de aplicações.

As anotações podem ser definidas como metadados que aparecem no código fonte e são ignorados pelo compilador. Qualquer símbolo em um código Java que comece com uma @ (arroba) é uma anotação. Este recurso foi introduzido na linguagem Java a partir da versão Java SE 5.0. Em outras palavras, as anotações marcam partes de objetos de forma que tenham algum significado especial.

A Listagem 1 e a Listagem 2 apresentam exemplo de um tipo de anotação denominado de TesteAnotacao e do seu uso em um método qualquer (metodoTeste), respectivamente. O exemplo é meramente ilustrativo, de forma que o tipo de anotação definido não agrega nenhum significado especial ao código fonte.

public @interface TesteAnotacao{
	...
}

Listagem 1 – Exemplo ilustrativo para a criação de um tipo de anotação

@TesteAnotacao
public void metodoTeste{
	...
}

Listagem 2 – Exemplo ilustrativo para o uso de um tipo de anotação

Inicialmente, o mapeamento objeto relacional com Hibernate era feito a partir de um conjunto de configurações em arquivos XMLs. Com o surgimento das anotações no Java SE 5.0, o framework Hibernate anexou este recurso, permitindo que as classes Java fossem mapeadas a partir de anotações, simplificando o seu uso. A próxima seção apresentará um exemplo simples do uso da persistência de uma classe com Hibernate Annotations.

2. Exemplo Simples com Anotações Hibernate

Inicialmente, para que o Hibernate soubesse como carregar e armazenar objetos de classes persistentes, eram utilizados apenas arquivos de mapeamento XML. Dessa forma, era possível informar que tabela do banco de dados se refere uma dada classe persistente e quais colunas na tabela são referentes a quais atributos da classe. Com o surgimento das anotações no Java 5.0, tornou-se possível substituir os arquivos XML para o mapeamento objeto relacional. Através do uso de um conjunto de anotações no código fonte das classes mapeadas.

Neste primeiro exemplo, será apresentado como realizar o mapeamento objeto relacional da classe Aluno (Classe ilustrada na Figura 1) utilizando anotações. Dessa forma, informando ao Hibernate que tabela no banco de dados a representa e quais atributos correspondem as quais colunas desta tabela.

Figura 1 - Classe Aluno

A classe Java que representa a entidade Aluno está ilustrada na Listagem 3.

package br.com.jeebrasil.dominio;

public class Aluno {
	
	//Atributos da classe
	private int id;
	private int matricula;
	private String nome;
	private long cpf;
		
	//Construtor padrão
	public void Aluno(){}
	
	//Métodos getters e setters
	public long getCpf() { return cpf; }
	public void setCpf(long cpf) { this.cpf = cpf; }

	public int getId() { return id; }
	public void setId(int id) { this.id = id;	}

	public int getMatricula() { return matricula; }
	public void setMatricula(int matricula) {
		this.matricula = matricula;
	}
	
	public String getNome() { return nome; }
	public void setNome(String nome) { this.nome = nome; }	
}

Listagem 3 - Classe de Domínio: Aluno

Para os exemplos ilustrados neste material, a base de dados foi feita utilizando o PostgreSQL 8.2, que pode ser baixado no site www.posgresql.org. A classe Aluno foi mapeada para a tabela aluno presente no esquema anotacoes do banco criado denominado jeebrasil. O script para a criação da tabela aluno pode ser visto na Listagem 4.

CREATE TABLE anotacoes.aluno
(
  id_aluno integer NOT NULL, -- Identificador da tabela
  matricula integer NOT NULL, -- Matrícula do aluno
  nome character(40) NOT NULL, -- Nome do aluno
  cpf bigint NOT NULL, -- CPF do aluno
  CONSTRAINT pk_aluno PRIMARY KEY (id_aluno),
  CONSTRAINT un_cpf_aluno UNIQUE (cpf),
  CONSTRAINT un_matricula_aluno UNIQUE (matricula)
) 
WITHOUT OIDS;
ALTER TABLE anotacoes.aluno OWNER TO postgres;
COMMENT ON COLUMN anotacoes.aluno.id IS 'Identificador da tabela';
COMMENT ON COLUMN anotacoes.aluno.matricula IS 'Matrícula do aluno';
COMMENT ON COLUMN anotacoes.aluno.nome IS 'Nome do aluno';
COMMENT ON COLUMN anotacoes.aluno.cpf IS 'CPF do aluno';

Listagem 4 – Script para a criação da tabela aluno

Todas as classes persistentes mapeadas com anotações Hibernate são declaradas usando a anotação @Entity, aplicada em nível de classes, como mostrado na Listagem 5. Observa-se que com o uso de anotações, não há mais a necessidade de se utilizar arquivos de mapeamento XML adicionais.

Quando o nome da classe é diferente do nome da tabela para a qual é mapeada é necessário informar na anotação @Table qual o nome da tabela, usando o atributo name. No caso do mapeamento da classe Aluno, não havia a necessidade de se informar o nome da tabela, pois ela e a classe possuem o mesmo nome. Como a tabela pertence a um esquema do banco de dados (anotacoes), no mapeamento da classe, também é necessário informar em que esquema a tabela mapeada se encontra, utilizando o atributo schema da anotação @Table. No caso, a linha do código fonte @Table(name="aluno", schema="anotacoes") está informando o nome e o esquema da tabela para a qual está mapeada a classe aluno.

A chave primária da tabela é mapeada na classe através da anotação @Id. O valor atribuído à chave primária pode ser dado tanto pela aplicação quanto por um mecanismo do Hibernate que o gere automaticamente. A anotação @GeneratedValue permite a definição automática para o valor do identificador, utilizando um dos mecanismos de geração apresentados anteriormente. Neste caso, utilizou-se a estratégia a partir de uma seqüência, como feito na linha de código @GeneratedValue(strategy = GenerationType.SEQUENCE). Dessa forma, na hora de persistir uma linha na tabela aluno, o Hibernate vai pegar como valor para a chave primária o próximo valor disponível por uma seqüência padrão chamada hibernate_sequence. Deve-se salientar que o programador deverá criar uma seqüência com este nome na base de dados. Ainda em relação ao identificador, como o nome da coluna mapeada é diferente do nome do atributo, é necessário utilizar a anotação @Column informando o nome da coluna, através do atributo name. Neste exemplo, o nome da coluna mapeada para o identificador é id_aluno, mapeada da seguinte forma: @Column(name="id_aluno").

Observa-se que nos demais atributos da classe não há nenhuma anotação de mapeamento. Isso pode ser feito quando o nome do atributo é igual ao nome da coluna da tabela mapeada, de forma que não há a necessidade de mapeamento explícito.

Por fim, para se utilizar as anotações para mapeamento das classes, é preciso importá-las de algum lugar, neste caso do pacote javax.persistence, como mostrado no início do código fonte da Listagem 10.

package br.com.jeebrasil.hibernate.anotacoes.dominio;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

//Anotação que informa que a classe mapeada é persistente
@Entity
//Informando nome e esquema da tabela mapeada
@Table(name="aluno", schema="anotacoes")
public class Aluno {

	//Definição da chave primária
	@Id
	//Definição do mecanismo de definição da chave primária
	@GeneratedValue(strategy = GenerationType.SEQUENCE)
	//Informa o nome da coluna mapeada para o atributo
	@Column(name="id_aluno")	
	private int id;
	private int matricula;
	private String nome;
	private long cpf;
	
	public void Aluno(){}
		
	//Métodos getters e setters
	//...	
}

Listagem 10 – Mapeamento da classe Aluno com anotações

Depois de criar todas as classes persistentes com seus respectivos mapeamentos com anotacoes, deve-se realizar algumas configurações do Hibernate, mostradas na seção seguinte.

2.1 Configurando a Base de Dados

Para tudo funcionar corretamente, é necessário realizar algumas configurações da base de dados. Essas configurações podem ser feitas a partir de um arquivo XML, em geral, denominado hibernate.cfg.xml. A partir deste arquivo, é possível realizar algumas configurações relacionadas à base de dados, bem como informar as classes mapeadas com anotações que poderão ser persistidas a partir dos mecanismos do Hibernate.

A Listagem 6 apresenta um exemplo para o arquivo de mapeamento hibernate.cfg.xml, onde alguns parâmetros são configurados, como:

  • A URL de conexão com o banco de dados;
  • Usuário e senha do banco de dados;
  • Números máximo e mínimo de conexões no pool;
  • Dialeto
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC 
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">


    <session-factory>

      <!-- properties -->
      <property name="connection.driver_class">
          org.postgresql.Driver
      </property>
	<property name="connection.url">
          jdbc:postgresql://localhost:5432/jeebrasil
      </property>
      <property name="dialect">
            org.hibernate.dialect.PostgreSQLDialect
      </property>
      <property name="show_sql">true</property>
      <property name="connection.username">postgres</property>
      <property name="connection.password">postgres</property>
	<property name="connection.pool_size">10</property>
		
      <!-- mapping classes -->
	<mapping class="br.com.jeebrasil.hibernate.anotacoes.dominio.Aluno"/>

    </session-factory>
</hibernate-configuration>

Listagem 6 - Arquivo de Configuração hibernate.cfg.xml

Resumindo as descrições das propriedades configuradas no arquivo hibernate.cfg.xml:

  • hibernate.dialect: implementação do dialeto SQL específico do banco de dados a ser utilizado. Usado para identificar as particularidades do banco de dados;
  • hibernate.connection.driver_class: nome da classe do driver JDBC do banco de dados que está sendo utilizado;
  • hibernate.connection.url: é a URL de conexão específica do banco que está sendo utilizado;
  • hibernate.connection.username: é o nome de usuário com o qual o Hibernate deve se conectar ao banco;
  • hibernate.connection.password: é a senha do usuário com o qual o Hibernate deve se conectar ao banco;
  • hibernate.connection.pool_size: tamanho do pool de conexões;
  • hibernate.connection.isolation: define o nível de isolamento. Parâmetro opcional;
  • hibernate.show_sql: utilizado para definir se os SQL’s gerados pelo Hibernate devem ou não ser exibidos (true | false).

Já no final do arquivo hibernate.cfg.xml é onde devem ser informados os arquivos das classes mapeadas que o Hibernate deve processar. Se alguma classe não for definida neste local, a mesma não poderá ser persistida utilizando os mecanismos do Hibernate.

Para este exemplo, apenas uma classe foi mapeada. Se existissem outras classes persistentes, as mesmas deveriam ter linhas semelhantes a , informando o seu nome para que possam ser persistidas através do Hibernate.

3. Exemplo de Persistência

O Hibernate utiliza objetos Session para persistir e recuperar objetos. Um objeto Session pode ser considerado como uma sessão de comunicação com o banco de dados através de uma conexão JDBC.

O código fonte exibido na Listagem 7 mostra a criação e persistência de um objeto do tipo Aluno.

...
1. try{
2.   //SessionFactory deve ser criado uma única vez durante a execução
3    //da aplicação
4    SessionFactory sf = new  AnnotationConfiguration()
5.    .configure(
6.	"/br/com/jeebrasil/hibernate/anotacoes/conf/hibernate.cfg.xml")
7.       .buildSessionFactory();
8.
9.    Session session = sf.openSession(); //Abre sessão
10.   Transaction tx = session.beginTransaction(); //Cria transação
11.
12.   //Cria objeto Aluno
13.   Aluno aluno = new Aluno();
14.   aluno.setNome("Raphaela Galhardo Fernandes");
15.   aluno.setMatricula(200027803);
16.   aluno.setCpf(1234567898);
17.   session.save(aluno); //Realiza persistência
18.   tx.commit(); //Fecha transação
19.   session.close(); //Fecha sessão
20
21. }catch(HibernateException e1){
22. 	e1.printStackTrace();
23. }catch(SQLException e2){
24.   e2.printStackTrace();
25. }

Listagem 7 - Exemplo de Persistência da Classe Aluno

O código presente nas linhas 4-7 deve ser chamado uma única vez durante a execução da aplicação. O objeto SessionFactory armazena os mapeamentos e configurações do Hibernate. É um objeto pesado e lento de se criar.

A Tabela 1 apresenta alguns dos métodos que podem ser invocados a partir do objeto Session.

save(Object) Inclui um objeto em uma tabela do banco de dados.
saveOrUpdate(Object) Inclui um objeto na tabela caso ele ainda não exista (seja transiente) ou atualiza o objeto caso ele já exista (seja persistente).
delete(Object) Apaga um objeto da tabela no banco de dados.
get(Class, Serializable id) Retorna um objeto a partir de sua chave primária. A classe do objeto é passada como primeiro argumento e o seu identificador como segundo argumento.

Tabela 1 - Métodos invocados a partir do objeto Session

As Listagem 8 e Listagem 9 apresentam exemplos dos métodos invocados a partir do objeto Session.

...
   Session session = sf.openSession();
   Transaction tx = session.beginTransaction(); 

   //Busca objeto aluno da base de dados com chave primária = 1
   Aluno aluno = (Aluno) session.get(Aluno.class, 1);   
   //Atualiza informação de matrícula.      
   aluno.setMatricula(200027807); 
   //Como o identificador do objeto aluno é diferente de 0,
   //a sua matrícula é atualizada já que foi alterada 
   session.saveOrUpdate(aluno); 
   tx.commit();
   session.close(); 
...

Listagem 8 - Exemplo de Busca e Atualização de um Objeto Aluno

...
   Session session = sf.openSession();
   Transaction tx = session.beginTransaction();
   
   Aluno aluno = new Aluno();
   //Existe linha na tabela aluno com chave primária = 2
   aluno.setId(2);   
   //Deleta aluno com id = 2 da tabela. 
   //Somente necessária informação do seu identificador
   session.delete (aluno); 

   tx.comiit();
   session.close(); 
...

Listagem 9 - Exemplo de Remoção de Objeto Aluno

4. Conclusões

Com este artigo, procurou-se passar uma breve introdução sobre a utilização do framework Hibernate utilizando anotações. As anotações surgiram melhorando o desenvolvimento das aplicações com Hibernate, considerando uma melhora de produtividade no que dizia respeito a uso de arquivos XML’s para a realização do mapeamento objeto relacional. Lembrando que o uso de anotações apenas provocou o surgimento de uma nova sintaxe para o mapeamento objeto relacional com Hibernate. Não houve adição de novos recursos ao framework, apenas unificou-se as configurações nas classes Java.

 

Free Web Hosting