SlideShare uma empresa Scribd logo
Curso: Persistência em Java com Hibernate Instrutor: Fabrício Lemos 23/04/2007
Persistência É um tópico vital para o desenvolvimento de aplicações Quase todas as aplicações necessitam que dados sejam persistidos Necessidades Armazenamento Busca Organização Compartilhamento dos dados
Persistência Necessidades Integridade dos dados Controle de concorrência Performance e a escalabilidade são fortemente afetadas pela estratégia de acesso a dados escolhida
Banco de Dados Relacionais Geralmente são utilizados banco de dados SQL Flexível Robusto Eficiente Confiável Maneira mais utilizada e conhecida de armazenar dados
Banco de Dados Relacionais Dados são armazenados de forma independente Independência de linguagem Independência de aplicação Os dados geralmente possuem longevidade maior do que as aplicações que os acessam A utilização de algum framework não elimina a necessidade de conhecimento de SQL e do modelo relacional
Persistindo dados com Java Realizado através da API Java Database Connectivity (JDBC) Tarefas de baixo nível Preparar consultas Associar parâmetros Executar a consulta Percorrer  e retornar o resultado Tarefas de alto nível Salvar e recuperar objetos
Persistindo objetos com Java (ou qualquer outra linguagem OO) Linguagem orientada a objetos Deve-se poder armazenar o estado de um objeto, mesmo após o objeto ser destruído Deve ser possível criar um novo objeto com o mesmo estado do anterior Operações não devem ser limitadas a um único objeto Associações devem ser salvas
Persistindo objetos com Java A aplicação deve trabalhar diretamente com objetos, ao invés de linhas e colunas da base de dados Lógica de negócio deve ser implementada na aplicação, utilizando-se Java, e não diretamente na base de dados Limitar o uso de stored procedures Conceitos da Orientação a Objetos não devem ser restringidos pela solução adotada
Diferença dos Paradigmas: OO/Relacional Granularidade Objetos de baixa granularidade podem ser persistidos em tabelas de grande granularidade ou vice-versa Uma tabela armazena diversos tipos de objetos Um objeto é armazenado em diversas tabelas Herança Modelo relacional não possui o conceito de herança
Diferença dos Paradigmas Polimorfismo Necessidade de um objeto referenciar outros através de superclasses Uma referência pode estar associada o objetos de tipos diferentes Chaves estrangeiras referenciam uma tabela específica
Diferença dos Paradigmas OO/Relacional Identidade dos objetos Java Operador == Método equals() Banco de dados Chave primária Atualização de algum atributo que faz parte da chave requer que outras tabelas sejam atualizadas
Diferença dos Paradigmas OO/Relacional Associações OO possui associações unidirecionais e bidirecionais Junções de tabelas e projeções não possuem o conceito de “direção” de uma associação Associações em OO podem ser do tipo many-to-many Associações entre tabelas só podem ser one-to-many e  one-to-one Necessidade de criar uma tabela de relacionamento para associações many-to-many Tabela não presente no modelo do domínio da aplicação
Diferença dos Paradigmas: Custo Necessário escrever muito código para (tentar) contornar o problema Código se torna repetitivo e de difícil manutenção A escrita de código SQL pode tornar a aplicação dependente do banco de dados Modelagem dos objetos fica prejudicada Outras camada ficam fortemente acopladas à Camada de Persistência Produtividade pode ser fortemente afetada
Estratégias de Persistência JDBC e SQL Faz parte da plataforma Java Necessário escrever bastante código de baixo nível Stored Procedures Lógica de negócio sai da aplicação e vai para a base de dados Perde-se a portabilidade
Estratégias de Persistência Framework corporativo Necessário grande esforço da empresa Demora-se muito para que a solução implementada atinga maturidade Documentação muitas vezes é esquecida Falta de suporte
Estratégias de Persistência Java Persistence API (JPA) Especificação elaborada pelo Java Community Process para persistência em Java Baseou-se em diversas soluções existentes Frameworks existentes passaram a implementar a especificação Recursos são um sub-conjunto dos encontrados nos frameworks que a implementam Atualizações são lentas e burocráticas
Estratégias de Persistência Frameworks de terceiros TopLink Framework de persistência Objeto/Relacional Desenvolvido pela Oracle Gratuito para avaliação e nas fases de desenvolvimento Hibernate
Hibernate Framework de mapeamento Objeto-Relacional Preenche a lacuna entre a base de dados relacional e a aplicação orientada a objetos Framework de persistência Java mais utilizado e documentado Mantido pela Jboss sob a licensa LGPL Suporta classes desenvolvidas com agregação, herança, polimorfismo, composição e coleções
Hibernate Permite a escrita de consultas tanto através de uma linguagem própria (HQL) como também através de SQL Framework não intrusivo Não restringe a arquitetura da aplicação Implementa a especificação Java Persistence API Grande e ativa comunidade Mais de 25 mil desenvolvedores registrados nos foruns oficiais
Mapeamento Objeto Relacional Permite a persistência de objetos em tabelas de uma base de dados relacional Automática e Transparente Utiliza metadados para descrever o relacionamento entre os objetos e a base de dados XML Xdoclet Annotations
Mapeamento Objeto Relacional O SQL é gerado automaticamente a partir dos metadados A escrita e manutenção de metadados necessita de esforço nas etapas de implementação Esforço bem menor do que o necessário para fazer a conversão manualmente A conversão entre os tipos de representação pode trazer perca de performance Ferramentas maduras otimizam a conversão em diversos pontos
Mapeamento Objeto Relacional Possui quatro partes principais API para realização de operações básicas (CRUD) Linguagem ou API para a realização de consultas Maneira para a especificação de metadados Técnicas de otimização Dirty checking Carregamento tardio (lazy association fetching)
Mapeamento Objeto Relacional: Vantagens Produtividade Elimina a necessidade de escrita de grande parte do código relativo a persistência Maior tempo disponível para implementar a lógica da aplicação Manutenibilidade Menos código Maior entendimento da aplicação Camada de abstração Facilita a refatoração
Vantagens Performance Tarefas manuais nem sempre tem performance melhor do que tarefas automatizadas Considerando limitações de custo e tempo Frameworks maduros são bastantes otimizados Com o aumento de produtividade, você pode dedicar mais tempo para resolver possíveis gargalos Portabilidade Independência nem sempre é algo simples de ser alcançado, mesmo em aplicações Java Suporte a diversos tipos de banco de dados
Hibernate: Módulos Hibernate Core Contém os serviços básicos Metadados escritos em XML Consultas HQL: Hibernate Query Language Interfaces utilizando critérios e exemplos Não depende de outros módulos Não depende de uma versão específica do JDK Executável em qualquer servidor Web e/ou de Aplicação e também em aplicações desktop
Módulos Hibernate Annotations Permite a escrita de metadados através de Annotations Beneficia-se da tipagem do Java Compatível com refatorações de código Semântica familiar para quem já está acostumado com metadados em XML Utiliza as Annotations da especificação JPA Possui Annotations próprias para configurações avançadas não presentes na especificação Necessita do JDK 5.0
Módulos Hibernate Entity Manager Implementação da especificação JPA Permite a escrita de código compatível com qualquer framework de persistência que implemente a especificação Utiliza o pacote javax.persistence Não disponibiliza todas as funcionalidades do Hibernate
Separação em camadas É uma boa prática dividir aplicações de médio e grande porte em camadas Padrão Layers (Pattern-Oriented Software architecture) Divisão mais utilizada Apresentação Negócio Persistência
Separação em camadas Permite a especificação de intefaces para os diversos tipos de serviços A implementação pode ser mudada sem afetar significativamente o código de outras camadas A comunicação ocorre das camadas superiores para as camadas inferiores Uma camada só depende da camada imediatamente inferior Camada de apresentação não sabe da existência da camada de persistência
 
Criando um projeto
Next >....
Finish
Adicionando as bibliotecas
Criando uma entidade @Entity @Table (name =  "MESSAGES" ) public   class  Message { @Id @GeneratedValue @Column (name =  "MESSAGE_ID" ) private  Long  id ; @Column (name =  "MESSAGE_TEXT" ) private  String  text ; @ManyToOne (cascade = CascadeType. ALL ) @JoinColumn (name =  "NEXT_MESSAGE_ID" ) private  Message  nextMessage ; private  Message() {} public  Message(String text) { this . text  = text; } //gets e sets }
Annotations da classe Entity Informa que a classe pode ser persistida pelo Hibernate Table Informa o nome da tabela em que os objetos da classe devem ser armazenados @Entity @Table (name =  "MESSAGES" ) public   class  Message {
Construtores Obrigatório um construtor sem argumentos private  Message() {} public  Message(String text) { this . text  = text; }
Propriedades Representa o identificador do objeto Preenchido automaticamente quando o objeto é salvo Mapeado para a chave primária da tabela Se duas instâncias tiverem o mesmo identificador, elas representam a mesma linha da tabela @Id @GeneratedValue @Column (name =  "MESSAGE_ID" ) private  Long  id ;
Atributos O atributo  text  é armazenado na coluna  MESSAGE_TEXT @Column (name =  "MESSAGE_TEXT" ) private  String  text ; O atributo  nextMessage  é uma associação many-to-one Mapeado pela chave estrangeira  NEXT_MESSAGE_ID @ManyToOne (cascade = CascadeType. ALL ) @JoinColumn (name =  "NEXT_MESSAGE_ID" ) private  Message  nextMessage ;
Transparência Não há a necessidade de se herdar de uma superclasse ou de implementar um interface POJO - Plain Ordinary Java Objects Classes podem ser reutilizadas fora do contexto de persistência Interface com o usuário Testes de unidades As entidades não precisam nem saber que serão persistidas Grande nível de portabilidade
Configurando o Hibernate Configuração feita através do arquivo hibernate.cfg.xml Deve estar localizado na raiz do classpath Localização default Para projetos maven, utilizar a pasta src/main/resources Configurações contém Parâmetros de acesso a base de dados Pool de conexões Entidades a serem persistidas
hibernate.cfg.xml < hibernate-configuration > < session-factory > <!-- Parâmetros de acesso a base de dados --> < property  name = &quot;connection.driver_class&quot; > org.postgresql.Driver </ property > < property  name = &quot;connection.url&quot; > jdbc:postgresql://localhost:5432/curso </ property > < property  name = &quot;connection.username&quot; > postgresql </ property > < property  name = &quot;connection.password&quot; > postgresql </ property > < property  name = &quot;dialect&quot; > org.hibernate.dialect.PostgreSQLDialect </ property > ...
hibernate.cfg.xml ... <!-- Configuração do Pool de conexões --> < property  name = &quot;c3p0.min_size&quot; > 5 </ property > < property  name = &quot;c3p0.max_size&quot; > 20 </ property > < property  name = &quot;c3p0.timeout&quot; > 300 </ property > < property  name = &quot;c3p0.max_statements&quot; > 50 </ property > < property  name = &quot;c3p0.idle_test_period&quot; > 3000 </ property > <!-- Exibe no console o SQL gerado pelo hibernate--> < property  name = &quot;show_sql&quot; > true </ property > <!-- Cria e executa a DDL (tabelas, colunas, etc...)--> < property  name = &quot;hbm2ddl.auto&quot; > create </ property > <!-- Informa as Entidades da aplicação --> < mapping class = &quot;br.gov.serpro.curso.hibernate.exemplo1.Message&quot;  /> </ session-factory > </ hibernate-configuration >
Armazenando uma Mensagem //Obtendo o Session Session session = HibernateUtil.getSessionFactory().openSession(); //Iniciando a transação Transaction tx = session.beginTransaction(); // Criando uma mensagem Message message =  new  Message( &quot;Hello World&quot; ); // Salvando a Mensagem Long msgId = (Long) session.save(message); //Fazendo o commit da transação tx.commit(); //Fechando o Session session.close(); HibernateUtil.shutdown();
Objetos utilizados Session Contém métodos utilizados para armazenar e recuperar entidades Armazena uma lista de comandos SQL que serão executados, em algum momento, na base de dados Mantém as entidades gerenciadas pelo Hibernate Recuperadas, inseridas ou atualizadas através do Session Único para cada thread
Objetos utilizados Transaction Utilizado para delimitar as transações com a base de dados Geralmente gerenciado pelo container EJB Spring SessionFactory Utilizado para criar os Session Reutilizável por toda a aplicação
HibernateUtil public   class  HibernateUtil { private   static  SessionFactory  sessionFactory ; static  { sessionFactory  =  new  AnnotationConfiguration().configure() .buildSessionFactory(); } public   static  SessionFactory getSessionFactory() { return   sessionFactory ; } public   static   void  shutdown() { getSessionFactory ().close(); } }
Recuperando as Mensagens Session newSession = HibernateUtil.getSessionFactory().openSession(); Transaction newTransaction = newSession.beginTransaction(); //Criando e executando uma consulta Query query = newSession .createQuery( &quot;from Message m order by m.text asc&quot; ); List<Message> messages = query.list(); //Retornando a quantidade de mensagens encontradas System. out .println(messages.size() +  &quot; message(s) found:&quot; ); //Retornando as mensagens encontradas for  (Message msg : messages) { System. out .println(msg.getText()); } newTransaction.commit(); newSession.close(); HibernateUtil.shutdown();
Objetos Utilizados Query Cria as consultas Associa os parâmetros Executa as consultas
Dirty Checking e Cascade Session thirdSession =    HibernateUtil.getSessionFactory().openSession(); Transaction thirdTransaction = thirdSession.beginTransaction(); // recuperando a mensagem message = (Message) thirdSession.get(Message. class , msgId); //Alterando o texto message.setText( &quot;Greetings Earthling&quot; ); //Criando uma nova mensagem e associando à antiga message.setNextMessage( new  Message( &quot;Take me to your leader&quot; )); thirdTransaction.commit(); thirdSession.close(); HibernateUtil.shutdown();
Dirty Checking e Cascade Dirty Checking O Hibernate automaticamente verifica quando um atributo é modificado O atributo é atualizado na base de dados sem a necessidade de uma chamada explicita É possível somente dentro de uma transação e para objetos gerenciados pelo Session Cascade Novas entidades são persistidas automaticamente Devem ser alcançáveis a partir de uma entidade gerenciada
Metadados Utilizados para especificar o mapeamento entre  Classes e tabelas Propriedades e colunas Associações e chaves estrangeiras Tipos de atributos Java e tipos de atributos SQL Pode ser escrita de duas formas Arquivos XML Xdoclet Java Annotations
Porque não usar XML Pode ser tornar pouco legível e de difícil edição Requer maior digitação Falta de valores default para atributos e elementos Não necessariamente mais flexível e mais fácil de manter do que código Java Mais fácil encontrar um bom editor Java do que um bom editor de XML
Metadados com Annotations A meta-informação fica perto dos dados que ela descreve Compatível com refatoração de código Renomear, deletar e remover classes e propriedades Sem necessidade de fazer parser em XML Inicialização mais rápida Lido através de reflection na inicialização do Hibernate Disponível a partir da JDK 5.0
Mapeando Propriedades Ao mapear uma classe através da Annotation @ Entity , todas as propriedades serão consideradas persistentes Propriedades não persistentes devem receber a Annotation @ Transient  ou o modificador  transient Por default, o nome da coluna será o mesmo da propriedade Meio de acesso é o mesmo do  @ID Definido na propriedade ou no método get()
@Column Aplicável para propriedades simples Atributos name Nome da coluna a qual a propriedade é mapeada unique Se o valor deve ser único ou não nullable Se a propriedade pode ser nula ou não
Mapeando Propriedades: Tipos
Mapeando Propriedades: Tipos
Datas Propriedades podem ser do tipo  java.util.Date  ou  java.util.Calendar Precisão default é TIMESTAMP Precisão pode ser alterada através da Annotation @Temporal @Temporal (TemporalType. DATE ) private  Date  date1 ; @Temporal (TemporalType. TIME ) private  Date  date2 ; @Temporal (TemporalType. TIMESTAMP ) private  Date  date3 ;
Identidade das Entidades Identidade versus Equivalência em Java Identidade Operador == Definido pela máquina virtual Dois objetos são idênticos se eles apontam para o mesmo local da memória Equivalência Definida pelas classes que sobreescrevem o método equals() Dois objetos diferentes possuem o mesmo valor Dois objetos String podem ter a mesma seqüência de caracteres
Identidade das Entidades Identidade na base de dados Duas Entidades são idênticas se elas representam a mesma linha na base de dados Se são armazenadas na mesma tabela e possuem a mesma chave primária
Adicionando um Identificador O valor é gerado automaticamente pelo Hibernate Não deve ser mudado pela aplicação @Entity @Table (name= &quot;CATEGORY&quot; ) public   class  Category { @Id @GeneratedValue (strategy = GenerationType. AUTO ) @Column (name =  &quot;CATEGORY_ID&quot; ) private  Long  id ; public  Long getId() {  return   id ; } }
Escolhendo a chave primária Uma chave candidata é uma coluna, ou um conjunto de colunas, que pode ser utilizada para identificar um registro na base de dados Requisitos O valor nunca deve ser nulo Cada registro deve ter um valor único O valor nunca deve mudar
Escolhendo a chave primária Chaves naturais são aquelas que possuem significado para o domínio da aplicação CPF de um usuário Seqüencial gerado pela aplicação Dificilmente chaves naturais atendem os requisitos necessários
Escolhendo a chave primária Chaves cegas Melhor alternativa Não possuem significado para o domínio da aplicação  Geradas pelo banco de dados ou pela aplicação
Geração automática de chaves Hibernate suporta diversas estratégias para geração automática de chaves A estratégia deve ser especificada através da Annotations @ GeneratedValue
Estratégias IDENTITY Suporte para colunas IDENTITY nos bancos de dados DB2, MySQL, MS  SQL Server, Sybase e HypersonicSQL Os tipos devem ser  long ,  short  ou  int SEQUENCE Utiliza um Sequence para a geração de chaves Suporte para DB2, PostgreSQL e Oracle dentre outros Nome default da sequence é  hibernate_sequence
Estratégias increment Na inicialização o Hibernate lê qual o maior valor para a chave da tabela  O valor é atribuído e incrementado em cada inserção Não deve ser utilizado se o Hibernate não tiver acesso exclusivo para a base de dados
Estratégias AUTO Escolhe entre as estratégias IDENTITY, SEQUENCE ou HILO Estratégia escolhida depende do banco de dados utilizado Utilizado para manter a portabilidade Outras hilo, seqhilo, uuid.hex, guid, select IdentifierGenerator Permite a implementação de sua própria estratégia
Mapeando Componentes Entidades são classes persistentes que representam objetos do domínio da aplicação Possuem identidade própria Hibernate suporta a construção de um modelo de objetos de alta granularidade Propriedades de uma Entidade podem ser encapsuladas em outros objetos Tais objetos não possuem identidade própria Chamados de Objetos Valores ou Componentes Mais classes do que tabelas
Mapeando Componentes
Mapeando Componentes User Representa uma Entidade Possui identidade própria Chave primária na base de dados Uma referência para User é persistida como uma chave estrangeira Tem seu próprio ciclo de vida Existe independentemente de qualquer outra entidade
Mapeando Componentes Address Representa um Componente Não possui identidade própria Pertence a Entidade User Estado é persistido no registro referente ao User a qual está associado Ciclo de vida dependente de User Se dois Usuários morarem no mesmo apartamento, cada um tem uma referência para um objeto distinto Comportamento similar a tipos como String e Integer
Mapeando Componentes @Embeddable public   class  Address { @Column (name =  &quot;ADDRESS_STREET&quot; , nullable =  false ) private  String  street ; @Column (name =  &quot;ADDRESS_CITY&quot; , nullable =  false ) private  String  city ; //gets e sets... }
Mapeando Componentes @Entity @Table (name =  &quot;USERS&quot; ) public   class  User { @Id @GeneratedValue (strategy=GenerationType. AUTO ) private  Long  id ; private  String  name ; private  String  email ; private  Address  address ; //gets e sets }
Mapeando Herança A utilização de uma tabela para cada entidade não funciona tão bem para heranças entre entidades Bancos de dados SQL, de maneira geral, não possuem o conceito de herança Soluções proprietária podem comprometer a portabilidade da aplicação
Estratégias Tabela por classe concreta Tabela por classe concreta, utilizando junção Tabela por hierarquia Tabela por classe (concreta ou não)
Uma tabela por Classe Concreta: Modelagem
Uma tabela por Classe Concreta Estratégia mais simples Todas propriedades de uma classe, incluindo as herdadas, são mapeadas para a mesma tabela Mapeamento convencional pode ser utilizado Não suporta associações polimórficas adequadamente Associação para classe abstrata necessitaria que a chave estrangeira referenciasse duas tabelas
Uma tabela por Classe Concreta Diferentes colunas em diferentes tabelas passariam a possuir a mesma semântica Recomendável somente para a hierarquia superior Associações polimórficas geralmente não necessárias e não recomendadas Modificações na superclasse são muito raras select CREDIT_CARD_ID, OWNER, NUMBER, EXP_MONTH, EXP_YEAR ... from CREDIT_CARD select BANK_ACCOUNT_ID, OWNER, ACCOUNT, BANKNAME, ... from BANK_ACCOUNT
Mapeando a Superclasse Mapear a super classe através da Annotattion @ MappedSuperclass @MappedSuperclass public   abstract   class  BillingDetails { @Column (name =  &quot;OWNER&quot; , nullable =  false ) private  String  owner ; //gets e sets... }
Mapeando as Subclasses Nenhuma configuração extra é necessária @Entity public   class  BankAccount  extends  BillingDetails{ @Id @GeneratedValue private  Long  id ; private  Integer  account ; private  String  bank ; }
Mapeando as Subclasses Mapeamento das propriedades herdadas pode ser alterado Adicionar a Annotation @AttributeOverride @Entity @AttributeOverride (name =  &quot;owner&quot; , column =  @Column (name =  &quot;CC_OWNER&quot; , nullable =  false )) public   class  CreditCard  extends  BillingDetails { @Id @GeneratedValue private  Long  id ; private  String  number ; }
Uma tabela por Classe Concreta: Union Com a utilização de consultas com Union, alguns problemas podem ser eliminados Suporte a associações polimórficas Hibernate utiliza o Union para simular uma única tabela As subclasses herdam o Id da super-classe
Mapeando a Super Classe É utilizada a Annotation @Inheritance @Entity @Inheritance (strategy = InheritanceType. TABLE_PER_CLASS ) public   class  BillingDetails { @Id   @ GeneratedValue @Column (name =  &quot;BILLING_DETAILS_ID&quot; ) private  Long  id  =  null ; @Column (name =  &quot;OWNER&quot; , nullable =  false ) private  String  owner ; }
Mapeando as Subclasses Não é necessário mapear o identificador O Identificador é mapeado na super-classe @Entity public   class  CreditCard  extends  BillingDetails{ @Column (name =  &quot;CC_NUMBER&quot; ) private  String  number ; }
Tabela por Hierarquia
Tabela por Hierarquia Toda uma hierarquia é mapeada em uma única tabela A tabela possui colunas para todas as propriedades de todas as entidades da hierarquia A subclasse de cada registro é identificada através de uma coluna discriminatória Vantagem Possui a melhor performance
Tabela por Hierarquia Desvantagens Valores para colunas das subclasses devem sempre permitir NULL Perca da restrição NOT NULL Dados são desnormalizados
Mapeando a Superclasse O valor do atributo  strategy  deve ser mudado para  InheritanceType.SINGLE_TABLE @Entity @Inheritance (strategy = InheritanceType. SINGLE_TABLE ) public   abstract   class  BillingDetails { @Id   @GeneratedValue @Column (name =  &quot;BILLING_DETAILS_ID&quot; ) private  Long  id  =  null ; @Column (name =  &quot;OWNER&quot; , nullable =  false ) private  String  owner ; }
Tabela por classe
Tabela por classe Uma tabela para todas as classes, incluindo as abstratas, que possuem propriedades para serem persistidas Relação de herança é representada por uma chave estrangeira As tabelas não contém colunas para as propriedades herdadas A chave primária é também uma chave estrangeira para a super classe
Tabela por classe Vantagens Os dados são normalizados Restrições podem ser mantidas Desvantagens Performance pode ser muito baixa para hierarquias complexas Necessidade de muitas junções
Mapeando a Superclasse O valor do atributo  strategy  deve ser mudado para  InheritanceType.JOINED @Entity @Inheritance (strategy = InheritanceType. JOINED ) public   abstract   class  BillingDetails { @Id   @GeneratedValue @Column (name =  &quot;BILLING_DETAILS_ID&quot; ) private  Long  id  =  null ; @Column (name =  &quot;OWNER&quot; , nullable =  false ) private  String  owner ; }
Mapeando as Subclasses Id é mapeado na super-classe @Entity public   class  CreditCard  extends  BillingDetails{ @Column (name =  &quot;CC_NUMBER&quot; ) private  String  number ; }
Escolhendo a melhor estratégia Tabela por classe concreta, utilizando junção Se associações ou consultas polimórficas nunca ou raramente são utilizadas Tabela por hierarquia Se associações ou consultas polimórficas são utilizadas e Se as subclasses declaram poucas propriedades Maior diferença entre as subclasses é o comportamento
Escolhendo a Melhor Estratégia Tabela por Classe Se associações ou consultas polimórficas são utilizadas e Se as subclasses declaram muitas propriedades Maior diferença entre as subclasses são os dados que elas armazenam Se a largura e o comprimento da hierarquia não for muito grande
Mapeando coleções Objetos podem possuir coleções As coleções podem ter duas naturezas Coleções de valores Tipos primitivos Componentes Coleções de entidades
Coleção de tipos primitivos: Set Um Item possui um conjunto de imagens Somente o nome da imagem é persistido Nomes não devem ser duplicados para um determinado Item
Annotations @CollectionOfElements Utilizada para coleções de tipos primitivos ou para coleções de objetos valores @JoinTable Informa a tabela em que a coleção é persistida Atributos Name Nome da tabela JoinColumns Coluna que é chave estrangeira Chave estrangeira referencia a tabela da entidade que possui a coleção
Annotations @JoinColumn É o tipo do atributo  JoinColumns  da Annotation @JoinTable Annotation dentro de outra Annotation Mapeia a coluna utilizada para junções Atributos Name Nome da coluna
Classe Item @Entity public   class  Item { @Id @GeneratedValue @Column (name =  &quot;ITEM_ID&quot; ) private  Long  id ; private  String  name ; @CollectionOfElements @JoinTable (name =  &quot;ITEM_IMAGE&quot; , joinColumns =  @JoinColumn (name =  &quot;ITEM_ID&quot; )) @Column (name =  &quot;FILENAME&quot; , nullable =  false ) private  Set<String>  images  =  new  HashSet<String>(); }
Coleção de tipos primitivos: List Caso a aplicação necessite guardar a ordem dos elementos Necessário uma coluna para informar a posição de cada elemento
Classe Item Deve-se adicionar a Annotation  @IndexColumn @Entity public   class  Item { ... @CollectionOfElements @JoinTable (name =  &quot;ITEM_IMAGE&quot; , joinColumns =  @JoinColumn (name  =  &quot;ITEM_ID&quot; )) @Column (name =  &quot;FILENAME&quot; , nullable =  false ) @IndexColumn (name =  &quot;POSITION&quot; ) private  List<String>  images  =  new  ArrayList<String>(); }
Coleção de tipos primitivos: Map Se o Item possuir um Map de imagens É necessário guardar o elemento e sua chave
Classe Item Utilizar a Annotation  @MapKey Atributo  columns  informa o nome da coluna que armazena a chave @Entity public   class  Item { ... @CollectionOfElements @JoinTable (name =  &quot;ITEM_IMAGE&quot; , joinColumns =  @JoinColumn (name  =  &quot;ITEM_ID&quot; )) @Column (name =  &quot;FILENAME&quot; , nullable =  false ) @MapKey (columns =  @Column (name =  &quot;IMAGENAME&quot; )) private  Map<String, String>  images  =  new  HashMap<String,  String>(); }
Associação entre Entidades Podem ser de diversas multiplicidades One-to-many One-to-one Many-to-many Many-to-one Também são implementadas através de atributos Para associações one-to-many e many-to-many é necessário a utilização de coleções
Implementando associações Coleções devem ser acessadas através de suas Interfaces Set, ao invés de HashSet List, ao invés de ArrayList
Associações Bidirecionais Os dois lados da associação devem estar consistentes Necessário mesmo para aplicações que não usam Hibernate
Classe Category public   class  Category { private  String  name ; private  Category  parentCategory ; private  Set<Category>  childCategories  =  new   HashSet<Category>(); //gets e sets //... }
Mantendo a Consistência Category aParent =  new  Category(); Category aChild =  new  Category(); aChild.setParentCategory(aParent); aParent.getChildCategories().add(aChild);
Relacionamento Pai-Filho
Classe Bid Relaciona-se a somente um Item Mapeamento realizado através da Annotation  @ManyToOne Annotation  @JoinColumn  informa qual a chave estrangeira Atributo  name Nome da coluna Atributo  nullable Se o relacionamento é opcional ou não
Classe Bid @Entity public   class  Bid { @Id @GeneratedValue @Column (name =  &quot;BID_ID&quot; ) private  Long  id ; private  Integer  amount ; @ManyToOne @JoinColumn (name =  &quot;ITEM_ID&quot; , nullable =  false ) private  Item  item ; }
Relacionamento Bidirecional O relacionamento pode ou não ser declarado como bidirecional Para relacionamentos bidirecionais o outro lado da associação é mapeado com a Annotation inversa @OneToMany no caso de Item Classe Bid utiliza a Annotation @ManyToOne
Relacionamento Bidirecional @Entity public   class  Item { @Id @GeneratedValue @Column (name =  &quot;ITEM_ID&quot; ) private  Long  id ; private  String  name ; @OneToMany (mappedBy =  &quot;item&quot; ) private  Set<Bid>  bids  =  new  HashSet<Bid>(); }
Relacionamento Bidirecional @OneToMany(mappedBy = &quot;item&quot;) Detalhes do mapeamento são configurados no outro lado da associação Através da Annotation  @ManyToOne Quando as referências de uma associação mudam, as duas propriedades são alteradas bid.setItem(item); item.getBids().add(bid);
Relacionamento Bidirecional Na base de dados somente uma atualização precisa ser feita Atualização da chave estrangeira Hibernate não precisa executar dois comandos UPDATE Uma das alterações é sincronizada e a outra é ignorada Não há efeito colateral se as associações estiverem consistentes
Relacionamento Bidirecional O lado que contém os detalhes do mapeamento é o lado que é sincronizado Relacionamentos many-to-one ou one-to-many Lado Many é sincronizado Relacionamento one-to-one Lado que possuir a chave estrangeira é sincronizado Relacionamento many-to-many Lado que mapear a tabela de junção é sincronizado Os lados do relacionamento não sincronizados possuem o atributo  mappedBy  na Annotation
Relacionamento Bidirecional Bid bid =  new  Bid(); bid.setAmount(Integer. valueOf (1000)); Item item =  new  Item(); item.setName( &quot;computador&quot; ); bid.setItem(item); item.getBids(). add (bid); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); //O item tem que ser salvo primeiro session.save(item); session.save(bid);
Relacionamento One-to-One
One-to-One O atributo deve conter a Annotation  @OneToOne Se o relacionamento for bidirecional os dois atributos devem conter a Annotation Em uma das propriedades deve ser adicionada a Annotation  @JoinColumn Na outra propriedade deve ser adicionado o atributo  mappedBy  à Annotation  @OneToOne
Classe User @Entity @Table (name =  &quot;USERS&quot; ) public   class  User { @Id @GeneratedValue (strategy=GenerationType. AUTO ) private  Long  id ; private  String  name ; @OneToOne @JoinColumn (name =  &quot;SHIPPING_ADDRESS_ID&quot; ) private  Address  address ; }
Classe Address @Entity public   class  Address { @Id @GeneratedValue private  Long  id ; @Column (nullable =  false ) private  String  street ; @OneToOne (mappedBy =  &quot;address&quot; ) private  User  user ; }
Ralacionamento Many-to-Many
Many-to-Many O atributo deve conter a Annotation  @ManyToMany Se o relacionamento for bidirecional os dois atributos devem conter a Annotation Em uma das propriedades deve ser adicionada a Annotation  @JoinTable Na outra propriedade deve ser adicionado o atributo  mappedBy  à Annotation  @ManyToMany
@JoinTable Contém o nome da tabela de relacionamento O atributo  joinColumns  mapeia a coluna associada à entidade mapeada O tipo do atributo é  @JoinColumn Annotation dentro de annotation O atributo  inverseJoinColumns  mapeia a coluna associada à outra entidade O tipo do atributo também é  @JoinColumn
Classe Category @Entity public   class  Category { @Id @GeneratedValue @Column (name =  &quot;CATEGORY_ID&quot; ) private  Long  id ; private  String  name ; @ManyToMany @JoinTable (name =  &quot;CATEGORY_ITEM&quot; , joinColumns =  @JoinColumn (name =  &quot;CATEGORY_ID&quot; ), inverseJoinColumns =  @JoinColumn (name =  &quot;ITEM_ID&quot; )) private  Set<Item>  items  =  new  HashSet<Item>(); }
Classe Item @Entity public   class  Item { @Id @GeneratedValue @Column (name =  &quot;ITEM_ID&quot; ) private  Long  id ; private  String  name ; @ManyToMany (mappedBy =  &quot;items&quot; ) private  Set<Category>  categories  =  new   HashSet<Category>(); }
Polimorfismo e LazyLoading Utilizando-se polimorfismo, as entidades são referenciadas através de suas super classes Não se deve fazer o cast da referência para alguma das subclasses, mesmo que se saiba o tipo do objeto Para associações carregadas por LazyLoading, é utilizado um objeto proxy O objeto proxy não pode ser atribuído a uma subclasse da classe referenciada
Associações: Polimorfismo
Entidade User @Entity @Table (name =  &quot;USERS&quot; ) public   class  User { @Id@GeneratedValue private  Long  id ; @OneToOne (fetch = FetchType. LAZY ) @JoinColumn (name =  &quot;DEFAULT_BILLING_ID&quot; ) private  BillingDetails  defaultBilling ; }
Polimorfismo e LazyLoading User user = (User) session.get(User. class , userId); BillingDetails bd = user.getDefaultBilling(); CreditCard cc = (CreditCard) session.load(CreditCard. class , bd.getId()); System. out .println(cc.getNumber()); User user = (User) session.get(User. class , userId); BillingDetails billingDetails = user.getDefaultBilling(); //imprime false System. out .println(billingDetails  instanceof  CreditCard); //ClassCastException CreditCard creditCard = (CreditCard) billingDetails;
Ciclo de Vida dos Objetos Em seu ciclo de vida, uma entidade pode assumir diversos estados relativos a sua persistência Transiente Persistente Desconectada Removida Entidades devem se comportar de maneira apropriada mesmo que ainda não estejam persistentes
Ciclo de Vida dos Objetos O ciclo de vida de uma entidade pode ser afetado através de chamadas às interfaces do Hibernate Operações de alterações e consultas na base de dados Operações para delimitar a existência de uma transação e de um  Sesssion Para o correta implementação, a aplicação deve se preocupar com o estado e o ciclo de vida do objeto
Ciclo de Vida dos Objetos: Conceitos Unidade de trabalho Conjunto de operações, geralmente atômicas Contexto de persistência Cache de todas alterações feitas em entidades em uma única unidade de trabalho
Estado Transiente É o estado que um objeto assume quando é criado através do operador  new Não está associado a nenhum registro da base de dados Os dados são perdidos quando o objeto não é mais referenciado e torna-se disponível para o Coletor de Lixo Não são gerenciados pelo Hibernate Não possuem comportamento transacional
Estado Persistente É uma entidade com um identificador na base de dados Possui uma chave primária São objetos gerenciados pelo Hibernate Podem ser objetos criados pela aplicação Tornam-se persistentes através de chamadas ao Hibernate Tornam-se persistentes se passarem a ser referenciados por outros objetos persistentes Depende do tipo de Cascade
Persistente Podem ser objetos retornados da base de dados Através de uma consulta Através de uma associação entre um objeto persistente Podem ser objetos atualizados na base de dados São sempre associados a um Contexto de Persistência São guardados em um cache Hibernate identifica qualquer alteração realizado no objeto
Removido Um objeto pode ser removido de duas maneiras Uma chamada explicita ao Hibernate Através de uma operação com Cascade Um objeto neste estado é removido ao final da Unidade de Trabalho É gerenciado pelo Contexto de Persistência até que a Unidade de Trabalho termine
Desconectado Objetos Persistentes passam para o estado Desconectado quando a Unidade de Trabalho é completada e o Contexto de Persistência é encerrado O objeto não é mais sincronizado com a base de dados Os dados do objeto podem se tornar desatualizados Seus dados ainda podem ser alterados pela aplicação Podem voltar ao estado Persistente
Contexto de Persistência Mantém um cache de instâncias gerenciadas Entidades no estado Persistente e Removido Conceito abstrato Não representado por um único objeto Cada objeto  Session  possui um Contexto de Persistência Permite Dirty Checking automático Delimita um escopo para a identidade das Entidades Não possui instâncias duplicadas
Dirty Checking Automático É possível através do Contexto de Persistência O dados de uma entidade são sincronizados com a base de dados No final da unidade de trabalho Em outros momentos: antes de uma consulta Somente os objetos alterados são atualizados na base de dados Atualização é retardada o máximo possível e é feita de forma automática Tempo de Lock do banco de dados é reduzido
Cache de Primeiro Nível Armazenado no Contexto de Persistência Mantém todas as instâncias de uma Unidade de Trabalho Provê ganho de performance para a aplicação Torna possível  Repeatable   Read Ao buscar mais de uma vez uma mesma entidade, os dados retornados são os mesmos O escopo é restrito à thread de execução
Cache de Primeiro Nível Um único objeto representa um determinado registro na base de dados Evita alterações conflitantes
Contexto Persistência: Escopo Algumas funcionalidades da aplicação necessitam de diversas requisições para serem completadas O escopo do Contexto de Persistência pode, ou não, ser o mesmo da funcionalidade Duas estratégias são as mais utilizadas para delimitar o escopo do Contexto de Persistência Um objeto  Session  por requisição Unidade de Trabalho de longa duração
Uma  Session  por Requisição Quando o servidor recebe alguma requisição que requer acesso a base de dados uma nova  Unidade de Trabalho é iniciada A Unidade de Trabalho é encerrada quando a requisição é processada e a resposta está pronta para ser enviada ao usuário As entidades são mantidas em estado Desconectado entre uma requisição e outra
Uma  Session  por Requisição Entidades mantidas entre duas requisições necessitam ser reconectadas para acessar serviços de persistência novamente Qualquer alteração feita em entidades desconectadas deve ser sincronizada manualmente Operações de atualização e/ou merge
Objetos Desconectados
Unidade de Trabalho de Longa Duração Objeto  Session  é mantido aberto durante várias requisições O Contexto de Persistência se propaga durante toda a conversação Conexões com a base de dados não são mantidas abertas A cada nova requisição o contexto é reconectado à base de dados As entidades são mantidas no estado Persistente Não requer merge ou atualização manual
Unidade de Trabalho de Longa Duração No final da conversação, o Contexto é sincronizado com a base de dados e encerrado A atomicidade das alterações é relativa à funcionalidade como um todo
Contexto expandido
Escopo limitado ao Contexto de Persistência Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); Long id = (Long) session.save( new  Message( &quot;Hibernate&quot; )); Message messageB = (Message) session.get(Message. class , id); Message messageC = (Message) session.get(Message. class , id); System. out .println(messageB.equals(messageC)); transaction.commit(); session.close(); Session session2 = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction2 = session2.beginTransaction(); Message messageD = (Message) session2.get(Message. class , id); System. out .println(messageC.equals(messageD));
Identidade de objetos Desconectados Sempre que se for trabalhar com objetos desconectados, deve-se sobrescrever o método equals() Para objetos desconectados a garantia de uma única instância por registro é perdida Implementação default não garante o comportamento desejado Mesmo que dois objetos possuam todas as propriedades iguais, o método pode retornar false
equals() Deve retornar verdadeiro se duas instâncias corresponderem ao mesmo registro Quais propriedades devem ser comparadas? Somente a chave primária Problema: entidades transientes não possuem valores para a chave primária Todas as propriedades Problema: entidades referentes ao mesmo registro não são consideradas iguais se alguma propriedade mudar Melhor abordagem: comparar a chave de negócio
Chave de negócio Uma propriedade, ou um conjunto delas, que é único para cada registro Chave candidata Não precisa ser imutável, basta que mude com pouca freqüência
Implementação public   boolean  equals(Object other) { if  (!(other  instanceof  User)){ return   false ; } User that = (User) other; return   this . name .equals(that.getName()); } public   int  hashCode() { return   this . name .hashCode(); }
Interagindo com o Hibernate O Hibernate provê diversos serviços Operações CRUD Criar Recuperar Atualizar Deletar Realização de consultas Controle de transação Gerenciamento do Contexto de Persistência
Interagindo com o Hibernate Os serviços são disponibilizados através de diversas Interfaces Session Transaction Query Criteria
Armazenando e Recuperando Objetos Para armazenar ou recuperar objetos, é necessário iniciar uma Unidade de Trabalho Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Um Contexto de Persistência é criado Irá gerenciar todas as entidades do Session Uma transação também deve ser iniciada mesmo para operações de leitura
Armazenando um Objeto // Quando é instanciado, o item está no estado Transiente Item item =  new  Item(); item.setName( &quot;Item 1&quot; ); // um novo Session é aberto Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); // O item passa para o estado Persistente e fica associado //ao Session e ao Contexto de Persistência session.save(item); //As mundanças são sincronizadas com a base de dados transaction.commit(); //O Session é fechado e o Contexto de Persistência encerrado. //O item passa para o estado Desconectado session.close();
Armazenando um Objeto
Recuperando uma Entidade Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction tx = session.beginTransaction(); //Item é recuperado no estado Transiente Item item = (Item) session.load(Item. class ,  new  Long(1234)); // Item item = (Item) session.get(Item.class, new Long(1234)); tx.commit(); //Item passa para o estado Desconectado session.close();
Recuperando uma Entidade
Recuperando uma Entidade Método get() Se o objeto procurado não for encontrado, retorna  null Método load() Se o objeto procurado não for encontrado, lança a exceção  ObjectNotFoundException A existência do objeto só é verificada quando alguma propriedade é acessada
Modificando um Objeto Persistente Todo objeto retornado pelos métodos  load()  ou  get()  ou através de uma consulta, assume o estado Persistente Os objetos podem ser modificados e as alterações são sincronizadas com a base de dados
Modificando um Objeto Persistente Long id =  armazenarItem (); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction tx = session.beginTransaction(); Item item = (Item) session.get(Item. class , id); item.setName( &quot;Playstation&quot; ); //Dados sincronizados com a base de dados. Dirty Cheking automático tx.commit(); session.close();
Modificando um Objeto Persistente
De Persistente para Transiente Long id =  armazenarItem (); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction tx = session.beginTransaction(); //Item no estado Persistente Item item = (Item) session.load(Item. class , id); //Item no estado Removido session.delete(item); tx.commit(); //Item no estado Transiente session.close();
De Persistente para Transiente
Trabalhando com Objetos Desconectados Modificações realizadas em objetos Desconectados não são sincronizadas na base de dados A atualização da base de dados pode ser feita de duas formas Reconectando o objeto –  reattach Realizando o  merge  do objeto
Reconectando um Objeto Um objeto é reconectado através do método  update()  da interface  Session O objeto passa a ser gerenciado pelo Session e assume o estado Persistente Deve-se ter certeza de que o  Session  ainda não possui um objeto gerenciado com o mesmo Id Somente uma instância do Contexto de Persistência pode estar associada a um determinado registro
Reconectando um Objeto Item item =  recuperarItem ( armazenarItem ()); item.setName( &quot;Novo nome&quot; ); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); session.update(item); item.setPrice(Integer. valueOf (114)); transaction.commit(); session.close();
Reconectando um Objeto
NonUniqueObjectException Long id =  armazenarItem (); Item item =  recuperarItem (id); item.setName( &quot;Novo nome&quot; ); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); Item item2 = (Item) session.get(Item. class , id); session.update(item); item.setPrice(Integer. valueOf (114)); transaction.commit(); session.close();
Realizando o merge() de um Objeto O merge de um objeto é feito através do método  merge()  da Interface  Session A a base de dados é atualizada com os valores contidos no objeto Os dados do objeto também atualizam o objeto persistente que possuir o mesmo identificador Se não existir um objeto persistente associado ao Session, ele é carregado
Método merge() O objeto desconectado não passa a ser associado ao Session Continua desconectado O objeto persistente é retornado
Método merge() Long id =  armazenarItem (); Item item =  recuperarItem (id); item.setName( &quot;Novo nome!!!&quot; ); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); Item item2 = (Item) session.get(Item. class , id); Item item3 = (Item) session.merge(item); transaction.commit(); session.close();
Método merge()
Persistência Transitiva Em aplicações não triviais, diversas Entidades podem estar associadas A aplicação deve poder manipular as associações Uma rede de objetos pode consistir de objetos em diferentes estados Persistentes Desconectados Transientes
Persistência Transitiva A Persistência Transitiva permite persistir objetos Desconectados e Transientes automaticamente Um objeto Transiente associado a um Persistente, torna-se persistente automaticamente Não há necessidade de chamar o método save() Diversas operações poder ser cascateadas Salvar Deletar Reconectar (update) Merge
Cascade Por default, em nenhuma operação é feito o cascade O Hibernate permite a configuração do tipo de comportamento desejado para cada associação Todos os tipos de associações podem ser configuradas one-to-one one-many many-to-many many-to-one
org.hibernate.annotations.CascadeType SAVE_UPDATE Objetos transientes são salvos Objetos desconectados são sincronizados DELETE Objetos relacionados são deletados após a chamada do método delete() ALL Habilita todos os tipos de cascade
org.hibernate.annotations.CascadeType DELETE_ORPHAN Deleta um objeto se ele for excluído da coleção Aplicável somente para relacionamentos One-to-Many Cascade é aplicável somente para relacionamentos entre entidades
Exercício
Consultas Umas das partes mais interessantes do acesso a dados Consultas complexas podem levar um bom tempo para serem escritas e podem ter considerável impacto na performance da aplicação Consultas são escritas utilizando conceitos de orientação a objetos Objetos no lugar de tabelas Propriedades no lugar de colunas Experiência em SQL não é desprezada
Consultas Podem ser feitas de três maneiras Hibernate Query Language (HQL) Criteria API e Query by Example Utilizando SQL
Consultas: Exemplos // Através de HQL session.createQuery( &quot;from Category c where c.name like 'Laptop%'&quot; ); // Utilizando-se Criteria session.createCriteria(Category. class ).add( Restrictions. like ( &quot;name&quot; ,  &quot;Laptop%&quot; )); // Através de SQL session.createSQLQuery( &quot;select {c.*} from CATEGORY {c} where NAME like 'Laptop%'&quot; ) .addEntity( &quot;c&quot; , Category. class );
Consultas Envolve alguns passos Criar a consulta com as restrições necessárias Adicionar parâmetros à consulta Executar a consulta e recuperar o resultado A forma de execução da consulta e obtenção dos dados pode ser configurada
Criando a Consulta Objetos  Query  e  Criteria  são   obtidos através do  Session org.hibernate.Query org.hibernate.Criteria Query query = session.createQuery( &quot;from User&quot; ); Criteria criteria = session.createCriteria(User. class );
Adicionando Parâmetros à Consulta Parâmetros não devem ser adicionados na própria String da consulta &quot;from Item i where i.description like '&quot; + search + &quot;'&quot; Evita-se ataque do tipo SQL Injection foo' and callSomeStoredProcedure() and 'bar' = 'bar Parâmetros podem ser adicionados através de sua posição ou de seu nome
Adicionando Parâmetros pelo Nome Nome do parâmetro é precedido de “:” O valores são adicionados através de métodos sets String queryString =  &quot;from Item item where item.description like  :search&quot; ; Query q = session.createQuery(queryString).setString( &quot;search&quot; , searchString); String queryString =  &quot;from Item item&quot; +  &quot; where item.description like :search&quot; +  &quot; and item.date > :minDate&quot; ; Query q = session.createQuery(queryString).setString( &quot;search&quot; , searchString).setDate( &quot;minDate&quot; , mDate);
Adicionando Parâmetros pela Posição A consulta contém “?” para indicar a existência de alguma parâmetro Os valores também são adicionado através de métodos sets String queryString =  &quot;from Item item&quot; +  &quot; where item.description like ?&quot;  +  &quot; and item.date > ?&quot; ; Query q = session.createQuery(queryString).setString(0,  searchString).setDate(1, minDate);
Executando a Consulta Se mais de um objeto pode ser retornado, chama-se o método  list() List list = query.list(); Se somente um objeto pode ser retornado, chama-se o método  uniqueResult() User user = (User) query.uniqueResult(); O método retorna  null  se nenhum objeto for encontrado Se a consulta retornar mais de um objetos, a exceção NonUniqueResultException é lançada
Executando a Consulta Query query = session.createQuery( &quot;from User&quot; ); List<User> list = query.list(); for  (User user : list) { System. out .println(user.getName()); } Query query2 = session.createQuery( &quot;from User user where user.name =:name&quot; ).setString( &quot;name&quot; , &quot;SUNSP&quot; ); User user = (User) query2.uniqueResult(); System. out .println(user.getName());
Consultas Básicas A consulta mais simples tem somente a cláusula FROM “ from Item” Para se referenciar as propriedades de uma entidade, um ALIAS deve ser criado “ from Item as item” “ from Item item” Palavra chave “as” é opcional A consulta não é case-sensitive “ FROM Item AS item” também pode ser utilizada
Consultas Polimórficas Consultas podem ser escritas utilizando polimorfismo “ from BillingDetails” Retorna todas as entidades que herdam de BillingDetails CreditCard BankAccount A superclasse não precisa estar mapeada “ from java.lang.Object” “ from java.io.Serializable”
Restrições Geralmente não se quer trazer todo o conteúdo da tabela Restrições devem ser adicionadas para restringir os objetos retornados HQL também utiliza-se a cláusula  WHERE As restrições são feitas sobre propriedades da entidade
Restrições Literais e condições podem ser incluídos Utiliza-se aspas simples para literais do tipo String “ from User u where u.email =  'foo@hibernate.org '” “ from Item i where i.isActive = true” Comparações podem ser realizadas “ from Bid bid where bid.amount between 1 and 10” “ from Bid bid where bid.amount > 100” “ from User u where u.email in ('foo@bar', 'bar@foo')”
Operador LIKE pode ser utilizado “ %” representa qualquer seqüência de caracteres _ (Under_Score) representa qualquer caractere “ from User u where u.firstname like 'G%'” Negação pode ser utilizada “ from User u where u.firstname not like '%Foo B%'” Operadores lógicos e parênteses “ from User user where user.firstname like 'G%' and user.lastname like 'K%'” Comparações
Comparações Operadores lógicos e parênteses “ from User u where (u.firstname like 'G%' and u.lastname like 'K%' ) or u.email in ('foo@hibernate.org', 'bar@hibernate.org' )” Coleções &quot;from Item i where i.bids is not empty&quot;
Comparações Funções podem ser chamadas a partir do HQL HQL permite a chamada de funções SQL na cláusula WHERE Funções podem ser definidas pelo usuário Depende do suporte do banco de dados Funções UPPER() e LOWER() &quot;from User u where lower(u.email) =  'foo@hibernate.org '&quot; Função SIZE() from Item i where size(i.bids) > 3 E muitas outras...
Comparações Outras funções CONCAT(s1, s2) SUBSTRING(s, offset, length) Offset começa a partir de 1 TRIM( [[BOTH|LEADING|TRAILING]  s) &quot;from Item i where TRIM(BOTH i.name) = 'Computador'&quot; LENGTH(s) LOCATE(search, s, offset) Procura a localização de uma substring dentro de uma string
Comparações Outras funções CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP() Valores retornados são referentes ao SGBD SECOND(d), MINUTE(d), HOUR(d), DAY(d), MONTH(d), YEAR(d) Extraem os valores de um argumento temporal
Ordenando o Resultado A Cláusula ORDER BY é utilizada para ordenar o resultado &quot;from User u order by u.name&quot; Ordem ascendente ou descendente Utiliza-se  asc  ou  desc from User u order by u.username desc Ordenando por mais de uma propriedade “ from User u order by u.lastname asc, u.firstname asc”
Junções A habilidade de realizar junções é uma das principais forças do modelo relacional Permite selecionar diferentes objetos associados e coleções em uma única consulta
Inner Join Contém somente os registros que estão relacionados com o outro lado da junção Contém somente os  Itens  que possuem  Bids
(left) Outer Join Retorna todos os Itens  Dados de Bid são preenchidos com NULL se não houver uma correspondência
Junção com HQL Coluna de junção não precisar ser informada na consulta Informação é extraída do mapeamento É necessário ser informado somente o nome da associação Nome do atributo que referencia a classe ou coleção de classes Joins podem ser executados de duas maneiras Join implícitos na Associação Join especificado na cláusula FROM
Join Implícito na Associação O Join é realizado através da associação entre duas entidades Exemplo: “ from Bid bid where bid.item.description like '%Foo%'” Bid é associado a Item através do atributo “item” Hibernate sabe que a associação está mapeada a partir da chave estrangeira ITEM_ID da tabela BID Joins implícitos são sempre realizados através de associações many-to-one ou one-to-one
Join Implícito na Associação Múltiplos joins são possíveis from Bid bid where bid.item.category.name like 'Laptop%'
Join especificado na Cláusula FROM Joins podem ser especificados explicitamente na cláusula FROM Exemplo &quot;select i from Item i join i.bids b where b.amount > 10&quot; Aliases devem ser especificados na cláusula FROM e utilizados na cláusula WHERE Cláusula SELECT é utilizada para que somente Itens sejam retornados
Join especificado na Cláusula FROM Na consulta, um Item pode ser retornado mais de uma vez Uma para cada Bid associado Somente uma instância é utilizada A consulta possui o mesmo formato para associações many-to-one e one-to-one
Outer Joins Para a utilização de Outer Joins utiliza-se a cláusula LEFT JOIN LEFT OUTER JOIN e RIGHT OUTER JOIN também podem ser utilizados A cláusula WITH é utilizada para adicionar restrições &quot;select i from Item i left join i.bids b with b.amount >= 9&quot; Itens que não possuem Bids também são retornados
Comparando Identificadores Na Orientação a Objetos não são os identificadores, mas as referências ao objetos que são comparadas Comparações podem ser feitas através dos atributos das entidades &quot;select i from Item i join i.bids b where i.seller = b.bidder&quot; i.seller e b.bidder representam referências para a entidade User Retorna os Itens em que o próprio vendedor deu um lance
Comparando Identificadores Entidades também podem ser adicionadas como parâmetros de uma consulta Query query = session.createQuery( &quot;from Item i where  i.seller = :seller&quot; ); query.setEntity( &quot;seller&quot; , user);
FIM... Referências Livro Java Persistence with Hibernate Edição revisada do livro Hibernate in Action Autores Christian Bauer Gavin King http://www.hibernate.org/ Documentação e Javadoc Fórum de discuções e dúvidas JSR 220: Enterprise JavaBeans Version 3.0 Para as Annotations do pacote javax.persistence

Mais conteúdo relacionado

PPTX
Introdução ao Entity Framework 4
PDF
PPT
Persistência de Objetos em Java
PPT
Padrão de Projeto - Adapter
PPT
Ferramenta de Apoio a UML e Modelo de Bases Relacionais
PDF
Padrões de Projeto de Software
PPT
Apresentação curso de Extensão em Java (UERJ-IME) v1
PDF
Paradigmas de Linguagens de Programação - Biblioteca de Classes e Frameworks
Introdução ao Entity Framework 4
Persistência de Objetos em Java
Padrão de Projeto - Adapter
Ferramenta de Apoio a UML e Modelo de Bases Relacionais
Padrões de Projeto de Software
Apresentação curso de Extensão em Java (UERJ-IME) v1
Paradigmas de Linguagens de Programação - Biblioteca de Classes e Frameworks

Mais procurados (20)

PDF
Padrão De Projeto Adapter
PDF
Palest"Tecnologias para Desenvolvimento Baseado em Componentes"
PPS
Componentes
ODP
A Linguagem UML
PPT
Integração de Tecnologias
KEY
Design Patterns - Adapter e Decorator
PDF
Paradigmas de Linguagens de Programação - Modularização, componentização e re...
PPTX
Padrões de Projeto: Adapter
PDF
Egenharia de Software Orientado a Aspectos
PPTX
ODI Series - Treinamento
PDF
Php Conf08 Enterprise Patterns
ODP
Seminário flyweight
PDF
Programação Orientada a Aspectos
PPTX
Hibernate
PDF
Design Pattern MVC – Arquitetura de Software Coesa e Flexível
PDF
Java programação orientada a objetos
PDF
Introdução à linguagem UML
ODP
Design Patterns
PDF
Apresentação Modelo de Gestão de dados para sistemas Colaborativos
PPT
Modelagem de sistemas
Padrão De Projeto Adapter
Palest"Tecnologias para Desenvolvimento Baseado em Componentes"
Componentes
A Linguagem UML
Integração de Tecnologias
Design Patterns - Adapter e Decorator
Paradigmas de Linguagens de Programação - Modularização, componentização e re...
Padrões de Projeto: Adapter
Egenharia de Software Orientado a Aspectos
ODI Series - Treinamento
Php Conf08 Enterprise Patterns
Seminário flyweight
Programação Orientada a Aspectos
Hibernate
Design Pattern MVC – Arquitetura de Software Coesa e Flexível
Java programação orientada a objetos
Introdução à linguagem UML
Design Patterns
Apresentação Modelo de Gestão de dados para sistemas Colaborativos
Modelagem de sistemas
Anúncio

Destaque (20)

PPT
Balanced vegetarian diet
PDF
ALM for CA Plex and CA 2E
PPTX
Politicas eib nov 2011 2012
PPT
Nerve injuries /certified fixed orthodontic courses by Indian dental academy
TXT
Comande oss
PPT
Receita de ano novo – Carlos Drummond de Andrade e MonkeyBusiness
PPT
Coffee Café Sample Page Layout Presentation
PDF
Пояснительная записка
PDF
Fashion 2.0. exploring current social media trends from fashion business pers...
PDF
Explorando Analysis Services: Power Pivot, Tabular y Multidimensional
PDF
Operaciones de pesca y re intervencion
PDF
Online Marketing BootCamp
PPTX
OKR - Objetivos e Resultados Chave
PDF
Ffhs seco videokonferenz_business_modeling_matthias_pohle_20141008_v1_final
PDF
Haustuerkatalog Sternstunden von Fenster-Schmidinger / Doors
PDF
Shopleiter Magazin Nr. 4 - SEO-, SEM- und eCommerce-Tipps
PDF
Team Jugendarbeit_Programm 2011.pdf
PPT
Hibernate
PPT
JPA - Java Persistence API
Balanced vegetarian diet
ALM for CA Plex and CA 2E
Politicas eib nov 2011 2012
Nerve injuries /certified fixed orthodontic courses by Indian dental academy
Comande oss
Receita de ano novo – Carlos Drummond de Andrade e MonkeyBusiness
Coffee Café Sample Page Layout Presentation
Пояснительная записка
Fashion 2.0. exploring current social media trends from fashion business pers...
Explorando Analysis Services: Power Pivot, Tabular y Multidimensional
Operaciones de pesca y re intervencion
Online Marketing BootCamp
OKR - Objetivos e Resultados Chave
Ffhs seco videokonferenz_business_modeling_matthias_pohle_20141008_v1_final
Haustuerkatalog Sternstunden von Fenster-Schmidinger / Doors
Shopleiter Magazin Nr. 4 - SEO-, SEM- und eCommerce-Tipps
Team Jugendarbeit_Programm 2011.pdf
Hibernate
JPA - Java Persistence API
Anúncio

Semelhante a Curso De Hibernate 3 (20)

PDF
Data accesss conect
PDF
Padrões de projeto - Martin Fowler - P of EAA
PPTX
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
PDF
Sistemas Distribuídos - Comunicação Distribuída - EJB
PPT
Java No Setor Público: Produtividade, Flexibilidade e Baixo Custo
PPTX
Palestra Sobre REST
PPT
teste86940.78038637294
PPT
Jsp+Jdbc+Servlets
PPTX
Apresentação em Projeto de Sistemas – Entity Framework
PPT
Desenvolvendo Produtos Com Java EE
PDF
Hibernate conceitos
PPT
Aula1
PPT
Banco de Dados Ágeis e Refatoração
PPT
01 Orientacao A Objetos Programacao
PPT
ZF Básico - 1. Introdução
PPTX
PPTX
Treinamento ASP.NET 2014
PDF
Odi tutorial glossário e termos técnicos
PPTX
Extreme 360 Arquitetura para Aplicações Delphi Spring4D - OOP e RAD
Data accesss conect
Padrões de projeto - Martin Fowler - P of EAA
Sistemas Distribuídos - Comunicação Distribuída - EJB (JBoss 7)
Sistemas Distribuídos - Comunicação Distribuída - EJB
Java No Setor Público: Produtividade, Flexibilidade e Baixo Custo
Palestra Sobre REST
teste86940.78038637294
Jsp+Jdbc+Servlets
Apresentação em Projeto de Sistemas – Entity Framework
Desenvolvendo Produtos Com Java EE
Hibernate conceitos
Aula1
Banco de Dados Ágeis e Refatoração
01 Orientacao A Objetos Programacao
ZF Básico - 1. Introdução
Treinamento ASP.NET 2014
Odi tutorial glossário e termos técnicos
Extreme 360 Arquitetura para Aplicações Delphi Spring4D - OOP e RAD

Último (19)

PDF
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
PPTX
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
PPTX
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
PPTX
Aula 18 - Manipulacao De Arquivos python
PDF
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
PPTX
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
PDF
Aula04-Academia Heri- Tecnologia Geral 2025
PPTX
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
PDF
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
PDF
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
PDF
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
PDF
Custos e liquidação no SAP Transportation Management, TM130 Col18
PDF
Apple Pippin Uma breve introdução. - David Glotz
PDF
Processos na gestão de transportes, TM100 Col18
PDF
COBITxITIL-Entenda as diferença em uso governança TI
PPTX
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
PPTX
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
PDF
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
PDF
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...
20250805_ServiceNow e a Arquitetura Orientada a Serviços (SOA) A Base para Ap...
Gestao-de-Bugs-em-Software-Introducao.pptxxxxxxxx
Programação - Linguagem C - Variáveis, Palavras Reservadas, tipos de dados, c...
Aula 18 - Manipulacao De Arquivos python
Custos e faturamento no SAP S/4HANA Transportation Management, S4TM3 Col26
Informática Aplicada Informática Aplicada Plano de Ensino - estudo de caso NR...
Aula04-Academia Heri- Tecnologia Geral 2025
Como-se-implementa-um-softwareeeeeeeeeeeeeeeeeeeeeeeee.pptx
Otimizador de planejamento e execução no SAP Transportation Management, TM120...
Gestão de transportes básica no SAP S/4HANA, S4611 Col20
Fullfilment AI - Forum ecommerce 2025 // Distrito e Total Express
Custos e liquidação no SAP Transportation Management, TM130 Col18
Apple Pippin Uma breve introdução. - David Glotz
Processos na gestão de transportes, TM100 Col18
COBITxITIL-Entenda as diferença em uso governança TI
BANCO DE DADOS - AULAS INICIAIS-sgbd.pptx
Aula16ManipulaçãoDadosssssssssssssssssssssssssssss
Mergulho profundo técnico para gestão de transportes no SAP S/4HANA, S4TM6 Col14
Fundamentos de gerenciamento de ordens e planejamento no SAP TransportationMa...

Curso De Hibernate 3

  • 1. Curso: Persistência em Java com Hibernate Instrutor: Fabrício Lemos 23/04/2007
  • 2. Persistência É um tópico vital para o desenvolvimento de aplicações Quase todas as aplicações necessitam que dados sejam persistidos Necessidades Armazenamento Busca Organização Compartilhamento dos dados
  • 3. Persistência Necessidades Integridade dos dados Controle de concorrência Performance e a escalabilidade são fortemente afetadas pela estratégia de acesso a dados escolhida
  • 4. Banco de Dados Relacionais Geralmente são utilizados banco de dados SQL Flexível Robusto Eficiente Confiável Maneira mais utilizada e conhecida de armazenar dados
  • 5. Banco de Dados Relacionais Dados são armazenados de forma independente Independência de linguagem Independência de aplicação Os dados geralmente possuem longevidade maior do que as aplicações que os acessam A utilização de algum framework não elimina a necessidade de conhecimento de SQL e do modelo relacional
  • 6. Persistindo dados com Java Realizado através da API Java Database Connectivity (JDBC) Tarefas de baixo nível Preparar consultas Associar parâmetros Executar a consulta Percorrer e retornar o resultado Tarefas de alto nível Salvar e recuperar objetos
  • 7. Persistindo objetos com Java (ou qualquer outra linguagem OO) Linguagem orientada a objetos Deve-se poder armazenar o estado de um objeto, mesmo após o objeto ser destruído Deve ser possível criar um novo objeto com o mesmo estado do anterior Operações não devem ser limitadas a um único objeto Associações devem ser salvas
  • 8. Persistindo objetos com Java A aplicação deve trabalhar diretamente com objetos, ao invés de linhas e colunas da base de dados Lógica de negócio deve ser implementada na aplicação, utilizando-se Java, e não diretamente na base de dados Limitar o uso de stored procedures Conceitos da Orientação a Objetos não devem ser restringidos pela solução adotada
  • 9. Diferença dos Paradigmas: OO/Relacional Granularidade Objetos de baixa granularidade podem ser persistidos em tabelas de grande granularidade ou vice-versa Uma tabela armazena diversos tipos de objetos Um objeto é armazenado em diversas tabelas Herança Modelo relacional não possui o conceito de herança
  • 10. Diferença dos Paradigmas Polimorfismo Necessidade de um objeto referenciar outros através de superclasses Uma referência pode estar associada o objetos de tipos diferentes Chaves estrangeiras referenciam uma tabela específica
  • 11. Diferença dos Paradigmas OO/Relacional Identidade dos objetos Java Operador == Método equals() Banco de dados Chave primária Atualização de algum atributo que faz parte da chave requer que outras tabelas sejam atualizadas
  • 12. Diferença dos Paradigmas OO/Relacional Associações OO possui associações unidirecionais e bidirecionais Junções de tabelas e projeções não possuem o conceito de “direção” de uma associação Associações em OO podem ser do tipo many-to-many Associações entre tabelas só podem ser one-to-many e one-to-one Necessidade de criar uma tabela de relacionamento para associações many-to-many Tabela não presente no modelo do domínio da aplicação
  • 13. Diferença dos Paradigmas: Custo Necessário escrever muito código para (tentar) contornar o problema Código se torna repetitivo e de difícil manutenção A escrita de código SQL pode tornar a aplicação dependente do banco de dados Modelagem dos objetos fica prejudicada Outras camada ficam fortemente acopladas à Camada de Persistência Produtividade pode ser fortemente afetada
  • 14. Estratégias de Persistência JDBC e SQL Faz parte da plataforma Java Necessário escrever bastante código de baixo nível Stored Procedures Lógica de negócio sai da aplicação e vai para a base de dados Perde-se a portabilidade
  • 15. Estratégias de Persistência Framework corporativo Necessário grande esforço da empresa Demora-se muito para que a solução implementada atinga maturidade Documentação muitas vezes é esquecida Falta de suporte
  • 16. Estratégias de Persistência Java Persistence API (JPA) Especificação elaborada pelo Java Community Process para persistência em Java Baseou-se em diversas soluções existentes Frameworks existentes passaram a implementar a especificação Recursos são um sub-conjunto dos encontrados nos frameworks que a implementam Atualizações são lentas e burocráticas
  • 17. Estratégias de Persistência Frameworks de terceiros TopLink Framework de persistência Objeto/Relacional Desenvolvido pela Oracle Gratuito para avaliação e nas fases de desenvolvimento Hibernate
  • 18. Hibernate Framework de mapeamento Objeto-Relacional Preenche a lacuna entre a base de dados relacional e a aplicação orientada a objetos Framework de persistência Java mais utilizado e documentado Mantido pela Jboss sob a licensa LGPL Suporta classes desenvolvidas com agregação, herança, polimorfismo, composição e coleções
  • 19. Hibernate Permite a escrita de consultas tanto através de uma linguagem própria (HQL) como também através de SQL Framework não intrusivo Não restringe a arquitetura da aplicação Implementa a especificação Java Persistence API Grande e ativa comunidade Mais de 25 mil desenvolvedores registrados nos foruns oficiais
  • 20. Mapeamento Objeto Relacional Permite a persistência de objetos em tabelas de uma base de dados relacional Automática e Transparente Utiliza metadados para descrever o relacionamento entre os objetos e a base de dados XML Xdoclet Annotations
  • 21. Mapeamento Objeto Relacional O SQL é gerado automaticamente a partir dos metadados A escrita e manutenção de metadados necessita de esforço nas etapas de implementação Esforço bem menor do que o necessário para fazer a conversão manualmente A conversão entre os tipos de representação pode trazer perca de performance Ferramentas maduras otimizam a conversão em diversos pontos
  • 22. Mapeamento Objeto Relacional Possui quatro partes principais API para realização de operações básicas (CRUD) Linguagem ou API para a realização de consultas Maneira para a especificação de metadados Técnicas de otimização Dirty checking Carregamento tardio (lazy association fetching)
  • 23. Mapeamento Objeto Relacional: Vantagens Produtividade Elimina a necessidade de escrita de grande parte do código relativo a persistência Maior tempo disponível para implementar a lógica da aplicação Manutenibilidade Menos código Maior entendimento da aplicação Camada de abstração Facilita a refatoração
  • 24. Vantagens Performance Tarefas manuais nem sempre tem performance melhor do que tarefas automatizadas Considerando limitações de custo e tempo Frameworks maduros são bastantes otimizados Com o aumento de produtividade, você pode dedicar mais tempo para resolver possíveis gargalos Portabilidade Independência nem sempre é algo simples de ser alcançado, mesmo em aplicações Java Suporte a diversos tipos de banco de dados
  • 25. Hibernate: Módulos Hibernate Core Contém os serviços básicos Metadados escritos em XML Consultas HQL: Hibernate Query Language Interfaces utilizando critérios e exemplos Não depende de outros módulos Não depende de uma versão específica do JDK Executável em qualquer servidor Web e/ou de Aplicação e também em aplicações desktop
  • 26. Módulos Hibernate Annotations Permite a escrita de metadados através de Annotations Beneficia-se da tipagem do Java Compatível com refatorações de código Semântica familiar para quem já está acostumado com metadados em XML Utiliza as Annotations da especificação JPA Possui Annotations próprias para configurações avançadas não presentes na especificação Necessita do JDK 5.0
  • 27. Módulos Hibernate Entity Manager Implementação da especificação JPA Permite a escrita de código compatível com qualquer framework de persistência que implemente a especificação Utiliza o pacote javax.persistence Não disponibiliza todas as funcionalidades do Hibernate
  • 28. Separação em camadas É uma boa prática dividir aplicações de médio e grande porte em camadas Padrão Layers (Pattern-Oriented Software architecture) Divisão mais utilizada Apresentação Negócio Persistência
  • 29. Separação em camadas Permite a especificação de intefaces para os diversos tipos de serviços A implementação pode ser mudada sem afetar significativamente o código de outras camadas A comunicação ocorre das camadas superiores para as camadas inferiores Uma camada só depende da camada imediatamente inferior Camada de apresentação não sabe da existência da camada de persistência
  • 30.  
  • 35. Criando uma entidade @Entity @Table (name = &quot;MESSAGES&quot; ) public class Message { @Id @GeneratedValue @Column (name = &quot;MESSAGE_ID&quot; ) private Long id ; @Column (name = &quot;MESSAGE_TEXT&quot; ) private String text ; @ManyToOne (cascade = CascadeType. ALL ) @JoinColumn (name = &quot;NEXT_MESSAGE_ID&quot; ) private Message nextMessage ; private Message() {} public Message(String text) { this . text = text; } //gets e sets }
  • 36. Annotations da classe Entity Informa que a classe pode ser persistida pelo Hibernate Table Informa o nome da tabela em que os objetos da classe devem ser armazenados @Entity @Table (name = &quot;MESSAGES&quot; ) public class Message {
  • 37. Construtores Obrigatório um construtor sem argumentos private Message() {} public Message(String text) { this . text = text; }
  • 38. Propriedades Representa o identificador do objeto Preenchido automaticamente quando o objeto é salvo Mapeado para a chave primária da tabela Se duas instâncias tiverem o mesmo identificador, elas representam a mesma linha da tabela @Id @GeneratedValue @Column (name = &quot;MESSAGE_ID&quot; ) private Long id ;
  • 39. Atributos O atributo text é armazenado na coluna MESSAGE_TEXT @Column (name = &quot;MESSAGE_TEXT&quot; ) private String text ; O atributo nextMessage é uma associação many-to-one Mapeado pela chave estrangeira NEXT_MESSAGE_ID @ManyToOne (cascade = CascadeType. ALL ) @JoinColumn (name = &quot;NEXT_MESSAGE_ID&quot; ) private Message nextMessage ;
  • 40. Transparência Não há a necessidade de se herdar de uma superclasse ou de implementar um interface POJO - Plain Ordinary Java Objects Classes podem ser reutilizadas fora do contexto de persistência Interface com o usuário Testes de unidades As entidades não precisam nem saber que serão persistidas Grande nível de portabilidade
  • 41. Configurando o Hibernate Configuração feita através do arquivo hibernate.cfg.xml Deve estar localizado na raiz do classpath Localização default Para projetos maven, utilizar a pasta src/main/resources Configurações contém Parâmetros de acesso a base de dados Pool de conexões Entidades a serem persistidas
  • 42. hibernate.cfg.xml < hibernate-configuration > < session-factory > <!-- Parâmetros de acesso a base de dados --> < property name = &quot;connection.driver_class&quot; > org.postgresql.Driver </ property > < property name = &quot;connection.url&quot; > jdbc:postgresql://localhost:5432/curso </ property > < property name = &quot;connection.username&quot; > postgresql </ property > < property name = &quot;connection.password&quot; > postgresql </ property > < property name = &quot;dialect&quot; > org.hibernate.dialect.PostgreSQLDialect </ property > ...
  • 43. hibernate.cfg.xml ... <!-- Configuração do Pool de conexões --> < property name = &quot;c3p0.min_size&quot; > 5 </ property > < property name = &quot;c3p0.max_size&quot; > 20 </ property > < property name = &quot;c3p0.timeout&quot; > 300 </ property > < property name = &quot;c3p0.max_statements&quot; > 50 </ property > < property name = &quot;c3p0.idle_test_period&quot; > 3000 </ property > <!-- Exibe no console o SQL gerado pelo hibernate--> < property name = &quot;show_sql&quot; > true </ property > <!-- Cria e executa a DDL (tabelas, colunas, etc...)--> < property name = &quot;hbm2ddl.auto&quot; > create </ property > <!-- Informa as Entidades da aplicação --> < mapping class = &quot;br.gov.serpro.curso.hibernate.exemplo1.Message&quot; /> </ session-factory > </ hibernate-configuration >
  • 44. Armazenando uma Mensagem //Obtendo o Session Session session = HibernateUtil.getSessionFactory().openSession(); //Iniciando a transação Transaction tx = session.beginTransaction(); // Criando uma mensagem Message message = new Message( &quot;Hello World&quot; ); // Salvando a Mensagem Long msgId = (Long) session.save(message); //Fazendo o commit da transação tx.commit(); //Fechando o Session session.close(); HibernateUtil.shutdown();
  • 45. Objetos utilizados Session Contém métodos utilizados para armazenar e recuperar entidades Armazena uma lista de comandos SQL que serão executados, em algum momento, na base de dados Mantém as entidades gerenciadas pelo Hibernate Recuperadas, inseridas ou atualizadas através do Session Único para cada thread
  • 46. Objetos utilizados Transaction Utilizado para delimitar as transações com a base de dados Geralmente gerenciado pelo container EJB Spring SessionFactory Utilizado para criar os Session Reutilizável por toda a aplicação
  • 47. HibernateUtil public class HibernateUtil { private static SessionFactory sessionFactory ; static { sessionFactory = new AnnotationConfiguration().configure() .buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sessionFactory ; } public static void shutdown() { getSessionFactory ().close(); } }
  • 48. Recuperando as Mensagens Session newSession = HibernateUtil.getSessionFactory().openSession(); Transaction newTransaction = newSession.beginTransaction(); //Criando e executando uma consulta Query query = newSession .createQuery( &quot;from Message m order by m.text asc&quot; ); List<Message> messages = query.list(); //Retornando a quantidade de mensagens encontradas System. out .println(messages.size() + &quot; message(s) found:&quot; ); //Retornando as mensagens encontradas for (Message msg : messages) { System. out .println(msg.getText()); } newTransaction.commit(); newSession.close(); HibernateUtil.shutdown();
  • 49. Objetos Utilizados Query Cria as consultas Associa os parâmetros Executa as consultas
  • 50. Dirty Checking e Cascade Session thirdSession = HibernateUtil.getSessionFactory().openSession(); Transaction thirdTransaction = thirdSession.beginTransaction(); // recuperando a mensagem message = (Message) thirdSession.get(Message. class , msgId); //Alterando o texto message.setText( &quot;Greetings Earthling&quot; ); //Criando uma nova mensagem e associando à antiga message.setNextMessage( new Message( &quot;Take me to your leader&quot; )); thirdTransaction.commit(); thirdSession.close(); HibernateUtil.shutdown();
  • 51. Dirty Checking e Cascade Dirty Checking O Hibernate automaticamente verifica quando um atributo é modificado O atributo é atualizado na base de dados sem a necessidade de uma chamada explicita É possível somente dentro de uma transação e para objetos gerenciados pelo Session Cascade Novas entidades são persistidas automaticamente Devem ser alcançáveis a partir de uma entidade gerenciada
  • 52. Metadados Utilizados para especificar o mapeamento entre Classes e tabelas Propriedades e colunas Associações e chaves estrangeiras Tipos de atributos Java e tipos de atributos SQL Pode ser escrita de duas formas Arquivos XML Xdoclet Java Annotations
  • 53. Porque não usar XML Pode ser tornar pouco legível e de difícil edição Requer maior digitação Falta de valores default para atributos e elementos Não necessariamente mais flexível e mais fácil de manter do que código Java Mais fácil encontrar um bom editor Java do que um bom editor de XML
  • 54. Metadados com Annotations A meta-informação fica perto dos dados que ela descreve Compatível com refatoração de código Renomear, deletar e remover classes e propriedades Sem necessidade de fazer parser em XML Inicialização mais rápida Lido através de reflection na inicialização do Hibernate Disponível a partir da JDK 5.0
  • 55. Mapeando Propriedades Ao mapear uma classe através da Annotation @ Entity , todas as propriedades serão consideradas persistentes Propriedades não persistentes devem receber a Annotation @ Transient ou o modificador transient Por default, o nome da coluna será o mesmo da propriedade Meio de acesso é o mesmo do @ID Definido na propriedade ou no método get()
  • 56. @Column Aplicável para propriedades simples Atributos name Nome da coluna a qual a propriedade é mapeada unique Se o valor deve ser único ou não nullable Se a propriedade pode ser nula ou não
  • 59. Datas Propriedades podem ser do tipo java.util.Date ou java.util.Calendar Precisão default é TIMESTAMP Precisão pode ser alterada através da Annotation @Temporal @Temporal (TemporalType. DATE ) private Date date1 ; @Temporal (TemporalType. TIME ) private Date date2 ; @Temporal (TemporalType. TIMESTAMP ) private Date date3 ;
  • 60. Identidade das Entidades Identidade versus Equivalência em Java Identidade Operador == Definido pela máquina virtual Dois objetos são idênticos se eles apontam para o mesmo local da memória Equivalência Definida pelas classes que sobreescrevem o método equals() Dois objetos diferentes possuem o mesmo valor Dois objetos String podem ter a mesma seqüência de caracteres
  • 61. Identidade das Entidades Identidade na base de dados Duas Entidades são idênticas se elas representam a mesma linha na base de dados Se são armazenadas na mesma tabela e possuem a mesma chave primária
  • 62. Adicionando um Identificador O valor é gerado automaticamente pelo Hibernate Não deve ser mudado pela aplicação @Entity @Table (name= &quot;CATEGORY&quot; ) public class Category { @Id @GeneratedValue (strategy = GenerationType. AUTO ) @Column (name = &quot;CATEGORY_ID&quot; ) private Long id ; public Long getId() { return id ; } }
  • 63. Escolhendo a chave primária Uma chave candidata é uma coluna, ou um conjunto de colunas, que pode ser utilizada para identificar um registro na base de dados Requisitos O valor nunca deve ser nulo Cada registro deve ter um valor único O valor nunca deve mudar
  • 64. Escolhendo a chave primária Chaves naturais são aquelas que possuem significado para o domínio da aplicação CPF de um usuário Seqüencial gerado pela aplicação Dificilmente chaves naturais atendem os requisitos necessários
  • 65. Escolhendo a chave primária Chaves cegas Melhor alternativa Não possuem significado para o domínio da aplicação Geradas pelo banco de dados ou pela aplicação
  • 66. Geração automática de chaves Hibernate suporta diversas estratégias para geração automática de chaves A estratégia deve ser especificada através da Annotations @ GeneratedValue
  • 67. Estratégias IDENTITY Suporte para colunas IDENTITY nos bancos de dados DB2, MySQL, MS SQL Server, Sybase e HypersonicSQL Os tipos devem ser long , short ou int SEQUENCE Utiliza um Sequence para a geração de chaves Suporte para DB2, PostgreSQL e Oracle dentre outros Nome default da sequence é hibernate_sequence
  • 68. Estratégias increment Na inicialização o Hibernate lê qual o maior valor para a chave da tabela O valor é atribuído e incrementado em cada inserção Não deve ser utilizado se o Hibernate não tiver acesso exclusivo para a base de dados
  • 69. Estratégias AUTO Escolhe entre as estratégias IDENTITY, SEQUENCE ou HILO Estratégia escolhida depende do banco de dados utilizado Utilizado para manter a portabilidade Outras hilo, seqhilo, uuid.hex, guid, select IdentifierGenerator Permite a implementação de sua própria estratégia
  • 70. Mapeando Componentes Entidades são classes persistentes que representam objetos do domínio da aplicação Possuem identidade própria Hibernate suporta a construção de um modelo de objetos de alta granularidade Propriedades de uma Entidade podem ser encapsuladas em outros objetos Tais objetos não possuem identidade própria Chamados de Objetos Valores ou Componentes Mais classes do que tabelas
  • 72. Mapeando Componentes User Representa uma Entidade Possui identidade própria Chave primária na base de dados Uma referência para User é persistida como uma chave estrangeira Tem seu próprio ciclo de vida Existe independentemente de qualquer outra entidade
  • 73. Mapeando Componentes Address Representa um Componente Não possui identidade própria Pertence a Entidade User Estado é persistido no registro referente ao User a qual está associado Ciclo de vida dependente de User Se dois Usuários morarem no mesmo apartamento, cada um tem uma referência para um objeto distinto Comportamento similar a tipos como String e Integer
  • 74. Mapeando Componentes @Embeddable public class Address { @Column (name = &quot;ADDRESS_STREET&quot; , nullable = false ) private String street ; @Column (name = &quot;ADDRESS_CITY&quot; , nullable = false ) private String city ; //gets e sets... }
  • 75. Mapeando Componentes @Entity @Table (name = &quot;USERS&quot; ) public class User { @Id @GeneratedValue (strategy=GenerationType. AUTO ) private Long id ; private String name ; private String email ; private Address address ; //gets e sets }
  • 76. Mapeando Herança A utilização de uma tabela para cada entidade não funciona tão bem para heranças entre entidades Bancos de dados SQL, de maneira geral, não possuem o conceito de herança Soluções proprietária podem comprometer a portabilidade da aplicação
  • 77. Estratégias Tabela por classe concreta Tabela por classe concreta, utilizando junção Tabela por hierarquia Tabela por classe (concreta ou não)
  • 78. Uma tabela por Classe Concreta: Modelagem
  • 79. Uma tabela por Classe Concreta Estratégia mais simples Todas propriedades de uma classe, incluindo as herdadas, são mapeadas para a mesma tabela Mapeamento convencional pode ser utilizado Não suporta associações polimórficas adequadamente Associação para classe abstrata necessitaria que a chave estrangeira referenciasse duas tabelas
  • 80. Uma tabela por Classe Concreta Diferentes colunas em diferentes tabelas passariam a possuir a mesma semântica Recomendável somente para a hierarquia superior Associações polimórficas geralmente não necessárias e não recomendadas Modificações na superclasse são muito raras select CREDIT_CARD_ID, OWNER, NUMBER, EXP_MONTH, EXP_YEAR ... from CREDIT_CARD select BANK_ACCOUNT_ID, OWNER, ACCOUNT, BANKNAME, ... from BANK_ACCOUNT
  • 81. Mapeando a Superclasse Mapear a super classe através da Annotattion @ MappedSuperclass @MappedSuperclass public abstract class BillingDetails { @Column (name = &quot;OWNER&quot; , nullable = false ) private String owner ; //gets e sets... }
  • 82. Mapeando as Subclasses Nenhuma configuração extra é necessária @Entity public class BankAccount extends BillingDetails{ @Id @GeneratedValue private Long id ; private Integer account ; private String bank ; }
  • 83. Mapeando as Subclasses Mapeamento das propriedades herdadas pode ser alterado Adicionar a Annotation @AttributeOverride @Entity @AttributeOverride (name = &quot;owner&quot; , column = @Column (name = &quot;CC_OWNER&quot; , nullable = false )) public class CreditCard extends BillingDetails { @Id @GeneratedValue private Long id ; private String number ; }
  • 84. Uma tabela por Classe Concreta: Union Com a utilização de consultas com Union, alguns problemas podem ser eliminados Suporte a associações polimórficas Hibernate utiliza o Union para simular uma única tabela As subclasses herdam o Id da super-classe
  • 85. Mapeando a Super Classe É utilizada a Annotation @Inheritance @Entity @Inheritance (strategy = InheritanceType. TABLE_PER_CLASS ) public class BillingDetails { @Id @ GeneratedValue @Column (name = &quot;BILLING_DETAILS_ID&quot; ) private Long id = null ; @Column (name = &quot;OWNER&quot; , nullable = false ) private String owner ; }
  • 86. Mapeando as Subclasses Não é necessário mapear o identificador O Identificador é mapeado na super-classe @Entity public class CreditCard extends BillingDetails{ @Column (name = &quot;CC_NUMBER&quot; ) private String number ; }
  • 88. Tabela por Hierarquia Toda uma hierarquia é mapeada em uma única tabela A tabela possui colunas para todas as propriedades de todas as entidades da hierarquia A subclasse de cada registro é identificada através de uma coluna discriminatória Vantagem Possui a melhor performance
  • 89. Tabela por Hierarquia Desvantagens Valores para colunas das subclasses devem sempre permitir NULL Perca da restrição NOT NULL Dados são desnormalizados
  • 90. Mapeando a Superclasse O valor do atributo strategy deve ser mudado para InheritanceType.SINGLE_TABLE @Entity @Inheritance (strategy = InheritanceType. SINGLE_TABLE ) public abstract class BillingDetails { @Id @GeneratedValue @Column (name = &quot;BILLING_DETAILS_ID&quot; ) private Long id = null ; @Column (name = &quot;OWNER&quot; , nullable = false ) private String owner ; }
  • 92. Tabela por classe Uma tabela para todas as classes, incluindo as abstratas, que possuem propriedades para serem persistidas Relação de herança é representada por uma chave estrangeira As tabelas não contém colunas para as propriedades herdadas A chave primária é também uma chave estrangeira para a super classe
  • 93. Tabela por classe Vantagens Os dados são normalizados Restrições podem ser mantidas Desvantagens Performance pode ser muito baixa para hierarquias complexas Necessidade de muitas junções
  • 94. Mapeando a Superclasse O valor do atributo strategy deve ser mudado para InheritanceType.JOINED @Entity @Inheritance (strategy = InheritanceType. JOINED ) public abstract class BillingDetails { @Id @GeneratedValue @Column (name = &quot;BILLING_DETAILS_ID&quot; ) private Long id = null ; @Column (name = &quot;OWNER&quot; , nullable = false ) private String owner ; }
  • 95. Mapeando as Subclasses Id é mapeado na super-classe @Entity public class CreditCard extends BillingDetails{ @Column (name = &quot;CC_NUMBER&quot; ) private String number ; }
  • 96. Escolhendo a melhor estratégia Tabela por classe concreta, utilizando junção Se associações ou consultas polimórficas nunca ou raramente são utilizadas Tabela por hierarquia Se associações ou consultas polimórficas são utilizadas e Se as subclasses declaram poucas propriedades Maior diferença entre as subclasses é o comportamento
  • 97. Escolhendo a Melhor Estratégia Tabela por Classe Se associações ou consultas polimórficas são utilizadas e Se as subclasses declaram muitas propriedades Maior diferença entre as subclasses são os dados que elas armazenam Se a largura e o comprimento da hierarquia não for muito grande
  • 98. Mapeando coleções Objetos podem possuir coleções As coleções podem ter duas naturezas Coleções de valores Tipos primitivos Componentes Coleções de entidades
  • 99. Coleção de tipos primitivos: Set Um Item possui um conjunto de imagens Somente o nome da imagem é persistido Nomes não devem ser duplicados para um determinado Item
  • 100. Annotations @CollectionOfElements Utilizada para coleções de tipos primitivos ou para coleções de objetos valores @JoinTable Informa a tabela em que a coleção é persistida Atributos Name Nome da tabela JoinColumns Coluna que é chave estrangeira Chave estrangeira referencia a tabela da entidade que possui a coleção
  • 101. Annotations @JoinColumn É o tipo do atributo JoinColumns da Annotation @JoinTable Annotation dentro de outra Annotation Mapeia a coluna utilizada para junções Atributos Name Nome da coluna
  • 102. Classe Item @Entity public class Item { @Id @GeneratedValue @Column (name = &quot;ITEM_ID&quot; ) private Long id ; private String name ; @CollectionOfElements @JoinTable (name = &quot;ITEM_IMAGE&quot; , joinColumns = @JoinColumn (name = &quot;ITEM_ID&quot; )) @Column (name = &quot;FILENAME&quot; , nullable = false ) private Set<String> images = new HashSet<String>(); }
  • 103. Coleção de tipos primitivos: List Caso a aplicação necessite guardar a ordem dos elementos Necessário uma coluna para informar a posição de cada elemento
  • 104. Classe Item Deve-se adicionar a Annotation @IndexColumn @Entity public class Item { ... @CollectionOfElements @JoinTable (name = &quot;ITEM_IMAGE&quot; , joinColumns = @JoinColumn (name = &quot;ITEM_ID&quot; )) @Column (name = &quot;FILENAME&quot; , nullable = false ) @IndexColumn (name = &quot;POSITION&quot; ) private List<String> images = new ArrayList<String>(); }
  • 105. Coleção de tipos primitivos: Map Se o Item possuir um Map de imagens É necessário guardar o elemento e sua chave
  • 106. Classe Item Utilizar a Annotation @MapKey Atributo columns informa o nome da coluna que armazena a chave @Entity public class Item { ... @CollectionOfElements @JoinTable (name = &quot;ITEM_IMAGE&quot; , joinColumns = @JoinColumn (name = &quot;ITEM_ID&quot; )) @Column (name = &quot;FILENAME&quot; , nullable = false ) @MapKey (columns = @Column (name = &quot;IMAGENAME&quot; )) private Map<String, String> images = new HashMap<String, String>(); }
  • 107. Associação entre Entidades Podem ser de diversas multiplicidades One-to-many One-to-one Many-to-many Many-to-one Também são implementadas através de atributos Para associações one-to-many e many-to-many é necessário a utilização de coleções
  • 108. Implementando associações Coleções devem ser acessadas através de suas Interfaces Set, ao invés de HashSet List, ao invés de ArrayList
  • 109. Associações Bidirecionais Os dois lados da associação devem estar consistentes Necessário mesmo para aplicações que não usam Hibernate
  • 110. Classe Category public class Category { private String name ; private Category parentCategory ; private Set<Category> childCategories = new HashSet<Category>(); //gets e sets //... }
  • 111. Mantendo a Consistência Category aParent = new Category(); Category aChild = new Category(); aChild.setParentCategory(aParent); aParent.getChildCategories().add(aChild);
  • 113. Classe Bid Relaciona-se a somente um Item Mapeamento realizado através da Annotation @ManyToOne Annotation @JoinColumn informa qual a chave estrangeira Atributo name Nome da coluna Atributo nullable Se o relacionamento é opcional ou não
  • 114. Classe Bid @Entity public class Bid { @Id @GeneratedValue @Column (name = &quot;BID_ID&quot; ) private Long id ; private Integer amount ; @ManyToOne @JoinColumn (name = &quot;ITEM_ID&quot; , nullable = false ) private Item item ; }
  • 115. Relacionamento Bidirecional O relacionamento pode ou não ser declarado como bidirecional Para relacionamentos bidirecionais o outro lado da associação é mapeado com a Annotation inversa @OneToMany no caso de Item Classe Bid utiliza a Annotation @ManyToOne
  • 116. Relacionamento Bidirecional @Entity public class Item { @Id @GeneratedValue @Column (name = &quot;ITEM_ID&quot; ) private Long id ; private String name ; @OneToMany (mappedBy = &quot;item&quot; ) private Set<Bid> bids = new HashSet<Bid>(); }
  • 117. Relacionamento Bidirecional @OneToMany(mappedBy = &quot;item&quot;) Detalhes do mapeamento são configurados no outro lado da associação Através da Annotation @ManyToOne Quando as referências de uma associação mudam, as duas propriedades são alteradas bid.setItem(item); item.getBids().add(bid);
  • 118. Relacionamento Bidirecional Na base de dados somente uma atualização precisa ser feita Atualização da chave estrangeira Hibernate não precisa executar dois comandos UPDATE Uma das alterações é sincronizada e a outra é ignorada Não há efeito colateral se as associações estiverem consistentes
  • 119. Relacionamento Bidirecional O lado que contém os detalhes do mapeamento é o lado que é sincronizado Relacionamentos many-to-one ou one-to-many Lado Many é sincronizado Relacionamento one-to-one Lado que possuir a chave estrangeira é sincronizado Relacionamento many-to-many Lado que mapear a tabela de junção é sincronizado Os lados do relacionamento não sincronizados possuem o atributo mappedBy na Annotation
  • 120. Relacionamento Bidirecional Bid bid = new Bid(); bid.setAmount(Integer. valueOf (1000)); Item item = new Item(); item.setName( &quot;computador&quot; ); bid.setItem(item); item.getBids(). add (bid); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); //O item tem que ser salvo primeiro session.save(item); session.save(bid);
  • 122. One-to-One O atributo deve conter a Annotation @OneToOne Se o relacionamento for bidirecional os dois atributos devem conter a Annotation Em uma das propriedades deve ser adicionada a Annotation @JoinColumn Na outra propriedade deve ser adicionado o atributo mappedBy à Annotation @OneToOne
  • 123. Classe User @Entity @Table (name = &quot;USERS&quot; ) public class User { @Id @GeneratedValue (strategy=GenerationType. AUTO ) private Long id ; private String name ; @OneToOne @JoinColumn (name = &quot;SHIPPING_ADDRESS_ID&quot; ) private Address address ; }
  • 124. Classe Address @Entity public class Address { @Id @GeneratedValue private Long id ; @Column (nullable = false ) private String street ; @OneToOne (mappedBy = &quot;address&quot; ) private User user ; }
  • 126. Many-to-Many O atributo deve conter a Annotation @ManyToMany Se o relacionamento for bidirecional os dois atributos devem conter a Annotation Em uma das propriedades deve ser adicionada a Annotation @JoinTable Na outra propriedade deve ser adicionado o atributo mappedBy à Annotation @ManyToMany
  • 127. @JoinTable Contém o nome da tabela de relacionamento O atributo joinColumns mapeia a coluna associada à entidade mapeada O tipo do atributo é @JoinColumn Annotation dentro de annotation O atributo inverseJoinColumns mapeia a coluna associada à outra entidade O tipo do atributo também é @JoinColumn
  • 128. Classe Category @Entity public class Category { @Id @GeneratedValue @Column (name = &quot;CATEGORY_ID&quot; ) private Long id ; private String name ; @ManyToMany @JoinTable (name = &quot;CATEGORY_ITEM&quot; , joinColumns = @JoinColumn (name = &quot;CATEGORY_ID&quot; ), inverseJoinColumns = @JoinColumn (name = &quot;ITEM_ID&quot; )) private Set<Item> items = new HashSet<Item>(); }
  • 129. Classe Item @Entity public class Item { @Id @GeneratedValue @Column (name = &quot;ITEM_ID&quot; ) private Long id ; private String name ; @ManyToMany (mappedBy = &quot;items&quot; ) private Set<Category> categories = new HashSet<Category>(); }
  • 130. Polimorfismo e LazyLoading Utilizando-se polimorfismo, as entidades são referenciadas através de suas super classes Não se deve fazer o cast da referência para alguma das subclasses, mesmo que se saiba o tipo do objeto Para associações carregadas por LazyLoading, é utilizado um objeto proxy O objeto proxy não pode ser atribuído a uma subclasse da classe referenciada
  • 132. Entidade User @Entity @Table (name = &quot;USERS&quot; ) public class User { @Id@GeneratedValue private Long id ; @OneToOne (fetch = FetchType. LAZY ) @JoinColumn (name = &quot;DEFAULT_BILLING_ID&quot; ) private BillingDetails defaultBilling ; }
  • 133. Polimorfismo e LazyLoading User user = (User) session.get(User. class , userId); BillingDetails bd = user.getDefaultBilling(); CreditCard cc = (CreditCard) session.load(CreditCard. class , bd.getId()); System. out .println(cc.getNumber()); User user = (User) session.get(User. class , userId); BillingDetails billingDetails = user.getDefaultBilling(); //imprime false System. out .println(billingDetails instanceof CreditCard); //ClassCastException CreditCard creditCard = (CreditCard) billingDetails;
  • 134. Ciclo de Vida dos Objetos Em seu ciclo de vida, uma entidade pode assumir diversos estados relativos a sua persistência Transiente Persistente Desconectada Removida Entidades devem se comportar de maneira apropriada mesmo que ainda não estejam persistentes
  • 135. Ciclo de Vida dos Objetos O ciclo de vida de uma entidade pode ser afetado através de chamadas às interfaces do Hibernate Operações de alterações e consultas na base de dados Operações para delimitar a existência de uma transação e de um Sesssion Para o correta implementação, a aplicação deve se preocupar com o estado e o ciclo de vida do objeto
  • 136. Ciclo de Vida dos Objetos: Conceitos Unidade de trabalho Conjunto de operações, geralmente atômicas Contexto de persistência Cache de todas alterações feitas em entidades em uma única unidade de trabalho
  • 137. Estado Transiente É o estado que um objeto assume quando é criado através do operador new Não está associado a nenhum registro da base de dados Os dados são perdidos quando o objeto não é mais referenciado e torna-se disponível para o Coletor de Lixo Não são gerenciados pelo Hibernate Não possuem comportamento transacional
  • 138. Estado Persistente É uma entidade com um identificador na base de dados Possui uma chave primária São objetos gerenciados pelo Hibernate Podem ser objetos criados pela aplicação Tornam-se persistentes através de chamadas ao Hibernate Tornam-se persistentes se passarem a ser referenciados por outros objetos persistentes Depende do tipo de Cascade
  • 139. Persistente Podem ser objetos retornados da base de dados Através de uma consulta Através de uma associação entre um objeto persistente Podem ser objetos atualizados na base de dados São sempre associados a um Contexto de Persistência São guardados em um cache Hibernate identifica qualquer alteração realizado no objeto
  • 140. Removido Um objeto pode ser removido de duas maneiras Uma chamada explicita ao Hibernate Através de uma operação com Cascade Um objeto neste estado é removido ao final da Unidade de Trabalho É gerenciado pelo Contexto de Persistência até que a Unidade de Trabalho termine
  • 141. Desconectado Objetos Persistentes passam para o estado Desconectado quando a Unidade de Trabalho é completada e o Contexto de Persistência é encerrado O objeto não é mais sincronizado com a base de dados Os dados do objeto podem se tornar desatualizados Seus dados ainda podem ser alterados pela aplicação Podem voltar ao estado Persistente
  • 142. Contexto de Persistência Mantém um cache de instâncias gerenciadas Entidades no estado Persistente e Removido Conceito abstrato Não representado por um único objeto Cada objeto Session possui um Contexto de Persistência Permite Dirty Checking automático Delimita um escopo para a identidade das Entidades Não possui instâncias duplicadas
  • 143. Dirty Checking Automático É possível através do Contexto de Persistência O dados de uma entidade são sincronizados com a base de dados No final da unidade de trabalho Em outros momentos: antes de uma consulta Somente os objetos alterados são atualizados na base de dados Atualização é retardada o máximo possível e é feita de forma automática Tempo de Lock do banco de dados é reduzido
  • 144. Cache de Primeiro Nível Armazenado no Contexto de Persistência Mantém todas as instâncias de uma Unidade de Trabalho Provê ganho de performance para a aplicação Torna possível Repeatable Read Ao buscar mais de uma vez uma mesma entidade, os dados retornados são os mesmos O escopo é restrito à thread de execução
  • 145. Cache de Primeiro Nível Um único objeto representa um determinado registro na base de dados Evita alterações conflitantes
  • 146. Contexto Persistência: Escopo Algumas funcionalidades da aplicação necessitam de diversas requisições para serem completadas O escopo do Contexto de Persistência pode, ou não, ser o mesmo da funcionalidade Duas estratégias são as mais utilizadas para delimitar o escopo do Contexto de Persistência Um objeto Session por requisição Unidade de Trabalho de longa duração
  • 147. Uma Session por Requisição Quando o servidor recebe alguma requisição que requer acesso a base de dados uma nova Unidade de Trabalho é iniciada A Unidade de Trabalho é encerrada quando a requisição é processada e a resposta está pronta para ser enviada ao usuário As entidades são mantidas em estado Desconectado entre uma requisição e outra
  • 148. Uma Session por Requisição Entidades mantidas entre duas requisições necessitam ser reconectadas para acessar serviços de persistência novamente Qualquer alteração feita em entidades desconectadas deve ser sincronizada manualmente Operações de atualização e/ou merge
  • 150. Unidade de Trabalho de Longa Duração Objeto Session é mantido aberto durante várias requisições O Contexto de Persistência se propaga durante toda a conversação Conexões com a base de dados não são mantidas abertas A cada nova requisição o contexto é reconectado à base de dados As entidades são mantidas no estado Persistente Não requer merge ou atualização manual
  • 151. Unidade de Trabalho de Longa Duração No final da conversação, o Contexto é sincronizado com a base de dados e encerrado A atomicidade das alterações é relativa à funcionalidade como um todo
  • 153. Escopo limitado ao Contexto de Persistência Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); Long id = (Long) session.save( new Message( &quot;Hibernate&quot; )); Message messageB = (Message) session.get(Message. class , id); Message messageC = (Message) session.get(Message. class , id); System. out .println(messageB.equals(messageC)); transaction.commit(); session.close(); Session session2 = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction2 = session2.beginTransaction(); Message messageD = (Message) session2.get(Message. class , id); System. out .println(messageC.equals(messageD));
  • 154. Identidade de objetos Desconectados Sempre que se for trabalhar com objetos desconectados, deve-se sobrescrever o método equals() Para objetos desconectados a garantia de uma única instância por registro é perdida Implementação default não garante o comportamento desejado Mesmo que dois objetos possuam todas as propriedades iguais, o método pode retornar false
  • 155. equals() Deve retornar verdadeiro se duas instâncias corresponderem ao mesmo registro Quais propriedades devem ser comparadas? Somente a chave primária Problema: entidades transientes não possuem valores para a chave primária Todas as propriedades Problema: entidades referentes ao mesmo registro não são consideradas iguais se alguma propriedade mudar Melhor abordagem: comparar a chave de negócio
  • 156. Chave de negócio Uma propriedade, ou um conjunto delas, que é único para cada registro Chave candidata Não precisa ser imutável, basta que mude com pouca freqüência
  • 157. Implementação public boolean equals(Object other) { if (!(other instanceof User)){ return false ; } User that = (User) other; return this . name .equals(that.getName()); } public int hashCode() { return this . name .hashCode(); }
  • 158. Interagindo com o Hibernate O Hibernate provê diversos serviços Operações CRUD Criar Recuperar Atualizar Deletar Realização de consultas Controle de transação Gerenciamento do Contexto de Persistência
  • 159. Interagindo com o Hibernate Os serviços são disponibilizados através de diversas Interfaces Session Transaction Query Criteria
  • 160. Armazenando e Recuperando Objetos Para armazenar ou recuperar objetos, é necessário iniciar uma Unidade de Trabalho Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Um Contexto de Persistência é criado Irá gerenciar todas as entidades do Session Uma transação também deve ser iniciada mesmo para operações de leitura
  • 161. Armazenando um Objeto // Quando é instanciado, o item está no estado Transiente Item item = new Item(); item.setName( &quot;Item 1&quot; ); // um novo Session é aberto Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); // O item passa para o estado Persistente e fica associado //ao Session e ao Contexto de Persistência session.save(item); //As mundanças são sincronizadas com a base de dados transaction.commit(); //O Session é fechado e o Contexto de Persistência encerrado. //O item passa para o estado Desconectado session.close();
  • 163. Recuperando uma Entidade Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction tx = session.beginTransaction(); //Item é recuperado no estado Transiente Item item = (Item) session.load(Item. class , new Long(1234)); // Item item = (Item) session.get(Item.class, new Long(1234)); tx.commit(); //Item passa para o estado Desconectado session.close();
  • 165. Recuperando uma Entidade Método get() Se o objeto procurado não for encontrado, retorna null Método load() Se o objeto procurado não for encontrado, lança a exceção ObjectNotFoundException A existência do objeto só é verificada quando alguma propriedade é acessada
  • 166. Modificando um Objeto Persistente Todo objeto retornado pelos métodos load() ou get() ou através de uma consulta, assume o estado Persistente Os objetos podem ser modificados e as alterações são sincronizadas com a base de dados
  • 167. Modificando um Objeto Persistente Long id = armazenarItem (); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction tx = session.beginTransaction(); Item item = (Item) session.get(Item. class , id); item.setName( &quot;Playstation&quot; ); //Dados sincronizados com a base de dados. Dirty Cheking automático tx.commit(); session.close();
  • 168. Modificando um Objeto Persistente
  • 169. De Persistente para Transiente Long id = armazenarItem (); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction tx = session.beginTransaction(); //Item no estado Persistente Item item = (Item) session.load(Item. class , id); //Item no estado Removido session.delete(item); tx.commit(); //Item no estado Transiente session.close();
  • 170. De Persistente para Transiente
  • 171. Trabalhando com Objetos Desconectados Modificações realizadas em objetos Desconectados não são sincronizadas na base de dados A atualização da base de dados pode ser feita de duas formas Reconectando o objeto – reattach Realizando o merge do objeto
  • 172. Reconectando um Objeto Um objeto é reconectado através do método update() da interface Session O objeto passa a ser gerenciado pelo Session e assume o estado Persistente Deve-se ter certeza de que o Session ainda não possui um objeto gerenciado com o mesmo Id Somente uma instância do Contexto de Persistência pode estar associada a um determinado registro
  • 173. Reconectando um Objeto Item item = recuperarItem ( armazenarItem ()); item.setName( &quot;Novo nome&quot; ); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); session.update(item); item.setPrice(Integer. valueOf (114)); transaction.commit(); session.close();
  • 175. NonUniqueObjectException Long id = armazenarItem (); Item item = recuperarItem (id); item.setName( &quot;Novo nome&quot; ); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); Item item2 = (Item) session.get(Item. class , id); session.update(item); item.setPrice(Integer. valueOf (114)); transaction.commit(); session.close();
  • 176. Realizando o merge() de um Objeto O merge de um objeto é feito através do método merge() da Interface Session A a base de dados é atualizada com os valores contidos no objeto Os dados do objeto também atualizam o objeto persistente que possuir o mesmo identificador Se não existir um objeto persistente associado ao Session, ele é carregado
  • 177. Método merge() O objeto desconectado não passa a ser associado ao Session Continua desconectado O objeto persistente é retornado
  • 178. Método merge() Long id = armazenarItem (); Item item = recuperarItem (id); item.setName( &quot;Novo nome!!!&quot; ); Session session = HibernateUtil. getSessionFactory ().openSession(); Transaction transaction = session.beginTransaction(); Item item2 = (Item) session.get(Item. class , id); Item item3 = (Item) session.merge(item); transaction.commit(); session.close();
  • 180. Persistência Transitiva Em aplicações não triviais, diversas Entidades podem estar associadas A aplicação deve poder manipular as associações Uma rede de objetos pode consistir de objetos em diferentes estados Persistentes Desconectados Transientes
  • 181. Persistência Transitiva A Persistência Transitiva permite persistir objetos Desconectados e Transientes automaticamente Um objeto Transiente associado a um Persistente, torna-se persistente automaticamente Não há necessidade de chamar o método save() Diversas operações poder ser cascateadas Salvar Deletar Reconectar (update) Merge
  • 182. Cascade Por default, em nenhuma operação é feito o cascade O Hibernate permite a configuração do tipo de comportamento desejado para cada associação Todos os tipos de associações podem ser configuradas one-to-one one-many many-to-many many-to-one
  • 183. org.hibernate.annotations.CascadeType SAVE_UPDATE Objetos transientes são salvos Objetos desconectados são sincronizados DELETE Objetos relacionados são deletados após a chamada do método delete() ALL Habilita todos os tipos de cascade
  • 184. org.hibernate.annotations.CascadeType DELETE_ORPHAN Deleta um objeto se ele for excluído da coleção Aplicável somente para relacionamentos One-to-Many Cascade é aplicável somente para relacionamentos entre entidades
  • 186. Consultas Umas das partes mais interessantes do acesso a dados Consultas complexas podem levar um bom tempo para serem escritas e podem ter considerável impacto na performance da aplicação Consultas são escritas utilizando conceitos de orientação a objetos Objetos no lugar de tabelas Propriedades no lugar de colunas Experiência em SQL não é desprezada
  • 187. Consultas Podem ser feitas de três maneiras Hibernate Query Language (HQL) Criteria API e Query by Example Utilizando SQL
  • 188. Consultas: Exemplos // Através de HQL session.createQuery( &quot;from Category c where c.name like 'Laptop%'&quot; ); // Utilizando-se Criteria session.createCriteria(Category. class ).add( Restrictions. like ( &quot;name&quot; , &quot;Laptop%&quot; )); // Através de SQL session.createSQLQuery( &quot;select {c.*} from CATEGORY {c} where NAME like 'Laptop%'&quot; ) .addEntity( &quot;c&quot; , Category. class );
  • 189. Consultas Envolve alguns passos Criar a consulta com as restrições necessárias Adicionar parâmetros à consulta Executar a consulta e recuperar o resultado A forma de execução da consulta e obtenção dos dados pode ser configurada
  • 190. Criando a Consulta Objetos Query e Criteria são obtidos através do Session org.hibernate.Query org.hibernate.Criteria Query query = session.createQuery( &quot;from User&quot; ); Criteria criteria = session.createCriteria(User. class );
  • 191. Adicionando Parâmetros à Consulta Parâmetros não devem ser adicionados na própria String da consulta &quot;from Item i where i.description like '&quot; + search + &quot;'&quot; Evita-se ataque do tipo SQL Injection foo' and callSomeStoredProcedure() and 'bar' = 'bar Parâmetros podem ser adicionados através de sua posição ou de seu nome
  • 192. Adicionando Parâmetros pelo Nome Nome do parâmetro é precedido de “:” O valores são adicionados através de métodos sets String queryString = &quot;from Item item where item.description like :search&quot; ; Query q = session.createQuery(queryString).setString( &quot;search&quot; , searchString); String queryString = &quot;from Item item&quot; + &quot; where item.description like :search&quot; + &quot; and item.date > :minDate&quot; ; Query q = session.createQuery(queryString).setString( &quot;search&quot; , searchString).setDate( &quot;minDate&quot; , mDate);
  • 193. Adicionando Parâmetros pela Posição A consulta contém “?” para indicar a existência de alguma parâmetro Os valores também são adicionado através de métodos sets String queryString = &quot;from Item item&quot; + &quot; where item.description like ?&quot; + &quot; and item.date > ?&quot; ; Query q = session.createQuery(queryString).setString(0, searchString).setDate(1, minDate);
  • 194. Executando a Consulta Se mais de um objeto pode ser retornado, chama-se o método list() List list = query.list(); Se somente um objeto pode ser retornado, chama-se o método uniqueResult() User user = (User) query.uniqueResult(); O método retorna null se nenhum objeto for encontrado Se a consulta retornar mais de um objetos, a exceção NonUniqueResultException é lançada
  • 195. Executando a Consulta Query query = session.createQuery( &quot;from User&quot; ); List<User> list = query.list(); for (User user : list) { System. out .println(user.getName()); } Query query2 = session.createQuery( &quot;from User user where user.name =:name&quot; ).setString( &quot;name&quot; , &quot;SUNSP&quot; ); User user = (User) query2.uniqueResult(); System. out .println(user.getName());
  • 196. Consultas Básicas A consulta mais simples tem somente a cláusula FROM “ from Item” Para se referenciar as propriedades de uma entidade, um ALIAS deve ser criado “ from Item as item” “ from Item item” Palavra chave “as” é opcional A consulta não é case-sensitive “ FROM Item AS item” também pode ser utilizada
  • 197. Consultas Polimórficas Consultas podem ser escritas utilizando polimorfismo “ from BillingDetails” Retorna todas as entidades que herdam de BillingDetails CreditCard BankAccount A superclasse não precisa estar mapeada “ from java.lang.Object” “ from java.io.Serializable”
  • 198. Restrições Geralmente não se quer trazer todo o conteúdo da tabela Restrições devem ser adicionadas para restringir os objetos retornados HQL também utiliza-se a cláusula WHERE As restrições são feitas sobre propriedades da entidade
  • 199. Restrições Literais e condições podem ser incluídos Utiliza-se aspas simples para literais do tipo String “ from User u where u.email = 'foo@hibernate.org '” “ from Item i where i.isActive = true” Comparações podem ser realizadas “ from Bid bid where bid.amount between 1 and 10” “ from Bid bid where bid.amount > 100” “ from User u where u.email in ('foo@bar', 'bar@foo')”
  • 200. Operador LIKE pode ser utilizado “ %” representa qualquer seqüência de caracteres _ (Under_Score) representa qualquer caractere “ from User u where u.firstname like 'G%'” Negação pode ser utilizada “ from User u where u.firstname not like '%Foo B%'” Operadores lógicos e parênteses “ from User user where user.firstname like 'G%' and user.lastname like 'K%'” Comparações
  • 201. Comparações Operadores lógicos e parênteses “ from User u where (u.firstname like 'G%' and u.lastname like 'K%' ) or u.email in ('foo@hibernate.org', 'bar@hibernate.org' )” Coleções &quot;from Item i where i.bids is not empty&quot;
  • 202. Comparações Funções podem ser chamadas a partir do HQL HQL permite a chamada de funções SQL na cláusula WHERE Funções podem ser definidas pelo usuário Depende do suporte do banco de dados Funções UPPER() e LOWER() &quot;from User u where lower(u.email) = 'foo@hibernate.org '&quot; Função SIZE() from Item i where size(i.bids) > 3 E muitas outras...
  • 203. Comparações Outras funções CONCAT(s1, s2) SUBSTRING(s, offset, length) Offset começa a partir de 1 TRIM( [[BOTH|LEADING|TRAILING] s) &quot;from Item i where TRIM(BOTH i.name) = 'Computador'&quot; LENGTH(s) LOCATE(search, s, offset) Procura a localização de uma substring dentro de uma string
  • 204. Comparações Outras funções CURRENT_DATE(), CURRENT_TIME(), CURRENT_TIMESTAMP() Valores retornados são referentes ao SGBD SECOND(d), MINUTE(d), HOUR(d), DAY(d), MONTH(d), YEAR(d) Extraem os valores de um argumento temporal
  • 205. Ordenando o Resultado A Cláusula ORDER BY é utilizada para ordenar o resultado &quot;from User u order by u.name&quot; Ordem ascendente ou descendente Utiliza-se asc ou desc from User u order by u.username desc Ordenando por mais de uma propriedade “ from User u order by u.lastname asc, u.firstname asc”
  • 206. Junções A habilidade de realizar junções é uma das principais forças do modelo relacional Permite selecionar diferentes objetos associados e coleções em uma única consulta
  • 207. Inner Join Contém somente os registros que estão relacionados com o outro lado da junção Contém somente os Itens que possuem Bids
  • 208. (left) Outer Join Retorna todos os Itens Dados de Bid são preenchidos com NULL se não houver uma correspondência
  • 209. Junção com HQL Coluna de junção não precisar ser informada na consulta Informação é extraída do mapeamento É necessário ser informado somente o nome da associação Nome do atributo que referencia a classe ou coleção de classes Joins podem ser executados de duas maneiras Join implícitos na Associação Join especificado na cláusula FROM
  • 210. Join Implícito na Associação O Join é realizado através da associação entre duas entidades Exemplo: “ from Bid bid where bid.item.description like '%Foo%'” Bid é associado a Item através do atributo “item” Hibernate sabe que a associação está mapeada a partir da chave estrangeira ITEM_ID da tabela BID Joins implícitos são sempre realizados através de associações many-to-one ou one-to-one
  • 211. Join Implícito na Associação Múltiplos joins são possíveis from Bid bid where bid.item.category.name like 'Laptop%'
  • 212. Join especificado na Cláusula FROM Joins podem ser especificados explicitamente na cláusula FROM Exemplo &quot;select i from Item i join i.bids b where b.amount > 10&quot; Aliases devem ser especificados na cláusula FROM e utilizados na cláusula WHERE Cláusula SELECT é utilizada para que somente Itens sejam retornados
  • 213. Join especificado na Cláusula FROM Na consulta, um Item pode ser retornado mais de uma vez Uma para cada Bid associado Somente uma instância é utilizada A consulta possui o mesmo formato para associações many-to-one e one-to-one
  • 214. Outer Joins Para a utilização de Outer Joins utiliza-se a cláusula LEFT JOIN LEFT OUTER JOIN e RIGHT OUTER JOIN também podem ser utilizados A cláusula WITH é utilizada para adicionar restrições &quot;select i from Item i left join i.bids b with b.amount >= 9&quot; Itens que não possuem Bids também são retornados
  • 215. Comparando Identificadores Na Orientação a Objetos não são os identificadores, mas as referências ao objetos que são comparadas Comparações podem ser feitas através dos atributos das entidades &quot;select i from Item i join i.bids b where i.seller = b.bidder&quot; i.seller e b.bidder representam referências para a entidade User Retorna os Itens em que o próprio vendedor deu um lance
  • 216. Comparando Identificadores Entidades também podem ser adicionadas como parâmetros de uma consulta Query query = session.createQuery( &quot;from Item i where i.seller = :seller&quot; ); query.setEntity( &quot;seller&quot; , user);
  • 217. FIM... Referências Livro Java Persistence with Hibernate Edição revisada do livro Hibernate in Action Autores Christian Bauer Gavin King http://www.hibernate.org/ Documentação e Javadoc Fórum de discuções e dúvidas JSR 220: Enterprise JavaBeans Version 3.0 Para as Annotations do pacote javax.persistence