Hibernate - LES PUC-Rio

Transcrição

Hibernate - LES PUC-Rio
Hibernate
Mapeamento O/R
Marcio Aguiar Ribeiro
[email protected]
Hibernate – O que é?
• Ferramenta para mapeamento O/R em Java
– Uma das mais difundidas
• Transparência
• Independência quanto ao tipo de base de dados
• Consulta de dados
– HQL, Criteria Queries, SQL, JPA QL
• Extensível
• Licença LGPL
© LES/PUC-Rio
Hibernate vs. JDBC
HIBERNATE
JDBC
© LES/PUC-Rio
Hibernate - Arquitetura
Arquitetura - Overview
© LES/PUC-Rio
Hibernate – Objetos Persistentes
Objetos Persistentes
• Implementam entidades lógica do negócio
• POJOs (Plain Old Java Object)
– Construtor padrão
– Possui métodos de acesso – gets/sets (opcional)
• Possui um atributo identificador (recomendado)
• Classes não final (recomendado)
• Recomenda-se implementar Serializable
© LES/PUC-Rio
POJO - Exemplo
© LES/PUC-Rio
POJO - Exemplo
mapeamento
© LES/PUC-Rio
Mapeamento
• Devemos informar ao Hibernate como relacionar o modelo
de objetos com o modelo relacional
• Arquivos de mapeamento vs. Annotations
© LES/PUC-Rio
Mapeando as classes
• Declaração de entidade
– Anotação @Entity
– Indicação do nome da table através do @Table (opcional)
@Entity
@Table (name = "COMUNIDADES")
public class Comunidade implements Serializable {
...
}
© LES/PUC-Rio
Mapeamento de Identificadores
• Indicação da chave primária
– @Id
• Escolha do gerador da Chave
– @GeneratedValue
– Estratégias: AUTO, SEQUENCE, IDENTITY e TABLE
@Entity
@Table (name = "COMUNIDADES")
public class Comunidade implements Serializable {
@Id @GeneratedValue
private Long id;
...
}
ver classe
© LES/PUC-Rio
Mapeamento de Propriedades
• Mapeamento de atributos primitivos não são necessários
• Opcionalmente todo atributo pode ser anotado com @Column
– name
– lenght
– nullable
– unique
– ...
@Entity
@Table (name = "COMUNIDADES")
public class Comunidade implements Serializable {
...
@Column(name="comNome", length=30, nullable=false, unique=true)
private String nome;
...
}
ver classe
© LES/PUC-Rio
Mapeamento de Propriedades
• Para datas (Date ou Calendar) é necessário a anotação @Temporal
para definir precisão:
– DATE
– TIME
– TIMESTAMP
@Entity
public class Ator implements Serializable {
...
@Temporal(TemporalType.DATE)
private Calendar nascimento;
...
}
ver classe
© LES/PUC-Rio
Mapeamento de Relacionamentos
• one-to-one
• many-to-one
• one-to-many
• many-to-many
© LES/PUC-Rio
Mapeamento de Relacionamentos - Exemplo
Unidirecional one-to-many
Bidirecional many-to-many
Unidirecional many-to-one
Unidirecional one-to-one
© LES/PUC-Rio
Mapeamento – one-to-one
•
Três formas
– Relação com chave estrangeira (Código 1)
– Relação por chave primária (Código 2)
– Com tabela associativa (Código 3)
public class Ator implements Serializable {
public class Ator implements Serializable {
...
...
@OneToOne
@OneToOne @PrimaryKeyJoinColumn
@JoinColumn(name=“cadastro_id”, unique=true)
private Cadastro cadastro;
private Cadastro cadastro;
...
...
}
}
Código 1
public class Ator implements Serializable {
...
@OneToOne
@JoinTable(
name=“Ator_Cadastro",
joinColumns = @JoinColumn(name = “Ator_ID"),
inverseJoinColumns = @JoinColumn(name = “Cadastro_ID")
)
private Cadastro cadastro;
...
}
Código 3
© LES/PUC-Rio
Código 2
Modelo relacional
atores
id <<PK>>
1)
cadastro_id <<FK>>
nome
nascimento
cadastros
id <<PK>>
email
username
senha
atores
cadastros
id <<PK>>
id <<PK>> <<FK>>
2)
email
nome
username
nascimento
senha
© LES/PUC-Rio
Mapeamento – many-to-one
@Entity
@Table (name = "COMUNIDADES")
public class Comunidade implements Serializable {
...
@ManyToOne
private Ator criador;
...
}
© LES/PUC-Rio
Modelo relacional
comunidades
atores
id <<PK>>
id <<PK>>
nome
nome
descricao
nascimento
atorID <<FK>>
© LES/PUC-Rio
Mapeamento – uso de Coleções
• java.util.Set, java.util.Collection, java.util.List, java.util.Map,
java.util.SortedSet, java.util.SortedMap...
@Entity
@Table (name = "COMUNIDADES")
public class Comunidade implements Serializable {
...
@OneToMany
private Set<Papel> papeis;
...
}
© LES/PUC-Rio
Modelo relacional
papeis
comunidades
id <<PK>>
id <<PK>>
nome
nome
descricao
descricao
atorID <<FK>>
comunidadeID <<FK>>
© LES/PUC-Rio
Mapeamento – many-to-many
@Entity()
public class Ator implements Serializable {
...
@ManyToMany()
@JoinTable(
name = "ATOR_PAPEL",
joinColumns = {@JoinColumn(name = "ATOR_ID")},
inverseJoinColumns = {@JoinColumn(name = "PAPEL_ID")}
)
private Set<Papel> papeis;
...
}
© LES/PUC-Rio
Mapeamento – List – many-to-many
@Entity()
public class Papel implements Serializable {
...
@ManyToMany(mappedBy="papeis“)
@IndexColumn(name="indice")
private List<Ator> atores;
...
}
© LES/PUC-Rio
Modelo relacional
atores
ator_papel
id <<PK>>
atorID <<FK>>
nome
papelID <<FK>>
nascimento
indice
papeis
id <<PK>>
nome
descricao
comunidadeID <<FK>>
© LES/PUC-Rio
Mapeamento - Herança
• Três estratégias
– Tabela por hierarquia
– Tabela por subclasse
– Tabela por classe concreta
• Recurso
– Polimorfismo implícito
© LES/PUC-Rio
Tabela por hierarquia
• Precisa determinar um discriminador
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name=“TIPO_DE_ATOR”, discriminatorType=DiscriminatorType.STRING)
public abstract class Ator implements Serializable {
…
}
@Entity
@DiscriminatorValue(value=“T”)
public class Trabalhador extends Ator {
…
}
@Entity
@DiscriminatorValue(value=“E”)
public class Estudante extends Ator {
…
}
© LES/PUC-Rio
Modelo relacional
Ator
id <<PK>>
nome
nascimento
escola
ano
ocupacao
salario
TIPO_DE_ATOR
© LES/PUC-Rio
Tabela por classe concreta
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Ator implements Serializable {
…
}
@Entity
public class Estudante extends Ator {
…
}
@Entity
public class Trabalhador extends Ator {
…
}
© LES/PUC-Rio
Modelo relacional
Trabalhador
Estudante
id <<PK>>
id <<PK>>
nome
nome
nascimento
nascimento
escola
ocupacao
ano
salario
© LES/PUC-Rio
Tabela por classe
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Ator implements Serializable {
…
}
@Entity
public class Estudante extends Ator {
…
}
@Entity
public class Trabalhador extends Ator {
…
}
© LES/PUC-Rio
Modelo relacional
Estudante
Ator
Trabalhador
id <<PK>> <<FK>>
id <<PK>>
id <<PK>> <<FK>>
escola
nome
ocupacao
ano
nascimento
salario
© LES/PUC-Rio
Configuração
• META-INF/persistence.xml
– Driver, url do banco de dados, senha, etc.
© LES/PUC-Rio
Copiar bibliotecas
• Copiar as bibliotecas
necessárias para o
funcionamento do Hibernate
© LES/PUC-Rio
Criando o banco
• Adiciona-se o atributo hibernate.hbm2ddl.auto ao persistence.xml
• Pode ser feito programáticamente
• É necessário a existência de um banco com o nome especificado
na configuração
Map configOverrides = new HashMap();
configOverrides.put("hibernate.hbm2ddl.auto", "create-drop");
EntityManagerFactory programmaticEmf =
Persistence.createEntityManagerFactory("HibernateTest", configOverrides);
© LES/PUC-Rio
Trabalhando com classes persistentes
EntityManagerFactory
cria
persistence.xml
save
EntityManager
P1
BANCO
A1
C1
P2
delete
© LES/PUC-Rio
EntityManagerFactory
(javax.persistence.EntityManagerFactory)
• Threadsafe
• Carrega as informações definidas no arquivo
persistence.xml
• Fábrica de EntityManager
• Geralmente se usa uma por aplicação
– Exceto quando se precisa acessar mais de uma fonte de dados
© LES/PUC-Rio
EntityManager (javax.persistence.EntityManager)
• Representa a troca de informações entre a aplicação e um
esquema de armazenamento de dados
• Começa e finaliza transações
• Wrapper para conexões JDBC
• Cache de objetos persistentes
© LES/PUC-Rio
Criando uma Session
• Criando um EntityManagerFactory
EntityManagerFactory factory = Persistence.
createEntityManagerFactory("HibernateTest");
• Criando um EntityManager
EntityManager manager = factory.createEntityManager();
© LES/PUC-Rio
Demarcação de transação
• Fronteiras de transação são
obrigatórias
try {
manager.getTransaction().begin();
[operações com o banco]
manager.getTransaction().commit();
• Envolve 4 passos básicos
–
} catch (RuntimeException ex) {
iniciar transação
–
dar o commit na transação
–
tratar erros
–
fechar sessão
manager.getTransaction().rollback();
throw ex;
} finally {
manager.close();
}
© LES/PUC-Rio
Ciclo de vida dos objetos persistentes
• Transientes
• Persistentes
• Detached
© LES/PUC-Rio
Tornando um objeto persistente
• Novas instancia são consideradas transientes
• Usa-se o comando persist para tornar um objeto persistente
• Ao salvar o seu id é gerado
• Se o objeto tiver associação com outros objetos é preciso salva-los
antes (ou usar persistência transitiva)
Comunidade comunidade = new Comunidade(
"Comunidade 1", "Primeira comunidade");
manager.persist(comunidade);
© LES/PUC-Rio
Carregando um objeto
• Comando find
– Carrega pelo id do objeto
Comunidade comunidade = manager.find(Comunidade.class, new Long(1));
© LES/PUC-Rio
Consultando objetos
• JPA QL
– Linguagem de consulta semi-OO
• Criteria
– Uma API orientada a objeto para busca
• SQL
© LES/PUC-Rio
JPA QL
List<Comunidade> comunidades = manager.
createQuery("from Comunidade").getResultList();
List<Comunidade> comunidades = manager.
createQuery("from Comunidade c where c.nome = ?")
.setParameter(1, “Java”)
.getResultList();
List<Comunidade> comunidades = manager.
createQuery("from Comunidade c where c.nome = :nome")
.setParameter(“nome”, “Java”)
.getResultList();
List<Comunidade> comunidades = manager.
createQuery("from Comunidade c where c.nome = ?
and c.descricao like ?")
.setParameter(1, “Java”)
.setParameter(2, “%Programadores%”)
.getResultList();
• Outer e inner join, subquery, order by, group by e vários operadores
© LES/PUC-Rio
Paginação
• Usado para determinar fronteiras no resultado
• Útil para evitar desperdício de memória.
List<Comunidade> comunidades = manager.
createQuery("from Comunidade")
.setFirstResult(5)
.setMaxResult(5)
.getResultList();
© LES/PUC-Rio
Externalizando queries
• Queries declaradas nas classe via Annotation
• Não mistura código de consulta com o da aplicação
@Entity
@Table (name = "COMUNIDADES")
@NamedQueries({
@NamedQuery(name=“Comunidade.porCriador”),
query=“from Comunidade c where c.criador = ?”
})
public class Comunidade implements Serializable {
...
}
Ator ator = manager.find(Ator.class, new Long(1));
List<Comunidade> comunidades = manager.
createNamedQuery("Comunidade.porCriador").
setParameter(1, ator).getResultList();
© LES/PUC-Rio
Criteria API
• Mais próximo de desenvolvedores que não conhecem
linguagens de consulta
• Não disponível na JPA
© LES/PUC-Rio
Alterando objetos persistentes
Ator ator = manager.find(Ator.class, new Long(1));
ator.setName("Marcio");
manager.getTransaction().commit();
• Para instâncias fora do contexto de persistência
manager.getTransaction().begin();
ator.setName("Marcio");
manager.merge(ator);
manager.getTransaction().commit();
© LES/PUC-Rio
Tornando os objetos transientes
• Remove o objeto do banco
• Cuidado para não resultar em violação de integridade
– Exemplo: ao remover um ator, seu cadastro deve ser removido
também
Ator ator = manager.find(Ator.class, new Long(1));
manager.remove(ator.getCadastro());
manager.remove(ator);
manager.getTransaction().commit();
© LES/PUC-Rio
Persistência transitiva
• As operações (persist, remove, merge) realizadas com o banco
podem resultar em violações de integridade
• O Hibernate possui mecanismos para tratar relações do tipo
pai/filho automaticamente
– Ex.: Ao remover um ator do banco não faz sentido manter o cadastro
do ator
public class Ator implements Serializable {
public class Comunidade implements Serializable {
...
...
@OneToOne(cascade={CascadeType.ALL})
@ManyToOne(cascade=CascadeType.PERSIST)
@JoinColumn(name=“cadastro_id”, unique=true)
@JoinColumn(name =“Ator_ID”, nullable=false)
private Cadastro cadastro;
private Ator criador;
...
...
}
}
© LES/PUC-Rio
Carga preguiçosa
• Carga dos objetos é feita apenas quando necessário
• Evita sobrecarregar a memória com objetos não necessários
• Hibernate usa proxies das coleções Java
• Pode ser difícil de se trabalhar (LazyInitializationException)
public class Comunidade implements Serializable {
...
@ManyToOne(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
@JoinColumn(name =“Ator_ID”, nullable=false)
private Ator criador;
...
}
© LES/PUC-Rio
Boas práticas e padrões
• Uso de Data Access Objects (DAOs e Generic DAOs)
• Patterns
– Session-per-request
• Uma sessão é aberta no inicio de uma requisição web e fechada ao final
• Implementada com ServletFilter
• Anti-patters
– Session-per-operation
• Uma sessão é aberta para cada operação executada
• Otimizar o pool de conexões (c3p0)
• Configurar o cache
© LES/PUC-Rio
Exercícios
• Trabalhar a “auto-didática”
– Referência do Hibernate bastante completa:
• http://www.hibernate.org
– Livro: JPA with Hibernate por Gavin King
© LES/PUC-Rio

Documentos relacionados