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