Você está na página 1de 13

JPA com Hibernate

Rascunho
Autor:Ivan Salvadori

1. Introduo ao JPA com Hibernate.


JPA ou Java Persistence API, uma padronizao da linguagem Java, para mapeamento
objeto/relacional. Em outras palavras, a padronizao de um mecanismo capaz de armazenar no
banco de dados as classes do modelo da aplicao que necessitam de persistncia. Este mecanismo
visa promover todos os recursos de banco de dados, sem a necessidade de manipulao direta de
instrues SQL.
Hibernate um framework que implementa a especificao do JPA. o verdadeiro
responsvel pela execuo do mecanismo de persistncia de dados. JPA define as regras enquanto o
Hibernate as executa. Existem vrias outras implementaes do JPA, como o TopLink da Oracle.
Essas implementaes so tambm so chamadas de Provider, ( Provedor ).
Para mostrar realmente o objetivo do JPA, imagine o seguinte cenrio:
Desejo gravar no banco de dados informaes de cadastros dos meus clientes.

Ilustrao 1: Classe Cliente.

A forma tradicional de manipulao de banco de dados em Java trabalha diretamente com


criao de conexes, elaborao de instrues SQL, atribuio de valores a estas instrues seguido
da execuo das querys.
Para inserir um cliente, uma classe responsvel pela manipulao do banco, geralmente um
DAO, recebe o objeto do tipo Cliente, com as informaes desejadas j definidas no objeto. De
posse desse objeto, as informaes so extradas atravs dos mtodos getter's, e inseridas na
instruo SQL de INSERT.
String comando = "insert into Cliente (nome, cpf, rg, telefone ,data_nasc)
values (?, ?, ?, ?, ?)";

Ilustrao 2: Mecanismo Tradicional de Gravao.

O trecho de cdigo abaixo mostra a forma tradicional de gravao de informaes dos


clientes no banco de dados MySql.
java.sql.Connection con;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/base", "user","senha");
} catch(SQLException e) {
throw new RuntimeException(e);
}
String comando = "insert into Cliente (nome, data_nasc, telefone, rg, cpf)
values (?,?,?,?,?)";
PreparedStatement stmt;
try {
stmt = con.prepareStatement(comando);
stmt.setString(1, cliente.getNome() );
stmt.setDate(2, new
java.sql.Date(cliente.getDataNasc().getTime() ) ); //formata data para sql
stmt.setString(3, cliente.getTelefone() );
stmt.setString(4, cliente.getRg() );
stmt.setString(5, cliente.getCpf() );
stmt.execute();
stmt.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}

Para listar os clientes gravados o banco, executa-se um instruo SQL SELECT, com os
dados obtidos do banco construdo um objeto do tipo Cliente, e definido as suas propriedades
atravs dos mtodos setter's.
PreparedStatement stmt = con.prepareStatement("select * from Cliente");

Ilustrao 3: Mecanismo Tradicional de Seleo.

while (rs.next()) {
Cliente c = new Cliente();
c.setCodigo(rs.getInt("codigo"));
c.setNome(rs.getString("nome"));
c.setRg(rs.getString("rg"));
c.setCpf(rs.getString("cpf"));
c.setTelefone(rs.getString("telefone"));
c.setDataNasc( rs.getDate("data_nasc")
);
}

Analisando os mecanismos e cdigos ilustrados anteriormente, nota-se que para implementar um


sistema de mdio a grande porte, uma esforo consideravelmente grande se faz necessrio para
tratar os assuntos de manipulao do banco de dados, observa-se tambm que as classes com essas
responsabilidades so extensas, qualquer alterao no banco de dados implica em manuteno do
cdigo.
JPA se propem a facilitar esse trabalho, abstraindo os detalhes do banco de dados e
concentrando-se nas suas funes. Imagine agora gravar o mesmo objeto cliente citado no esquema
anterior, mas agora sem se preocupar com os detalhes fsicos da tabelas, nome dos campos,
converses de tipos dentre outros detalhes. O trecho de cdigo abaixo mostra como seria o processo
de gravao no banco de dados utilizando o JPA com Hibernate.
public void gravar(Cliente cliente) {
hibernate.gravar(cliente);
}

Mecanismo de procura por um determinado cliente a partir do seu cdigo:


public Cliente procurar(int codigo) {
return hibernate.procurar(Cliente.class, codigo);
}

Lembrando que os cdigos acima apenas demonstram a filosofia do mecanismo utilizado


pelo JPA, em um caso real, um pouco mais de cdigo necessrio.
Com os exemplos anteriores, pode-se notar que toda a implementao da persistncia dos
dados fica sob responsabilidade do FrameWork, retirando toda a manipulao direta com o banco
de dados. Caso alguma alterao seja feita na classe Cliente, que consequentemente provoque
alguma alterao na tabela que armazena seus dados, nenhum cdigo sofrer alterao, diminuindo
muito o custo de manuteno. Isso possvel pois o JPA com Hibernate representa uma camada
extra entre a aplicao e o JDBC, at ento programado diretamente pelo desenvolvedor.
Aplicao
JPA
Hibernate
JDBC

Banco de Dados
Ilustrao 4: Estrutura JPA Hibernate . Adaptado de Bellia, Renato.
Revista Java Magazine, ed. 44, p. 28.

JPA nos possibilita desenvolver toda a persistncia com o mnimo de cdigo possvel atravs
de uma forma fantstica, mas como possvel realizar essa facilidade? Ser o Assunto dos
prximos captulos.

2. Entendendo o Framework.
Segundo FLVIO HENRIQUE CURTE, Antares Information Systems:
A ideia da persistncia O/R reunir as vantagens de se utilizar um modelo orientado a
objetos para a construo de uma aplicao, com a performance e a confiabilidade dos bancos de
dados relacionais. (adaptado de JPA: Persistncia padronizada em Java).
O modelo orientado a objetos nos d muito mais recursos para a representao da
informao, fica muito mais fcil de entender e principalmente desenvolver software fazendo uso
do paradigma dos objetos, por outro lado, o modelo relacional excelente para armazenamento
fsico das informaes. Criou-se ai um empasse, sendo necessrio uma especie de traduo entre um
modelo para o outro. A introduo desse material exemplificou a forma que essa traduo
realizada via JDBC. A Especificao JPA possibilita trabalhar com o modelo relacional dos bancos
de dados, com a representao do modelo orientado a objetos. Observe o cdigo a seguir:

public void gravar(Cliente cliente) {


hibernate.gravar(cliente);

}
Como possvel o framework Hibernate realizar a gravao das informaes do objeto
cliente no banco de dados?
Para que isso seja possvel, o Hibernate deve ter conhecimento das informaes do objeto
cliente, assim como conhecer os detalhes do banco de dados. necessrio o conhecimento do
contedo das tabelas dentre outras informaes ligadas ao projeto relacional.
Vamos recorrer ao nosso problema de cadastro de clientes, temos a nossa Classe Cliente que
deve ter as suas propriedades gravadas. A tabela Cliente da suporte para a gravao de todas as
informaes da classe. Dessa forma a classe cliente ser armazenada na tabela Cliente. Cada
atributo da classe ser gravado em uma coluna da tabela com seu respectivo nome. A Ilustrao 5
demonstra como deve ser o mapeamento da classe Cliente para a tabela Cliente.

Ilustrao 5: Mapeamento classe Cliente para a tabela Cliente.

A configurao do Hibernate envolve a especificao deste mapeamento, definido quais


atributos sero gravados em cada campo de uma tabela no banco de dados. Essa configurao se faz
por meio de anotaes. Anotaes so instrues que descrevem informaes sobre a classe. Vamos
um exemplo prtico. O cdigo abaixo mostra a classe Cliente, totalmente anotada, trazendo as
informaes que o framework necessita para realizar o mapeamento para a tabela do banco de
dados que ir armazen-la.
@Entity
@Table(name = "Cliente")
public class Cliente implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(unique=true, nullable=false)
private int codigo;
@Column(length=45)
private String cpf;
@Column(length=45)
private String rg;
@Column(length=45)
private String nome;
@Column(length=45)
private String telefone;
@Column(name = "data_nasc")
@Temporal(TemporalType.DATE)
private Date dataNascimento;
set's()
get's()
}

Repare a presena de estruturas que iniciam com @ , so as anotaes. Existe diferentes


tipos de anotaes, cada uma denota uma configurao diferente, definido informaes a
componentes que a procedem, vamos explicar algumas:
@Entity - Esta anotao diz que essa classe uma entidade, portanto ser persistida. ( uma
classe chamada de entidade quando caracterizar necessidade de gravao no banco de dados de
suas propriedades ).
@Table(name = "Cliente") Anotao responsvel por apontar em qual tabela a classe ser
armazenada, neste caso na tabela Cliente.
@Id - Define o identificador nico da entidade, ser a chave primria da tabela.
@GeneratedValue(strategy=GenerationType.IDENTITY) Cdigo auto incrementvel.
@Column(unique=true, nullable=false) Diz que o atributo ser gravado na coluna
especificada. Caso no seja informado um nome, a coluna assume o mesmo nome do atributo. As
opes de (unique=true, nullable=false) informam que o cdigo nico e no aceita valores nulos.
@Column(name = "data_nasc") Define um nome da coluna da tabela diferente do nome
do atributo da classe. O atributo dataNascimento ser gravado na coluna data_nasc.
@Temporal(TemporalType.DATE)
e ser armazenado com essa caracterstica.

Anotao que indica que o tipo de atributo uma data

Com as anotaes anteriores a instruo hibernate.gravar(cliente); agora parece


totalmente possvel de acontecer, pois a classe Cliente possui todas as informaes referentes a sua
gravao no banco. A configurao requer ainda as informaes para realizar a conexo com o
banco de dados, como por exemplo endereo ip do servidor, usurio e senha. H um arquivo
especifico destinado a guardar essa configurao, persistence.xml. A listagem a seguir mostra um
exemplo dessa configurao.
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="ClienteJPA">
<class>Cliente</class>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.connection.driver_class"
value="org.gjt.mm.mysql.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost/nomeDaBase" />
<property name="hibernate.connection.username" value="usuario" />
<property name="hibernate.connection.password" value="senha" />
</properties>
</persistence-unit>
</persistence>

Algumas consideraes sobre a listagem anterior:


<class>Cliente</class>

- Classe a ser gerenciada pelo JPA.

<persistence-unit name="ClienteJPA"> - Numa solicitao de servios do JPA, uma


conexo ser criada utilizando um persistence-unit, identificado atravs de seu nome, onde as
informaes necessrias para a estabelecer uma conexo com o banco esto presentes.

As clausulas property informam os detalhes da conexo, identificando o tipo de banco de


dados utilizado, endereo do servidor, senha, usurio dentre outras informaes.
Outro conceito que o JPA nos apresenta o EntityManager, responsvel pela execuo dos
servios de persistncia do framework. Ele gerencia as entidades, estabelece a conexo com o banco
de dados, executa as operaes de gravao, alterao, remoo e seleo das classes anotadas. O
EntityManager criado baseando-se em no persistence-unit definido no persistence.xml. O
cdigo que segue, demostra a criao do gerenciador.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ClienteJPA");
EntityManager em = emf.createEntityManager();

Repare que o parametro de contruao do gerenciador o mesmo nome contido no valor


name da unidade de persistencia.
<persistence-unit name="ClienteJPA">

Nos exemplos anteriores, tratamos apenas a filosofia de funcionamento do Hibernate, o

exemplo a seguir mostra o cdigo que realiza a gravao de um objeto cliente, no banco de dados,
mas dessa vez utilizando a sintaxe completa do JPA.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("ClienteJPA");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(cliente);
em.getTransaction().commit();
em.close();
emf.close();

O exemplo cria um EntityManager, fazendo referncia ao


arquivo persistence.xml, em seguida uma transao iniciada.

persistence-unit

configurado no

em.getTransaction().begin();

A instruo abaixo diz ao EntityManager para executar a gravao, no banco de dados, do


objeto cliente passado por parmetro. Persist significa persistir, armazenar, gravar.
em.persist(cliente);

Para que o objeto seja realmente gravado, deve-se dar a ordem de exucao de gravao,
isso se faz atravs do cdigo abaixo. Commit concretiza a solicitao do recurso de gravao.
em.getTransaction().commit();

Para finalizar, encerra-se a transao.


em.close();
emf.close();

Para realizar uma seleo, o mecanismo similar, vamos a um exemplo de procura de um


cliente a partir do seu cdigo:
em.getTransaction().begin();
compra = em.find(Compra.class, codigo);
em.getTransaction().commit();

No exemplo acima, uma transao iniciada, e o mtodo find localiza a partir do cdigo o
objeto, os dois parmetros da procura so a classe do objeto, que serve de referencia para dizer
aonde procurar, e o cdigo, que diz oque procurar.
O cdigo abaixo mostra como alterar os objetos:
entityManager.merge(cliente);

O mtodo merge atualiza o registro da tabela do banco que possui o mesmo cdigo do
objeto passado por parmetro. As ilustraes 6 e 7 mostram o processo de atualizao do objeto
cliente.

Ilustrao 6: Registro antes da alterao.


Cliente cliente = new Cliente();
cliente.setNome("Jos Serra");
cliente.setRg("123");
cliente.setCpf("456");
cliente.setTelefone("999");
cliente.setCodigo(5);
em.getTransaction().begin();
em.merge(cliente);
em.getTransaction().commit();

Ilustrao 7: Registro depois da alterao.

O exemplo anterior altera os valores do cpf, rg e telefone do registro de cdigo 5. Repare


que a data de nascimento no foi definida no objeto cliente alterado, sendo assim, o atributo alterou
o valor armazenado na tabela por valores nulos. Para que ocorra a alterao necessrio que o
cdigo do cliente esta definido no objeto passado por parmetro.
Agora vamos remover o registro que foi alterado no exemplo anterior, seguindo o principio
dos exemplos temos:
Cliente cliente = new Cliente();
cliente.setNome("Jos Serra");
cliente.setRg("123");
cliente.setCpf("456");
cliente.setTelefone("999");
cliente.setCodigo(5);
em.getTransaction().begin();
em.remove(cliente);
em.getTransaction().commit();

Recebemos o seguinte erro:


Exception in thread "main" java.lang.IllegalArgumentException:
Removing a detached instance Cliente

Para explicar oque ocorreu errado na tentativa de remover o registro, tem-se que entender o
conceito de entidades gerenciadas pelo JPA. Ao criar objetos na aplicao, inicialmente esses no
esto sendo gerenciados pelo JPA.
Cliente titi = new Cliente();
cliente.setNome("Carvo");
cliente.setCpf("4445988-5");
cliente.setRg("48053400");
cliente.setTelefone("4833666");

Entidades Monitoradas pelo JPA


Cliente bi = new Cliente();
cliente.setNome("bianchi");
cliente.setCpf("5433535");
cliente.setRg("34567454");
cliente.setTelefone("483233");

Ilustrao 8: Entidades no gerenciadas pelo JPA.

Ao executar operaes de persistncia, como por exemplo persist, a entidade gravada no


banco de dados e passa a ser gerenciada pelo framework.

em.getTransaction().begin();
em.persist(cliente);
em.getTransaction().commit();

Cliente carvo = new Cliente();


cliente.setNome("Carvo");
cliente.setCpf("4445988-5");
cliente.setRg("48053400");
cliente.setTelefone("4833666");

Entidades Monitoradas pelo JPA

Cliente bi = new Cliente();


cliente.setNome("bianchi");
cliente.setCpf("5433535");
cliente.setRg("34567454");
cliente.setTelefone("483233");

Ilustrao 9: Processo de gerenciamento de entidades JPA.

Na tentativa de remoo, que resultou no erro, tinha-se o seguinte cenrio:

Entidades Monitoradas pelo JPA

Cliente cliente = new Cliente();


cliente.setNome("Jos Serra");
cliente.setRg("123");
cliente.setCpf("456");
cliente.setTelefone("999");
cliente.setCodigo(5);

em.getTransaction().begin();
em.remove(cliente);
em.getTransaction().commit();
Ilustrao 10: Tentativa de remoo de entidade no gerenciada.

ERRO

Note que a remoo se aplicou a uma entidade que no estava sendo gerenciada pelo JPA, este o
motivo do erro. O JPA no pode remover uma entidade que no gerenciada por ele. Sendo assim, a
entidade que deseja-se remover deve estar sob o domnio do framework. Uma forma de fazer isso
solicitar que o Hibernate faa a pesquisa da entidade. Toda a entidade selecionada do banco de
dados atravs do framework, est sob gerenciamento. O cdigo que segue mostra a implementao
da soluo encontrada.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPAExemplo");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Cliente c = em.find(Cliente.class, 5);
em.getTransaction().commit();
em.getTransaction().begin();
em.remove(c);
em.getTransaction().commit();
em.close();
emf.close();

em.getTransaction().begin();
Cliente c = em.find(Cliente.class, 5);
em.getTransaction().commit();

Nome = ("Jos Serra");


Rg = ("123");
Cpf = ("456");
Telefone = ("999");
Codigo = (5);
.....

em.getTransaction().begin();
em.remove(c);
em.getTransaction().commit();

Remoo
Realizada
Entidades Monitoradas pelo JPA

Ilustrao 11: Remoo de entidade gerenciada.

Resumo do Captulo:
A forma tradicional de manipulao de informaes em banco de dados, envolve um cdigo
muito extenso e propenso a erros e profundas modificaes caso seja necessrio qualquer
modificao na configurao dos dados. A pratica de uso JDBC despende de grande esforo para o
desenvolvimento e consequentemente na manuteno dos sistemas.
JPA vem com a proposta de facilitar o penoso trabalho de manipular informaes que
precisam ser gravadas em banco de dados, tornando a manipulao de banco de dados, que segue o
paradigma relacional, em uma abordagem orientada a objeto.
O Hibernate uma implementao da especificao padro, e a configurao do framework
se faz principalmente por meio de anotaes nas classes que sofreram persistncia. As
configuraes fsicas do banco de dados ficam no arquivo persistence.xml, que contm todas as
propriedades do sistema gerenciador de banco de dados a a ser utilizado.
As funes de manipulao de dados so realizadas por mtodos do gerenciador de
entidades, sendo essas persist, merge, find e remove. O JPA mantem sob seu gerenciamento as
entidades que manipula.
Este capitulo mostrou os conceitos bsicos do JPA com Hibernate, seus principais
componentes, conceitos e configuraes.

3. Implementando JPA no projeto JSF.


Iniciamos anteriormente um projeto JSF de cadastro de clientes, que utiliza JDBC para
manipular as operaes com o banco de dados, vamos construir uma implementao JPA com
Hibernate para realizar essa tarefa, e veremos as vantagens ao se desenvolver utilizando esta
tecnologia.
A ilustrao 12 mostra o diagrama de classe do projeto e evidencia a nova classe que
implementar a interface ClienteDAO utilizando JPA. A ilustrao 13 representa o Diagrama ER,
observe que no houve alterao nenhuma do banco de dados.

Ilustrao 12: Diagrama de Classe Adaptado para JPA

Ilustrao 13: Diagrama ER do Projeto Cadastro Clientes

Com a estrutura do projeto redefinida, vamos agora a implementao. Devemos acrescentar


a classe JPAClienteDAO ao projeto, mas antes disso temos que adicionar ao projeto JSF, as funes
JPA com Hibernate. V as propriedades do projeto e selecione a opo Project Facets. Selecione a
opo Java Persistence e clique em OK.

Ilustrao 14: Adicionando Funcionalidades JPA ao Projeto.

Concluda esta etapa, o projeto passa a possuir caractersticas JSF e JPA, em outras palavras,
o projeto agrega funcionalidades dos dois Frameworks. Observe que agora est presente o arquivo
de configurao do Hibernate.

Ilustrao 15: Estrutura JPA ao Projeto JSF.

Você também pode gostar