Hibernate.orgCommunity Documentation

HIBERNATE - Persistência Relacional para Java Idiomático

Documentação de Referência Hibernate

3.6.10.Final

Legal Notice

February 8, 2012


Prefácio
1. Tutorial
1.1. Parte 1 – A primeira aplicação Hibernate
1.1.1. Configuração
1.1.2. A primeira Classe
1.1.3. O mapeamento do arquivo
1.1.4. Configuração do Hibernate
1.1.5. Construindo com o Maven
1.1.6. Inicialização e Auxiliares
1.1.7. Carregando e salvando objetos
1.2. Parte 2 - Mapeando associações
1.2.1. Mapeando a classe Person
1.2.2. Uma associação unidirecional baseada em Configuração
1.2.3. Trabalhando a associação
1.2.4. Coleção de valores
1.2.5. Associações bidirecionais
1.2.6. Trabalhando com links bidirecionais
1.3. EventManager um aplicativo da web
1.3.1. Criando um servlet básico
1.3.2. Processando e renderizando
1.3.3. Implementando e testando
1.4. Sumário
2. Arquitetura
2.1. Visão Geral
2.1.1. Minimal architecture
2.1.2. Comprehensive architecture
2.1.3. Basic APIs
2.2. Integração JMX
2.3. Sessões Contextuais
3. Configuration
3.1. Configuração programática
3.2. Obtendo uma SessionFactory
3.3. Conexões JDBC
3.4. Propriedades opcionais de configuração
3.4.1. Dialetos SQL
3.4.2. Busca por união externa (Outer Join Fetching)
3.4.3. Fluxos Binários (Binary Streams)
3.4.4. Cachê de segundo nível e consulta
3.4.5. Substituição na Linguagem de Consulta
3.4.6. Estatísticas do Hibernate
3.5. Logging
3.6. Implementando um NamingStrategy
3.7. Implementing a PersisterClassProvider
3.8. Arquivo de configuração XML
3.9. Java EE Application Server integration
3.9.1. Configuração de estratégia de transação
3.9.2. SessionFactory vinculada à JNDI
3.9.3. Gerenciamento de contexto de Sessão atual com JTA
3.9.4. implementação JMX
4. Classes Persistentes
4.1. Um exemplo simples de POJO
4.1.1. Implemente um construtor de não argumento
4.1.2. Provide an identifier property
4.1.3. Prefer non-final classes (semi-optional)
4.1.4. Declare acessores e mutadores para campos persistentes (opcional)
4.2. Implementando herança
4.3. Implementando equals() e hashCode()
4.4. Modelos dinâmicos
4.5. Tuplizadores
4.6. EntityNameResolvers
5. Mapeamento O/R Básico
5.1. Declaração de mapeamento
5.1.1. Entity
5.1.2. Identifiers
5.1.3. Optimistic locking properties (optional)
5.1.4. Propriedade
5.1.5. Embedded objects (aka components)
5.1.6. Inheritance strategy
5.1.7. Mapping one to one and one to many associations
5.1.8. Id Natural
5.1.9. Any
5.1.10. Propriedades
5.1.11. Some hbm.xml specificities
5.2. Tipos do Hibernate
5.2.1. Entidades e valores
5.2.2. Valores de tipos básicos
5.2.3. Tipos de valores personalizados
5.3. Mapeando uma classe mais de uma vez
5.4. Identificadores quotados do SQL
5.5. Propriedades geradas
5.6. Column transformers: read and write expressions
5.7. Objetos de Banco de Dados Auxiliares
6. Types
6.1. Value types
6.1.1. Basic value types
6.1.2. Composite types
6.1.3. Collection types
6.2. Entity types
6.3. Significance of type categories
6.4. Custom types
6.4.1. Custom types using org.hibernate.type.Type
6.4.2. Custom types using org.hibernate.usertype.UserType
6.4.3. Custom types using org.hibernate.usertype.CompositeUserType
6.5. Type registry
7. Mapeamento de coleção
7.1. Coleções persistentes
7.2. How to map collections
7.2.1. Chaves Externas de Coleção
7.2.2. Coleções indexadas
7.2.3. Collections of basic types and embeddable objects
7.3. Mapeamentos de coleção avançados.
7.3.1. Coleções escolhidas
7.3.2. Associações Bidirecionais
7.3.3. Associações bidirecionais com coleções indexadas
7.3.4. Associações Ternárias
7.3.5. Using an <idbag>
7.4. Exemplos de coleções
8. Mapeamento de associações
8.1. Introdução
8.2. Associações Unidirecionais
8.2.1. Muitos-para-um
8.2.2. Um-para-um
8.2.3. Um-para-muitos
8.3. Associações Unidirecionais com tabelas associativas
8.3.1. Um-para-muitos
8.3.2. Muitos-para-um
8.3.3. Um-para-um
8.3.4. Muitos-para-muitos
8.4. Associações Bidirecionais
8.4.1. Um-para-muitos/muitos-para-um
8.4.2. Um-para-um
8.5. Associações Bidirecionais com tabelas associativas
8.5.1. Um-para-muitos/muitos-para-um
8.5.2. Um para um
8.5.3. Muitos-para-muitos
8.6. Mapeamento de associações mais complexas
9. Mapeamento de Componentes
9.1. Objetos dependentes
9.2. Coleções de objetos dependentes
9.3. Componentes como índices de Map
9.4. Componentes como identificadores compostos
9.5. Componentes Dinâmicos
10. Mapeamento de Herança
10.1. As três estratégias
10.1.1. Tabela por hierarquia de classes
10.1.2. Tabela por subclasse
10.1.3. Tabela por subclasse: usando um discriminador
10.1.4. Mesclar tabela por hierarquia de classes com tabela por subclasse
10.1.5. Tabela por classe concreta
10.1.6. Tabela por classe concreta usando polimorfismo implícito
10.1.7. Mesclando polimorfismo implícito com outros mapeamentos de herança
10.2. Limitações
11. Trabalhando com objetos
11.1. Estado dos objetos no Hibernate
11.2. Tornando os objetos persistentes
11.3. Carregando o objeto
11.4. Consultando
11.4.1. Executando consultas
11.4.2. Filtrando coleções
11.4.3. Consulta por critério
11.4.4. Consultas em SQL nativa
11.5. Modificando objetos persistentes
11.6. Modificando objetos desacoplados
11.7. Detecção automática de estado
11.8. Apagando objetos persistentes
11.9. Replicando objeto entre dois armazenamentos de dados diferentes.
11.10. Limpando a Sessão
11.11. Persistência Transitiva
11.12. Usando metadados
12. Read-only entities
12.1. Making persistent entities read-only
12.1.1. Entities of immutable classes
12.1.2. Loading persistent entities as read-only
12.1.3. Loading read-only entities from an HQL query/criteria
12.1.4. Making a persistent entity read-only
12.2. Read-only affect on property type
12.2.1. Simple properties
12.2.2. Unidirectional associations
12.2.3. Bidirectional associations
13. Transações e Concorrência
13.1. Sessão e escopos de transações
13.1.1. Unidade de trabalho
13.1.2. Longas conversações
13.1.3. Considerando a identidade do objeto
13.1.4. Edições comuns
13.2. Demarcação de transações de bancos de dados
13.2.1. Ambiente não gerenciado
13.2.2. Usando JTA
13.2.3. Tratamento de Exceção
13.2.4. Tempo de espera de Transação
13.3. Controle de concorrência otimista
13.3.1. Checagem de versão da aplicação
13.3.2. Sessão estendida e versionamento automático
13.3.3. Objetos destacados e versionamento automático
13.3.4. Versionamento automático customizado
13.4. Bloqueio Pessimista
13.5. Modos para liberar a conexão
14. Interceptadores e Eventos
14.1. Interceptadores
14.2. Sistema de Eventos
14.3. Segurança declarativa do Hibernate
15. Batch processing
15.1. Inserção em lotes
15.2. Atualização em lotes
15.3. A interface de Sessão sem Estado
15.4. Operações no estilo DML
16. HQL: A Linguagem de Consultas do Hibernate
16.1. Diferenciação de maiúscula e minúscula
16.2. A cláusula from
16.3. Associações e uniões
16.4. Formas de sintáxe de uniões
16.5. Referência à propriedade do identificador
16.6. A cláusula select
16.7. Funções de agregação
16.8. Pesquisas Polimórficas
16.9. A cláusula where
16.10. Expressões
16.11. A cláusula ordenar por
16.12. A cláusula agrupar por
16.13. Subconsultas
16.14. Exemplos de HQL
16.15. Atualização e correção em lote
16.16. Dicas & Truques
16.17. Componentes
16.18. Sintáxe do construtor de valores de linha
17. Consultas por critérios
17.1. Criando uma instância Criteria
17.2. Limitando o conjunto de resultados
17.3. Ordenando resultados
17.4. Associações
17.5. Busca de associação dinâmica
17.6. Exemplos de consultas
17.7. Projeções, agregações e agrupamento.
17.8. Consultas e subconsultas desanexadas.
17.9. Consultas por um identificador natural
18. SQL Nativo
18.1. Usando um SQLQuery
18.1.1. Consultas Escalares
18.1.2. Consultas de Entidade
18.1.3. Manuseio de associações e coleções
18.1.4. Retorno de entidades múltiplas
18.1.5. Retorno de entidades não gerenciadas
18.1.6. Manuseio de herança
18.1.7. Parâmetros
18.2. Consultas SQL Nomeadas
18.2.1. Utilizando a propriedade retorno para especificar explicitamente os nomes de colunas/alias
18.2.2. Usando procedimentos de armazenamento para consultas
18.3. SQL padronizado para criar, atualizar e deletar
18.4. SQL padronizado para carga
19. Filtrando dados
19.1. Filtros do Hibernate
20. Mapeamento XML
20.1. Trabalhando com dados em XML
20.1.1. Especificando o mapeamento de uma classe e de um arquivo XML simultaneamente
20.1.2. Especificando somente um mapeamento XML
20.2. Mapeando metadados com XML
20.3. Manipulando dados em XML
21. Aumentando o desempenho
21.1. Estratégias de Busca
21.1.1. Trabalhando com associações preguiçosas (lazy)
21.1.2. Personalizando as estratégias de busca
21.1.3. Proxies de associação final único
21.1.4. Inicializando coleções e proxies
21.1.5. Usando busca em lote
21.1.6. Usando busca de subseleção
21.1.7. Perfis de Busca
21.1.8. Usando busca preguiçosa de propriedade
21.2. O Cachê de Segundo Nível
21.2.1. Mapeamento de Cache
21.2.2. Estratégia: somente leitura
21.2.3. Estratégia: leitura/escrita
21.2.4. Estratégia: leitura/escrita não estrita
21.2.5. Estratégia: transacional
21.2.6. Compatibilidade de Estratégia de Concorrência de Cache Provedor
21.3. Gerenciando os caches
21.4. O Cache de Consulta
21.4.1. Ativação do cache de consulta
21.4.2. Regiões de cache de consulta
21.5. Entendendo o desempenho da Coleção
21.5.1. Taxonomia
21.5.2. Listas, mapas, bags de id e conjuntos são coleções mais eficientes para atualizar
21.5.3. As Bags e listas são as coleções de inversão mais eficientes.
21.5.4. Deletar uma vez
21.6. Monitorando desempenho
21.6.1. Monitorando uma SessionFactory
21.6.2. Métricas
22. Guia de Toolset
22.1. Geração de esquema automático
22.1.1. Padronizando o esquema
22.1.2. Executando a ferramenta
22.1.3. Propriedades
22.1.4. Usando o Ant
22.1.5. Atualizações de esquema incremental
22.1.6. Utilizando Ant para atualizações de esquema incremental
22.1.7. Validação de esquema
22.1.8. Utilizando Ant para validação de esquema
23. Additional modules
23.1. Bean Validation
23.1.1. Adding Bean Validation
23.1.2. Configuration
23.1.3. Catching violations
23.1.4. Database schema
23.2. Hibernate Search
23.2.1. Description
23.2.2. Integration with Hibernate Annotations
24. Exemplo: Pai/Filho
24.1. Uma nota sobre as coleções
24.2. Bidirecional um-para-muitos
24.3. Ciclo de vida em Cascata
24.4. Cascatas e unsaved-value
24.5. Conclusão
25. Exemplo: Aplicativo Weblog
25.1. Classes Persistentes
25.2. Mapeamentos Hibernate
25.3. Código Hibernate
26. Exemplo: Vários Mapeamentos
26.1. Empregador/Empregado
26.2. Autor/Trabalho
26.3. Cliente/Ordem/Produto
26.4. Exemplos variados de mapeamento
26.4.1. Associação um-para-um "Typed"
26.4.2. Exemplo de chave composta
26.4.3. Muitos-para-muitos com função de chave composta compartilhada
26.4.4. Conteúdo baseado em discriminação
26.4.5. Associações em chaves alternativas
27. Melhores práticas
28. Considerações da Portabilidade do Banco de Dados
28.1. Fundamentos da Portabilidade
28.2. Dialeto
28.3. Resolução do Dialeto
28.4. Geração do identificador
28.5. Funções do banco de dados
28.6. Tipos de mapeamentos
Referências

Working with both Object-Oriented software and Relational Databases can be cumbersome and time consuming. Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases. Hibernate is an Object/Relational Mapping solution for Java environments. The term Object/Relational Mapping refers to the technique of mapping data from an object model representation to a relational data model representation (and visa versa). See http://en.wikipedia.org/wiki/Object-relational_mapping for a good high-level discussion.

Nota

While having a strong background in SQL is not required to use Hibernate, having a basic understanding of the concepts can greatly help you understand Hibernate more fully and quickly. Probably the single best background is an understanding of data modeling principles. You might want to consider these resources as a good starting point:

Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities. It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC. Hibernate’s design goal is to relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for manual, hand-crafted data processing using SQL and JDBC. However, unlike many other persistence solutions, Hibernate does not hide the power of SQL from you and guarantees that your investment in relational technology and knowledge is as valid as always.

Hibernate may not be the best solution for data-centric applications that only use stored-procedures to implement the business logic in the database, it is most useful with object-oriented domain models and business logic in the Java-based middle-tier. However, Hibernate can certainly help you to remove or encapsulate vendor-specific SQL code and will help with the common task of result set translation from a tabular representation to a graph of objects.

Por favor siga os seguintes passos, caso você seja inexperiente com o Hibernate, Mapeamento Objeto/Relacional ou mesmo Java:

  1. Read Capítulo 1, Tutorial for a tutorial with step-by-step instructions. The source code for the tutorial is included in the distribution in the doc/reference/tutorial/ directory.

  2. Read Capítulo 2, Arquitetura to understand the environments where Hibernate can be used.

  3. Verifique no diretório eg/ em sua distribuição de Hibernate, do qual possui uma simples aplicação autônoma. Copie seu driver JDBC para o diretório lib/ e edite eg/hibernate.properties, especificando valores corretos para o seu banco de dados. No diretório de distribuição sob o comando aviso, digite ant eg (usando Ant), ou sob Windows, digite build eg.

  4. Use this reference documentation as your primary source of information. Consider reading [JPwH] if you need more help with application design, or if you prefer a step-by-step tutorial. Also visit http://caveatemptor.hibernate.org and download the example application from [JPwH].

  5. As respostas das perguntas mais freqüentes podem ser encontradas no website Hibernate.

  6. A terceira parte de demonstração, exemplos e tutoriais estão vinculadas no website Hibernate.

  7. A Área de Comunidade no website Hibernate é um bom recurso para parceiros de design e várias soluções integradas. ( Tomcat, JBoss AS, Struts, EJB, etc. )

There are a number of ways to become involved in the Hibernate community, including

  • Trying stuff out and reporting bugs. See http://hibernate.org/issuetracker.html details.

  • Trying your hand at fixing some bugs or implementing enhancements. Again, see http://hibernate.org/issuetracker.html details.

  • http://hibernate.org/community.html list a few ways to engage in the community.

    • There are forums for users to ask questions and receive help from the community.

    • There are also IRC channels for both user and developer discussions.

  • Helping improve or translate this documentation. Contact us on the developer mailing list if you have interest.

  • Evangelizing Hibernate within your organization.

Intencionado para novos usuários, este capítulo fornece uma introdução detalhada do Hibernate, começando com um aplicativo simples usando um banco de dados em memória. O tutorial é baseado num tutorial anterior desenvolvido por Michael Gloegl. Todo o código está contido no diretório tutorials/web da fonte do projeto.

Importante

Este tutorial espera que o usuário tenha conhecimento de ambos Java e SQL. Caso você tenha um conhecimento limitado do JAVA ou SQL, é recomendado que você inicie com uma boa introdução àquela tecnologia, antes de tentar entender o Hibernate.

Nota

Esta distribuição contém outro aplicativo de amostra sob o diretório de fonte do projeto tutorial/eg.

Vamos supor que precisemos de uma aplicação com um banco de dados pequeno que possa armazenar e atender os eventos que queremos, além das informações sobre os hosts destes eventos.

Nota

Mesmo que usando qualquer banco de dados do qual você se sinta confortável, nós usaremos HSQLDB (o em memória, banco de dados Java) para evitar a descrição de instalação/configuração de quaisquer servidores do banco de dados.

O primeiro passo em que precisamos tomar é configurar o ambiente de desenvolvimento. Nós usaremos o "layout padrão" suportado por muitas ferramentas de construção, tais como Maven. Maven, em particular, possui um excelente recurso de descrição disto layout. Assim como este tutorial deve ser um aplicativo da web, nós criaremos e faremos uso dos diretórios src/main/java, src/main/resources e src/main/webapp.

Nós usaremos Maven neste tutorial, tirando vantagem destas capacidades de dependência transitiva assim como a habilidade de muitos IDEs de configurar automaticamente um projeto baseado no descritor maven.


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>org.hibernate.tutorials</groupId>
    <artifactId>hibernate-tutorial</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <name>First Hibernate Tutorial</name>

    <build>
         <!-- we dont want the version to be part of the generated war file name -->
         <finalName>${artifactId}</finalName>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

        <!-- Because this is a web app, we also have a dependency on the servlet api. -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
        </dependency>

        <!-- Hibernate uses slf4j for logging, for our purposes here use the simple backend -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
        </dependency>

        <!-- Hibernate gives you a choice of bytecode providers between cglib and javassist -->
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
        </dependency>
    </dependencies>

</project>

Dica

It is not a requirement to use Maven. If you wish to use something else to build this tutorial (such as Ant), the layout will remain the same. The only change is that you will need to manually account for all the needed dependencies. If you use something like Ivy providing transitive dependency management you would still use the dependencies mentioned below. Otherwise, you'd need to grab all dependencies, both explicit and transitive, and add them to the project's classpath. If working from the Hibernate distribution bundle, this would mean hibernate3.jar, all artifacts in the lib/required directory and all files from either the lib/bytecode/cglib or lib/bytecode/javassist directory; additionally you will need both the servlet-api jar and one of the slf4j logging backends.

Salve este arquivo como pom.xml no diretório raiz do projeto.

Agora, iremos criar uma classe que representa o evento que queremos armazenar na base de dados. Isto é uma classe JavaBean simples com algumas propriedades:

package org.hibernate.tutorial.domain;


import java.util.Date;
public class Event {
    private Long id;
    private String title;
    private Date date;
    public Event() {}
    public Long getId() {
        return id;
    }
    private void setId(Long id) {
        this.id = id;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}

Você pode ver que esta classe usa o padrão JavaBean para o nome convencional dos métodos de propriedade getter e setter, como também a visibilidade privada dos campos. Este é um padrão de projeto recomendado, mas não requerido. O Hibernate pode também acessar campos diretamente, o benefício para os métodos de acesso é a robustez para o refactoring.

A propriedade id mantém um único valor de identificação para um evento particular. Todas as classes persistentes da entidade (bem como aquelas classes dependentes de menos importância) precisam de uma propriedade de identificação, caso nós queiramos usar o conjunto completo de características do Hibernate. De fato, a maioria das aplicações, especialmente. aplicações web, precisam distinguir os objetos pelo identificador. Portanto, você deverá considerar esta, uma característica ao invés de uma limitação. Porém, nós normalmente não manipulamos a identidade de um objeto, conseqüentemente o método setter deverá ser privado. O Hibernate somente nomeará os identificadores quando um objeto for salvo. O Hibernate pode acessar métodos públicos, privados, e protegidos, como também campos públicos, privados, protegidos diretamente. A escolha é sua e você pode adaptar seu projeto de aplicação.

O construtor sem argumentos é um requerimento para todas as classes persistentes; O Hibernate precisa criar para você os objetos usando Java Reflection. O construtor pode ser privado, porém, a visibilidade do pacote é requerida para a procuração da geração em tempo de execução e recuperação eficiente dos dados sem a instrumentação de bytecode.

Salve este arquivo no diretório src/main/java/org/hibernate/tutorial/domain.

O Hibernate precisa saber como carregar e armazenar objetos da classe de persistência. É aqui que o mapeamento do arquivo do Hibernate entrará em jogo. O arquivo mapeado informa ao Hibernate, qual tabela no banco de dados ele deverá acessar, e quais as colunas na tabela ele deverá usar.

A estrutura básica de um arquivo de mapeamento é parecida com:


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="org.hibernate.tutorial.domain">
[...]
</hibernate-mapping
>

Note que o Hibernate DTD é muito sofisticado. Você pode usar isso para auto-conclusão no mapeamento XML dos elementos e funções no seu editor ou IDE. Você também pode abrir o arquivo DTD no seu editor. Esta é a maneira mais fácil de ter uma visão geral de todos os elementos e funções e dos padrões, como também alguns comentários. Note que o Hibernate não irá carregar o arquivo DTD da web, e sim da classpath da aplicação. O arquivo DTD está incluído no hibernate-core.jar (como também no hibernate3.jar, caso usando a vinculação de distribuição.

Entre as duas tags hibernate-mapping, inclua um elemento class. Todas as classes persistentes da entidade (novamente, poderá haver mais tarde, dependências sobre as classes que não são classes-primárias de entidades) necessitam do tal mapeamento, para uma tabela na base de dados SQL:


<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">

    </class>

</hibernate-mapping>

Até agora, informamos o Hibernate sobre como fazer para persistir e carregar objetos da classe Event da tabela EVENTS, cada instância representada por uma coluna na tabela. Agora, continuaremos com o mapeamento de uma única propriedade identificadora para as chaves primárias da tabela. Além disso, como não precisamos nos preocupar em manipular este identificador, iremos configurar uma estratégia de geração de id’s do Hibernate para uma coluna de chave primária substituta:


<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">
        <id name="id" column="EVENT_ID">
            <generator class="native"/>
        </id>
    </class>

</hibernate-mapping>

O elemento id é a declaração de uma propriedade do identificador. O atributo do mapeamento name="id" declara que o nome da propriedade JavaBeans e informa o Hibernate a utilizar os métodos getId() and setId() para acessar a propriedade. A atributo da coluna informa o Hibernate qual coluna da tabela EVENTS mantém o valor de chave primária.

O elemento generator aninhado especifica a estratégia da geração do identificador (como os valores do identificador são gerados?). Neste caso, nós escolhemos native, do qual oferece um nível de portabilidade dependendo no dialeto do banco de dados configurado. O Hibernate suporta o banco de dados gerado, globalmente único, assim como a aplicação determinada, identificadores. A geração do valor do identificador é também um dos muitos pontos de extensão do Hibernate e você pode realizar o plugin na sua própria estratégia.

Finalmente, incluiremos as declarações para as propriedades persistentes da classe no arquivo mapeado. Por padrão, nenhuma das propriedades da classe é considerada persistente:



<hibernate-mapping package="org.hibernate.tutorial.domain">

    <class name="Event" table="EVENTS">
        <id name="id" column="EVENT_ID">
            <generator class="native"/>
        </id>
        <property name="date" type="timestamp" column="EVENT_DATE"/>
        <property name="title"/>
    </class>

</hibernate-mapping>

Assim como com o elemento id, a função name do elemento property informa ao Hibernate qual método getter e setter deverá usar. Assim, neste caso, o Hibernate irá procurar pelos métodos getDate(), setDate(), getTitle() e setTitle().

Nota

Porque fazer o mapeamento da propriedade date incluído na função column, e no title não fazer? Sem a função column o Hibernate, por padrão, utiliza o nome da propriedade como o nome da coluna. Isto funciona bem para o title. Entretanto, o date é uma palavra-chave reservada na maioria dos bancos de dados, por isso seria melhor mapeá-lo com um nome diferente.

O mapeamento do title também não possui a função type. O tipo que declaramos e utilizamos nos arquivos mapeados, não são como você esperava, ou seja, funções de dados Java. Eles também não são como os tipos de base de dados SQL. Esses tipos podem ser chamados de Tipos de mapeamento Hibernate, que são conversores que podem traduzir tipos de dados do Java para os tipos de dados SQL e vice-versa. Novamente, o Hibernate irá tentar determinar a conversão correta e mapeará o type próprio, caso o tipo da função não estiver presente no mapeamento. Em alguns casos, esta detecção automática (que usa Reflection sobre as classes Java) poderá não ter o padrão que você espera ou necessita. Este é o caso com a propriedade date. O Hibernate não sabe se a propriedade, que é do java.util.Date, pode mapear para uma coluna do tipo date do SQL, timestamp ou time. Nós preservamos as informações sobre datas e horas pelo mapeamento da propriedade com um conversor timestamp.

Dica

O Hibernate realiza esta determinação de tipo de mapeamento usando a reflexão quando os arquivos de mapeamentos são processados. Isto pode levar tempo e recursos, portanto se você inicializar o desempenho, será importante que você considere claramente a definição do tipo para uso.

Salve este arquivo de mapeamento como src/main/resources/org/hibernate/tutorial/domain/Event.hbm.xml.

Nestas alturas, você deve possuir a classe persistente e seu arquivo de mapeamento prontos. É o momento de configurar o Hibernate. Primeiro, vamos configurar o HSQLDB para rodar no "modo do servidor".

Nós utilizaremos o Maven exec plugin para lançar o servidor HSQLDB pela execução: mvn exec:java -Dexec.mainClass="org.hsqldb.Server" -Dexec.args="-database.0 file:target/data/tutorial". Você pode ver ele iniciando e vinculando ao soquete TCP/IP, aqui será onde nossa aplicação irá se conectar depois. Se você deseja iniciar uma nova base de dados durante este tutorial, finalize o HSQLDB, delete todos os arquivos no diretório target/data, e inicie o HSQLBD novamente.

O Hibernate conectará ao banco de dados no lugar de sua aplicação, portanto ele precisará saber como obter as conexões. Para este tutorial nós usaremos um pool de conexão autônomo (ao invés de javax.sql.DataSource). O Hibernate vem com o suporte para dois terços dos pools de conexão JDBC de código aberto: c3p0 e proxool. No entanto, nós usaremos o pool de conexão interna do Hibernate para este tutorial.

Cuidado

O pool de conexão interna do Hibernate não é recomendado para uso de produção. Ele possui deficiência em diversos recursos encontrados em qualquer pool de conexão apropriado.

Para as configurações do Hibernate, nós podemos usar um arquivo simples hibernate.properties, um arquivo mais sofisticado hibernate.cfg.xml ou até mesmo uma instalação programática completa. A maioria dos usuários prefere utilizar o arquivo de configuração XML:


<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class"
>org.hsqldb.jdbcDriver</property>
        <property name="connection.url"
>jdbc:hsqldb:hsql://localhost</property>
        <property name="connection.username"
>sa</property>
        <property name="connection.password"
></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size"
>1</property>

        <!-- SQL dialect -->
        <property name="dialect"
>org.hibernate.dialect.HSQLDialect</property>

        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class"
>thread</property>

        <!-- Disable the second-level cache  -->
        <property name="cache.provider_class"
>org.hibernate.cache.NoCacheProvider</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql"
>true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto"
>update</property>

        <mapping resource="org/hibernate/tutorial/domain/Event.hbm.xml"/>

    </session-factory>

</hibernate-configuration
>

Nota

Perceba que este arquivo de configuração especifica um DTD diferente

Configure a SessionFactory do Hibernate. A SessionFactory é uma fábrica global responsável por uma base de dados particular. Se você tiver diversas bases de dados, use diversas configurações <session-factory>, geralmente em diversos arquivos de configuração, para uma inicialização mais fácil.

Os primeiros quatro elementos property contêm a configuração necessária para a conexão JBDC. O elemento property do dialeto especifica a variante do SQL particular que o Hibernate gera.

Dica

In most cases, Hibernate is able to properly determine which dialect to use. See Seção 28.3, “Resolução do Dialeto” for more information.

O gerenciamento automático de sessão do Hibernate para contextos de persistência é bastante útil neste contexto. A opção hbm2ddl.auto habilita a geração automática de esquemas da base de dados, diretamente na base de dados. Isto também pode ser naturalmente desligado apenas removendo a opção de configuração ou redirecionado para um arquivo com ajuda do SchemaExport na tarefa do Ant. Finalmente, iremos adicionar os arquivos das classes de persistência mapeadas na configuração.

Salve este arquivo como hibernate.cfg.xml no diretório src/main/resources.

Nós iremos construir agora o tutorial com Maven. Você necessitará que o Maven esteja instalado; ele está disponível a partir do Maven download page. O Maven gravará o arquivo /pom.xml que criamos anteriormente, além de saber como executar algumas tarefas do projeto básico. Primeiro, vamos rodar o objetivo compile para nos certificarmos de que tudo foi compilado até agora:

[hibernateTutorial]$ mvn compile
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building First Hibernate Tutorial
[INFO]    task-segment: [compile]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [compiler:compile]
[INFO] Compiling 1 source file to /home/steve/projects/sandbox/hibernateTutorial/target/classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2 seconds
[INFO] Finished at: Tue Jun 09 12:25:25 CDT 2009
[INFO] Final Memory: 5M/547M
[INFO] ------------------------------------------------------------------------

É hora de carregar e armazenar alguns objetos Event, mas primeiro nós temos de completar a instalação com algum código de infraestrutura. Você precisa inicializar o Hibernate pela construção de um objeto org.hibernate.SessionFactory global e o armazenamento dele em algum lugar de fácil acesso para o código da aplicação. O org.hibernate.SessionFactory é usado para obter instâncias org.hibernate.Session. O org.hibernate.Session representa uma unidade de single-threaded de trabalho. O org.hibernate.SessionFactory é um objeto global thread-safe, instanciado uma vez.

Criaremos uma classe de ajuda HibernateUtil, que cuida da inicialização e faz acesso a uma org.hibernate.SessionFactory mais conveniente.

package org.hibernate.tutorial.util;


import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
    private static final SessionFactory sessionFactory = buildSessionFactory();
    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        }
        catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Salve este código como src/main/java/org/hibernate/tutorial/util/HibernateUtil.java

Esta classe não só produz uma referência org.hibernate.SessionFactory global em seu inicializador estático, mas também esconde o fato de que utiliza um autônomo estático. Nós poderemos buscar pela referência org.hibernate.SessionFactory a partir do JNDI no servidor da aplicação ou qualquer outra localização para este assunto.

Se você der um nome à SessionFactory em seu arquivo de configuração, o Hibernate irá, de fato, tentar vinculá-lo ao JNDI sob aquele nome, depois que estiver construído. Outra opção melhor seria usar a implementação JMX e deixar o recipiente JMX capaz, instanciar e vincular um HibernateService ao JNDI. Essas opções avançadas são discutidas no documento de referência do Hibernate. Tais opções avançadas serão discutidas mais tarde.

Você precisará agora configurar um sistema de logging. O Hibernate usa logging comuns e lhe oferece a escolha entre o Log4j e o logging do JDK 1.4 . A maioria dos desenvolvedores prefere o Log4j: copie log4j.properties da distribuição do Hibernate no diretório etc/, para seu diretório src, depois vá em hibernate.cfg.xml. Dê uma olhada no exemplo de configuração e mude as configurações se você quiser ter uma saída mais detalhada. Por padrão, apenas as mensagens de inicialização do Hibernate são mostradas no stdout.

O tutorial de infra-estrutura está completo e nós já estamos preparados para algum trabalho de verdade com o Hibernate.

We are now ready to start doing some real work with Hibernate. Let's start by writing an EventManager class with a main() method:

package org.hibernate.tutorial;


import org.hibernate.Session;
import java.util.*;
import org.hibernate.tutorial.domain.Event;
import org.hibernate.tutorial.util.HibernateUtil;
public class EventManager {
    public static void main(String[] args) {
        EventManager mgr = new EventManager();
        if (args[0].equals("store")) {
            mgr.createAndStoreEvent("My Event", new Date());
        }
        HibernateUtil.getSessionFactory().close();
    }
    private void createAndStoreEvent(String title, Date theDate) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);
        session.save(theEvent);
        session.getTransaction().commit();
    }
}

Em createAndStoreEvent(), criamos um novo objeto de Event, e passamos para o Hibernate. O Hibernate sabe como tomar conta do SQL e executa INSERTs no banco de dados.

A org.hibernate.Session is designed to represent a single unit of work (a single atomic piece of work to be performed). For now we will keep things simple and assume a one-to-one granularity between a Hibernate org.hibernate.Session and a database transaction. To shield our code from the actual underlying transaction system we use the Hibernate org.hibernate.Transaction API. In this particular case we are using JDBC-based transactional semantics, but it could also run with JTA.

O que a sessionFactory.getCurrentSession() faz? Primeiro, você pode chamar quantas vezes e de onde quiser, assim que você receber sua org.hibernate.SessionFactory. O método getCurrentSession() sempre retorna à unidade de trabalho "atual". Você se lembra que nós mudamos a opção de configuração desse mecanismo para "thread" em nosso src/main/resources/hibernate.cfg.xml? Devido a esta configuração, o contexto de uma unidade de trabalho atual estará vinculada à thread Java atual que executa nossa aplicação.

Um org.hibernate.Session começa quando for necessária, quando é feita a primeira chamada à getCurrentSession(). É então limitada pelo Hibernate para a thread atual. Quando a transação termina, tanto com commit quanto rollback, o Hibernate também desvincula a Session da thread e fecha isso pra você. Se você chamar getCurrentSession() novamente, você receberá uma nova Session e poderá começar uma nova unidade de trabalho.

Em relação ao escopo da unidade de trabalho, o Hibernate org.hibernate.Session deve ser utilizado para executar uma ou mais operações do banco de dados? O exemplo acima utiliza uma Session para cada operação. Isto é pura coincidência, o exemplo simplesmente não é complexo o bastante para mostrar qualquer outra abordagem. O escopo de um Hibernate org.hibernate.Session é flexível, mas você nunca deve configurar seu aplicativo para utilizar um novo Hibernate org.hibernate.Session para aoperação de banco de dados every. Portanto, mesmo que você o veja algumas vezes mais nos seguintes exemplos, considere session-per-operation como um anti-modelo. Um aplicativo da web real será demonstrado mais adiante neste tutorial.

See Capítulo 13, Transações e Concorrência for more information about transaction handling and demarcation. The previous example also skipped any error handling and rollback.

Para rodar isto, nós faremos uso do Maven exec plugin para chamar nossa classe com a instalação do classpath necessária: mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="store"

Nota

Você precisa executar o mvn compile primeiramente.

Você deverá ver, após a compilação, a inicialização do Hibernate e, dependendo da sua configuração, muito log de saída. No final, você verá a seguinte linha:

[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)

Este é o INSERT executado pelo Hibernate.

Adicionamos uma opção para o método principal com o objetivo de listar os eventos arquivados:

        if (args[0].equals("store")) {

            mgr.createAndStoreEvent("My Event", new Date());
        }
        else if (args[0].equals("list")) {
            List events = mgr.listEvents();
            for (int i = 0; i < events.size(); i++) {
                Event theEvent = (Event) events.get(i);
                System.out.println(
                        "Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate()
                );
            }
        }

Nos também adicionamos um novo listEvents() method is also added:

    private List listEvents() {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        List result = session.createQuery("from Event").list();
        session.getTransaction().commit();
        return result;
    }

Here, we are using a Hibernate Query Language (HQL) query to load all existing Event objects from the database. Hibernate will generate the appropriate SQL, send it to the database and populate Event objects with the data. You can create more complex queries with HQL. See Capítulo 16, HQL: A Linguagem de Consultas do Hibernate for more information.

Agora podemos chamar nossa nova funcionalidade usando, novamente, o Maven exec plugin: mvn exec:java -Dexec.mainClass="org.hibernate.tutorial.EventManager" -Dexec.args="list"

Nós mapeamos uma classe de entidade de persistência para uma tabela. Agora vamos continuar e adicionar algumas associações de classe. Primeiro iremos adicionar pessoas à nossa aplicação e armazenar os eventos em que elas participam.

Iremos adicionar uma coleção de eventos na classe Person. Dessa forma, poderemos navegar pelos eventos de uma pessoa em particular, sem executar uma consulta explicitamente, apenas chamando Person#getEvents. As associações de valores múltiplos são representadas no Hibernate por um dos contratos do Java Collection Framework; aqui nós escolhemos um java.util.Set, uma vez que a coleção não conterá elementos duplicados e a ordem não é relevante em nossos exemplos:

public class Person {


    private Set events = new HashSet();
    public Set getEvents() {
        return events;
    }
    public void setEvents(Set events) {
        this.events = events;
    }
}

Antes de mapearmos esta associação, pense no outro lado. Claramente, poderíamos apenas fazer isto de forma unidirecional. Ou poderíamos criar outra coleção no Event, se quisermos navegar de ambas direções. Isto não é necessário, de uma perspectiva funcional. Você poderá sempre executar uma consulta explícita para recuperar os participantes de um evento em particular. Esta é uma escolha de design que cabe a você, mas o que é claro nessa discussão é a multiplicidade da associação: "muitos" válidos em ambos os lados, nós chamamos isto de uma associação muitos-para-muitos. Daqui pra frente, usaremos o mapeamento muitos-para-muitos do Hibernate:


<class name="Person" table="PERSON">
    <id name="id" column="PERSON_ID">
        <generator class="native"/>
    </id>
    <property name="age"/>
    <property name="firstname"/>
    <property name="lastname"/>

    <set name="events" table="PERSON_EVENT">
        <key column="PERSON_ID"/>
        <many-to-many column="EVENT_ID" class="Event"/>
    </set>

</class>

O Hibernate suporta todo tipo de mapeamento de coleção, sendo um set mais comum. Para uma associação muitos-para-muitos ou relacionamento de entidade n:m, é necessária uma tabela de associação. Cada linha nessa tabela representa um link entre uma pessoa e um evento. O nome da tabela é configurado com a função table do elemento set. O nome da coluna identificadora na associação, pelo lado da pessoa, é definido com o elemento key, o nome da coluna pelo lado dos eventos, é definido com a função column do many-to-many. Você também precisa dizer para o Hibernate a classe dos objetos na sua coleção (a classe do outro lado das coleções de referência).

O esquema de mapeamento para o banco de dados está a seguir:

    _____________        __________________
   |             |      |                  |       _____________
   |   EVENTS    |      |   PERSON_EVENT   |      |             |
   |_____________|      |__________________|      |    PERSON   |
   |             |      |                  |      |_____________|
   | *EVENT_ID   | <--> | *EVENT_ID        |      |             |
   |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  |
   |  TITLE      |      |__________________|      |  AGE        |
   |_____________|                                |  FIRSTNAME  |
                                                  |  LASTNAME   |
                                                  |_____________|
 

Vamos reunir algumas pessoas e eventos em um novo método na classe EventManager:

    private void addPersonToEvent(Long personId, Long eventId) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Person aPerson = (Person) session.load(Person.class, personId);
        Event anEvent = (Event) session.load(Event.class, eventId);
        aPerson.getEvents().add(anEvent);
        session.getTransaction().commit();
    }

Após carregar um Person e um Event, simplesmente modifique a coleção usando os métodos normais de uma coleção. Como você pode ver, não há chamada explícita para update() ou save(); o Hibernate detecta automaticamente que a coleção foi modificada e que necessita ser atualizada. Isso é chamado de checagem suja automática, e você também pode usá-la modificando o nome ou a data de qualquer um dos seus objetos. Desde que eles estejam no estado persistent, ou seja, limitado por uma Session do Hibernate em particular, o Hibernate monitora qualquer alteração e executa o SQL em modo de gravação temporária. O processo de sincronização do estado da memória com o banco de dados, geralmente apenas no final de uma unidade de trabalho, normalmente apenas no final da unidade de trabalho, é chamado de flushing. No nosso código, a unidade de trabalho termina com o commit , ou rollback, da transação do banco de dados.

Você pode também querer carregar pessoas e eventos em diferentes unidades de trabalho. Ou você modifica um objeto fora de um org.hibernate.Session, quando não se encontra no estado persistente (se já esteve neste estado anteriormente, chamamos esse estado de detached). Você pode até mesmo modificar uma coleção quando esta se encontrar no estado detached:

    private void addPersonToEvent(Long personId, Long eventId) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Person aPerson = (Person) session
                .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
                .setParameter("pid", personId)
                .uniqueResult(); // Eager fetch the collection so we can use it detached
        Event anEvent = (Event) session.load(Event.class, eventId);
        session.getTransaction().commit();
        // End of first unit of work
        aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached
        // Begin second unit of work
        Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
        session2.beginTransaction();
        session2.update(aPerson); // Reattachment of aPerson
        session2.getTransaction().commit();
    }

A chamada update cria um objeto persistente novamente, pode-se dizer que ele liga o objeto a uma nova unidade de trabalho, assim qualquer modificação que você faça neste objeto enquanto estiver no estado desanexado pode ser salvo no banco de dados. Isso inclui qualquer modificação (adição/exclusão) que você faça em uma coleção da entidade deste objeto.

Bem, isso não é de grande utilidade na nossa situação atual, porém, é um importante conceito que você pode criar em seu próprio aplicativo. No momento, complete este exercício adicionando uma ação ao método principal da classe EventManager e chame-o pela linha de comando. Se você precisar dos identificadores de uma pessoa ou evento - o método save() retornará estes identificadores (você poderá modificar alguns dos métodos anteriores para retornar aquele identificador):

        else if (args[0].equals("addpersontoevent")) {

            Long eventId = mgr.createAndStoreEvent("My Event", new Date());
            Long personId = mgr.createAndStorePerson("Foo", "Bar");
            mgr.addPersonToEvent(personId, eventId);
            System.out.println("Added person " + personId + " to event " + eventId);
        }

Este foi um exemplo de uma associação entre duas classes igualmente importantes: duas entidades. Como mencionado anteriormente, há outras classes e tipos dentro de um modelo típico, geralmente "menos importante". Alguns você já viu, como um int ou uma String. Nós chamamos essas classes de tipos de valores, e suas instâncias dependem de uma entidade particular. As instâncias desses tipos não possuem sua própria identidade, nem são compartilhados entre entidades. Duas pessoas não referenciam o mesmo objeto firstname mesmo se elas tiverem o mesmo objeto firstname. Naturalmente, os tipos de valores não são apenas encontrados dentro da JDK, mas você pode também criar suas classes como, por exemplo, Address ou MonetaryAmount. De fato, no aplicativo Hibernate todas as classes JDK são consideradas tipos de valores.

Você também pode criar uma coleção de tipo de valores. Isso é conceitualmente muito diferente de uma coleção de referências para outras entidades, mas em Java parece ser quase a mesma coisa.

Vamos adicionar uma coleção de endereços de e-mail à entidade Person. Isto será representado como um java.util.Set das instâncias java.lang.String:

    private Set emailAddresses = new HashSet();


    public Set getEmailAddresses() {
        return emailAddresses;
    }
    public void setEmailAddresses(Set emailAddresses) {
        this.emailAddresses = emailAddresses;
    }

Segue abaixo o mapeamento deste Set:


        <set name="emailAddresses" table="PERSON_EMAIL_ADDR">
            <key column="PERSON_ID"/>
            <element type="string" column="EMAIL_ADDR"/>
        </set>

A diferença comparada com o mapeamento anterior se encontra na parte element, que informa ao Hibernate que a coleção não contém referências à outra entidade, mas uma coleção de elementos do tipo String. O nome da tag em minúsculo indica que se trata de um tipo/conversor de mapeamento do Hibernate. Mais uma vez, a função table do elemento set determina o nome da tabela para a coleção. O elemento key define o nome da coluna de chave estrangeira na tabela de coleção. A função column dentro do elemento element define o nome da coluna onde os valores da String serão armazenados.

Segue abaixo o esquema atualizado:

  _____________        __________________
 |             |      |                  |       _____________
 |   EVENTS    |      |   PERSON_EVENT   |      |             |       ___________________
 |_____________|      |__________________|      |    PERSON   |      |                   |
 |             |      |                  |      |_____________|      | PERSON_EMAIL_ADDR |
 | *EVENT_ID   | <--> | *EVENT_ID        |      |             |      |___________________|
 |  EVENT_DATE |      | *PERSON_ID       | <--> | *PERSON_ID  | <--> |  *PERSON_ID       |
 |  TITLE      |      |__________________|      |  AGE        |      |  *EMAIL_ADDR      |
 |_____________|                                |  FIRSTNAME  |      |___________________|
                                                |  LASTNAME   |
                                                |_____________|
 

Você pode observar que a chave primária da tabela da coleção é na verdade uma chave composta, usando as duas colunas. Isso também implica que cada pessoa não pode ter endereços de e-mail duplicados, o que é exatamente a semântica que precisamos para um set em Java.

Você pode agora tentar adicionar elementos à essa coleção, do mesmo modo que fizemos anteriormente ligando pessoas e eventos. É o mesmo código em Java:

    private void addEmailToPerson(Long personId, String emailAddress) {

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        Person aPerson = (Person) session.load(Person.class, personId);
        // adding to the emailAddress collection might trigger a lazy load of the collection
        aPerson.getEmailAddresses().add(emailAddress);
        session.getTransaction().commit();
    }

Desta vez não utilizamos uma consulta fetch (busca) para inicializar a coleção. Monitore o log SQL e tente otimizá-lo com árdua busca.

Agora iremos mapear uma associação bidirecional. Você fará uma associação entre o trabalho person e event de ambos os lados em Java. O esquema do banco de dados acima não muda, de forma que você continua possuir a multiplicidade muitos-para-muitos.

Primeiramente, adicione uma coleção de participantes à classe Event:

    private Set participants = new HashSet();


    public Set getParticipants() {
        return participants;
    }
    public void setParticipants(Set participants) {
        this.participants = participants;
    }

Agora mapeie este lado da associação em Event.hbm.xml.


        <set name="participants" table="PERSON_EVENT" inverse="true">
            <key column="EVENT_ID"/>
            <many-to-many column="PERSON_ID" class="Person"/>
        </set
>

Como você pode ver, esses são mapeamentos set normais em ambos documentos de mapeamento. Observe que os nomes das colunas em key e many-to-many estão trocados em ambos os documentos de mapeamento. A adição mais importante feita está na função inverse="true" no elemento set da coleção da classe Event.

Isso significa que o Hibernate deve pegar o outro lado, a classe Person, quando precisar encontrar informação sobre a relação entre as duas entidades. Isso será muito mais fácil de entender quando você analisar como a relação bidirecional entre as entidades é criada.

Primeiro, tenha em mente que o Hibernate não afeta a semântica normal do Java. Como foi que criamos um link entre uma Person e um Event no exemplo unidirecional? Adicionamos uma instância de Event, da coleção de referências de eventos, à uma instância de Person. Então, obviamente, se quisermos que este link funcione bidirecionalmente, devemos fazer a mesma coisa para o outro lado, adicionando uma referência de Person na coleção de um Event. Essa "configuração de link de ambos os lados" é absolutamente necessária e você nunca deve esquecer de fazê-la.

Muitos desenvolvedores programam de maneira defensiva e criam métodos de gerenciamento de um link que ajustam-se corretamente em ambos os lados (como por exemplo, em Person):

    protected Set getEvents() {

        return events;
    }
    protected void setEvents(Set events) {
        this.events = events;
    }
    public void addToEvent(Event event) {
        this.getEvents().add(event);
        event.getParticipants().add(this);
    }
    public void removeFromEvent(Event event) {
        this.getEvents().remove(event);
        event.getParticipants().remove(this);
    }

Observe que os métodos set e get da coleção estão protegidos. Isso permite que classes e subclasses do mesmo pacote continuem acessando os métodos, mas evita que qualquer outra classe, que não esteja no mesmo pacote, acesse a coleção diretamente. Repita os passos para a coleção do outro lado.

E sobre o mapeamento da função inverse? Para você, e para o Java, um link bidirecional é simplesmente uma questão de configurar corretamente as referências de ambos os lados. O Hibernate, entretanto, não possui informação necessária para ajustar corretamente as instruções INSERT e UPDATE do SQL (para evitar violações de restrição) e precisa de ajuda para manipular as associações bidirecionais de forma apropriada. Ao fazer um lado da associação com a função inverse, você instrui o Hibernate para basicamente ignorá-lo, considerando-o uma cópia do outro lado. Isso é o necessário para o Hibernate compreender todas as possibilidades quando transformar um modelo de navegação bidirecional em esquema de banco de dados do SQL. As regras que você precisa lembrar são diretas: todas as associações bidirecionais necessitam que um lado possua a função inverse. Em uma associação de um-para-muitos, precisará ser o lado de "muitos", já em uma associação de muitos-para-muitos você poderá selecionar qualquer lado.

Um aplicativo de web do Hibernate utiliza uma Session e uma Transaction quase do mesmo modo que um aplicativo autônomo. Entretanto, alguns modelos comuns são úteis. Nós agora criaremos um EventManagerServlet. Esse servlet lista todos os eventos salvos no banco de dados, e cria um formulário HTML para entrada de novos eventos.

Nós deveremos criar o nosso servket de processamento básico primeiramente. Uma vez que o servlet manuseia somente requisições GET do HTTP, o método que iremos implementar é doGet():

package org.hibernate.tutorial.web;


// Imports
public class EventManagerServlet extends HttpServlet {
    protected void doGet(
            HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        SimpleDateFormat dateFormatter = new SimpleDateFormat( "dd.MM.yyyy" );
        try {
            // Begin unit of work
            HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
            // Process request and render page...
            // End unit of work
            HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit();
        }
        catch (Exception ex) {
            HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback();
            if ( ServletException.class.isInstance( ex ) ) {
                throw ( ServletException ) ex;
            }
            else {
                throw new ServletException( ex );
            }
        }
    }
}

Salve esse servlet como src/main/java/org/hibernate/tutorial/web/EventManagerServlet.java

O modelo que estamos aplicando neste código é chamado session-per-request. Quando uma solicitação chega ao servlet, uma nova Session do Hibernate é aberta através da primeira chamada para getCurrentSession() em SessionFactory. Então uma transação do banco de dados é inicializada e todo acesso a dados deve ocorrer dentro de uma transação, não importando se o dado é de leitura ou escrita. Não se deve utilizar o modo auto-commit em aplicações.

Nunca utilize uma nova Session do Hibernate para todas as operações de banco de dados. Utilize uma Session do Hibernate que seja de interesse à todas as solicitações. Utilize getCurrentSession(), para que seja vinculado automaticamente à thread atual de Java.

Agora, as possíveis ações de uma solicitação serão processadas e uma resposta HTML será renderizada. Já chegaremos nesta parte.

Finalmente, a unidade de trabalho termina quando o processamento e a renderização são completados. Se ocorrer algum erro durante o processamento ou a renderização, uma exceção será lançada e a transação do banco de dados revertida. Isso completa o modelo session-per-request. Em vez de usar código de demarcação de transação em todo servlet você pode também criar um filtro servlet. Dê uma olhada no website do Hibernate e do Wiki para maiores informações sobre esse modelo, chamado Sessão Aberta na Visualização. Você precisará disto assim que você considerar renderizar sua visualização no JSP, não apenas num servlet.

Vamos implementar o processamento da solicitação e renderização da página.

        // Write HTML header

        PrintWriter out = response.getWriter();
        out.println("<html><head><title>Event Manager</title></head><body>");
        // Handle actions
        if ( "store".equals(request.getParameter("action")) ) {
            String eventTitle = request.getParameter("eventTitle");
            String eventDate = request.getParameter("eventDate");
            if ( "".equals(eventTitle) || "".equals(eventDate) ) {
                out.println("<b><i>Please enter event title and date.</i></b>");
            }
            else {
                createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
                out.println("<b><i>Added event.</i></b>");
            }
        }
        // Print page
       printEventForm(out);
       listEvents(out, dateFormatter);
       // Write HTML footer
       out.println("</body></html>");
       out.flush();
       out.close();

O estilo deste código misturado com o Java e HTML, não escalariam em um aplicativo mais complexo, tenha em mente que estamos somente ilustrando os conceitos básicos do Hibernate neste tutorial. O código imprime um cabeçalho e nota de rodapé em HTML. Dentro desta página, são impressos um formulário para entrada de evento em HTML e uma lista de todos os evento no banco de dados. O primeiro método é trivial e somente produz um HTML:

    private void printEventForm(PrintWriter out) {

        out.println("<h2>Add new event:</h2>");
        out.println("<form>");
        out.println("Title: <input name='eventTitle' length='50'/><br/>");
        out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>");
        out.println("<input type='submit' name='action' value='store'/>");
        out.println("</form>");
    }

O método listEvents() utiliza a Session do Hibernate, limitado ao thread atual para executar uma consulta:

    private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) {


        List result = HibernateUtil.getSessionFactory()
                .getCurrentSession().createCriteria(Event.class).list();
        if (result.size() > 0) {
            out.println("<h2>Events in database:</h2>");
            out.println("<table border='1'>");
            out.println("<tr>");
            out.println("<th>Event title</th>");
            out.println("<th>Event date</th>");
            out.println("</tr>");
            Iterator it = result.iterator();
            while (it.hasNext()) {
                Event event = (Event) it.next();
                out.println("<tr>");
                out.println("<td>" + event.getTitle() + "</td>");
                out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>");
                out.println("</tr>");
            }
            out.println("</table>");
        }
    }

Finalmente, a ação store, é despachada ao método createAndStoreEvent(), que também utiliza a Session da thread atual:

    protected void createAndStoreEvent(String title, Date theDate) {

        Event theEvent = new Event();
        theEvent.setTitle(title);
        theEvent.setDate(theDate);
        HibernateUtil.getSessionFactory()
                .getCurrentSession().save(theEvent);
    }

O servlet está completo agora. Uma solicitação ao servlet será processada com uma única Session e Transaction. Quanto antes estiver no aplicativo autônomo, maior a chance do Hibernate vincular automaticamente estes objetos à thread atual de execução. Isto lhe dá a liberdade para inserir seu código e acessar a SessionFactory como desejar. Geralmente, usaríamos um diagrama mais sofisticado e moveríamos o código de acesso de dados para os objetos de acesso dos dados (o modelo DAO). Veja o Hibernate Wiki para mais exemplos.

Para implementar este aplicativo em testes, nós devemos criar um Arquivo da Web (WAR). Primeiro, nós devemos definir o descritor WAR como src/main/webapp/WEB-INF/web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <servlet>
        <servlet-name>Event Manager</servlet-name>
        <servlet-class>org.hibernate.tutorial.web.EventManagerServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Event Manager</servlet-name>
        <url-pattern>/eventmanager</url-pattern>
    </servlet-mapping>
</web-app>

Para construir e implementar, chame seu diretório de projeto ant war e copie o arquivo hibernate-tutorial.war para seu diretório Tomcat webapp.

Nota

If you do not have Tomcat installed, download it from http://tomcat.apache.org/ and follow the installation instructions. Our application requires no changes to the standard Tomcat configuration.

Uma vez implementado e com o Tomcat rodando, acesse o aplicativo em http://localhost:8080/hibernate-tutorial/eventmanager. Tenha a certeza de observar o log do Tomcat para ver o Hibernate inicializar quando a primeira solicitação chegar em seu servlet (o inicializador estático no HibernateUtil é chamado) e para obter o resultado detalhado caso exceções aconteçam.

O diagrama abaixo fornece uma visão de altíssimo nível da arquitetura do Hibernate:

Unfortunately we cannot provide a detailed view of all possible runtime architectures. Hibernate is sufficiently flexible to be used in a number of ways in many, many architectures. We will, however, illustrate 2 specifically since they are extremes.

Here are quick discussions about some of the API objects depicted in the preceding diagrams (you will see them again in more detail in later chapters).

SessionFactory (org.hibernate.SessionFactory)

A thread-safe, immutable cache of compiled mappings for a single database. A factory for org.hibernate.Session instances. A client of org.hibernate.connection.ConnectionProvider. Optionally maintains a second level cache of data that is reusable between transactions at a process or cluster level.

Session (org.hibernate.Session)

A single-threaded, short-lived object representing a conversation between the application and the persistent store. Wraps a JDBC java.sql.Connection. Factory for org.hibernate.Transaction. Maintains a first level cache of persistent the application's persistent objects and collections; this cache is used when navigating the object graph or looking up objects by identifier.

Objetos persistentes e coleções

Short-lived, single threaded objects containing persistent state and business function. These can be ordinary JavaBeans/POJOs. They are associated with exactly one org.hibernate.Session. Once the org.hibernate.Session is closed, they will be detached and free to use in any application layer (for example, directly as data transfer objects to and from presentation). Capítulo 11, Trabalhando com objetos discusses transient, persistent and detached object states.

Objetos e coleções desanexados e transientes

Instances of persistent classes that are not currently associated with a org.hibernate.Session. They may have been instantiated by the application and not yet persisted, or they may have been instantiated by a closed org.hibernate.Session. Capítulo 11, Trabalhando com objetos discusses transient, persistent and detached object states.

Transaction (org.hibernate.Transaction)

(Optional) A single-threaded, short-lived object used by the application to specify atomic units of work. It abstracts the application from the underlying JDBC, JTA or CORBA transaction. A org.hibernate.Session might span several org.hibernate.Transactions in some cases. However, transaction demarcation, either using the underlying API or org.hibernate.Transaction, is never optional.

ConnectionProvider (org.hibernate.connection.ConnectionProvider)

(Optional) A factory for, and pool of, JDBC connections. It abstracts the application from underlying javax.sql.DataSource or java.sql.DriverManager. It is not exposed to application, but it can be extended and/or implemented by the developer.

TransactionFactory (org.hibernate.TransactionFactory)

(Optional) A factory for org.hibernate.Transaction instances. It is not exposed to the application, but it can be extended and/or implemented by the developer.

Extension Interfaces

O Hibernate oferece várias opções de interfaces estendidas que você pode implementar para customizar sua camada persistente. Veja a documentação da API para maiores detalhes.

A maioria das aplicações que usa o Hibernate necessita de algum tipo de sessão "contextual", onde uma sessão dada é na verdade um escopo de um contexto. Entretanto, através de aplicações, a definição sobre um contexto é geralmente diferente; e contextos diferentes definem escopos diferentes. Aplicações usando versões anteriores ao Hibernate 3.0 tendem a utilizar tanto sessões contextuais baseadas em ThreadLocal, classes utilitárias como HibernateUtil, ou utilizar frameworks de terceiros (como Spring ou Pico) que provê sessões contextuais baseadas em proxy.

A partir da versão 3.0.1, o Hibernate adicionou o método SessionFactory.getCurrentSession(). Inicialmente, este considerou o uso de transações JTA, onde a transação JTA definia tanto o escopo quanto o contexto de uma sessão atual. Dada a maturidade de diversas implementações autônomas disponíveis do JTA TransactionManager, a maioria (se não todos) dos aplicativos deveria utilizar o gerenciador de transações JTA sendo ou não instalados dentro de um recipiente J2EE. Baseado neste recurso, você deve sempre utilizar sessões contextuais baseadas em JTA.

Entretanto, a partir da versão 3.1, o processo por trás do método SessionFactory.getCurrentSession() é agora plugável. Com isso, uma nova interface (org.hibernate.context.CurrentSessionContext) e um novo parâmetro de configuração (hibernate.current_session_context_class) foram adicionados para possibilitar a compatibilidade do contexto e do escopo na definição de sessões correntes.

Consulte no Javadocs sobre a interface org.hibernate.context.CurrentSessionContext para uma discussão detalhada. Ela define um método único, currentSession(), pelo qual a implementação é responsável por rastrear a sessão contextual atual. Fora da caixa, o Hibernate surge com três implementações dessa interface:

The first two implementations provide a "one session - one database transaction" programming model. This is also known and used as session-per-request. The beginning and end of a Hibernate session is defined by the duration of a database transaction. If you use programmatic transaction demarcation in plain JSE without JTA, you are advised to use the Hibernate Transaction API to hide the underlying transaction system from your code. If you use JTA, you can utilize the JTA interfaces to demarcate transactions. If you execute in an EJB container that supports CMT, transaction boundaries are defined declaratively and you do not need any transaction or session demarcation operations in your code. Refer to Capítulo 13, Transações e Concorrência for more information and code examples.

O parâmetro de configuração hibernate.current_session_context_class define qual implementação org.hibernate.context.CurrentSessionContext deve ser usada. Note que para compatibilidade anterior, se este parâmetro de configuração não for determinado mas um org.hibernate.transaction.TransactionManagerLookup for configurado, Hibernate usará o org.hibernate.context.JTASessionContext. Tipicamente, o valor deste parâmetro nomearia apenas a classe de implementação para usar; para as três implementações fora da caixa, entretanto, há dois pequenos nomes correspondentes, "jta", "thread", e "managed".

Devido ao fato do Hibernate ser projetado para operar em vários ambientes diferentes, há um grande número de parâmetros de configuração. Felizmente, a maioria possui valores padrão consideráveis e o Hibernate é distribuído com um arquivo hibernate.properties de exemplo no etc/ que mostra várias opções. Apenas coloque o arquivo de exemplo no seu classpath e personalize-o.

Uma instância de org.hibernate.cfg.Configuration representa um conjunto inteiro de mapeamentos de tipos Java de aplicação para um banco de dados SQL. O org.hibernate.cfg.Configuration é usado para construir uma SessionFactory imutável. Os mapeamentos são compilados a partir de diversos arquivos de mapeamento XML.

Você pode obter uma instância org.hibernate.cfg.Configuration intanciando-a diretamente e especificando os documentos de mapeamento XML. Se os arquivos de mapeamento estiverem no classpath, use addResource(). Por exemplo:

Configuration cfg = new Configuration()

    .addResource("Item.hbm.xml")
    .addResource("Bid.hbm.xml");

Uma alternativa é especificar a classe mapeada e permitir que o Hibernate encontre o documento de mapeamento para você:

Configuration cfg = new Configuration()

    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class);

O Hibernate procurará pelos arquivos de mapeamento chamados /org/hibernate/auction/Item.hbm.xml e /org/hibernate/auction/Bid.hbm.xml no classpath. Esta abordagem elimina qualquer nome de arquivo de difícil compreensão.

Uma Configuration também permite que você especifique propriedades de configuração específica. Por exemplo:

Configuration cfg = new Configuration()

    .addClass(org.hibernate.auction.Item.class)
    .addClass(org.hibernate.auction.Bid.class)
    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
    .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
    .setProperty("hibernate.order_updates", "true");

Esta não é a única forma de passar as propriedades de configuração para o Hibernate. As várias opções incluem:

Caso você deseje inicializar rapidamente o hibernate.properties é a abordagem mais rápida.

O org.hibernate.cfg.Configuration é previsto como um objeto de tempo de inicialização, a ser descartado quando um SessionFactory for criado.

Normalmente, você deseja que o org.hibernate.SessionFactory crie e faça um um pool de conexões JDBC para você. Se você seguir essa abordagem, a abertura de um org.hibernate.Session será tão simples quanto:

Session session = sessions.openSession(); // open a new Session

Assim que você fizer algo que requeira o acesso ao banco de dados, uma conexão JDBC será obtida a partir do pool.

Para esse trabalho, precisaremos passar algumas propriedades da conexão JDBC para o Hibernate. Todos os nomes de propriedades Hibernate e semânticas são definidas na classe org.hibernate.cfg.Environment. Descreveremos agora as configurações mais importantes para a conexão JDBC.

O Hibernate obterá conexões (e efetuará o pool) usando java.sql.DriverManager se você determinar as seguintes propriedades:


No entanto, o algoritmo de pool de conexões do próprio Hibernate é um tanto rudimentar. A intenção dele é ajudar a iniciar e não para ser usado em um sistema de produção ou até para testar o desempenho. Você deve utilizar um pool de terceiros para conseguir um melhor desempenho e estabilidade. Apenas substitua a propriedade hibernate.connection.pool_size pela configuração específica do pool de conexões. Isto irá desligar o pool interno do Hibernate. Por exemplo, você pode gostar de usar C3P0.

O C3P0 é um pool conexão JDBC de código aberto distribuído junto com Hibernate no diretório lib. O Hibernate usará o próprio org.hibernate.connection.C3P0ConnectionProvider para o pool de conexão se você configurar a propriedade hibernate.c3p0.*. Se você gostar de usar Proxool, consulte o pacote hibernate.properties e o web site do Hibernate para mais informações.

Este é um exemplo de arquivo hibernate.properties para c3p0:

hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
hibernate.connection.username = myuser
hibernate.connection.password = secret
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Para usar dentro de um servidor de aplicação, você deve configurar o Hibernate para obter conexões de um servidor de aplicação javax.sql.Datasource registrado no JNDI. Você precisará determinar pelo menos uma das seguintes propriedades:


Eis um exemplo de arquivo hibernate.properties para um servidor de aplicação fornecedor de fontes de dados JNDI:

hibernate.connection.datasource = java:/comp/env/jdbc/test
hibernate.transaction.factory_class = \
    org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
    org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Conexões JDBC obtidas de um datasource JNDI irão automaticamente participar das transações gerenciadas pelo recipiente no servidor de aplicação.

As propriedades de conexão arbitrárias podem ser acrescentandas ao "hibernate.connnection" ao nome da propriedade. Por exemplo, você deve especificar a propriedade de conexão charSet usando hibernate.connection.charSet.

Você pode definir sua própria estratégia de plugin para obter conexões JDBC implementando a interface org.hibernate.connection.ConnectionProvider e especificando sua implementação customizada através da propriedade hibernate.connection.provider_class.

Há um grande número de outras propriedades que controlam o comportamento do Hibernate em tempo de execução. Todos são opcionais e têm valores padrão lógicos.

Tabela 3.3. Propriedades de Configuração do Hibernate

Nome da PropriedadePropósito
hibernate.dialectO nome da classe de um Hibernate org.hibernate.dialect.Dialect que permite o Hibernate gerar SQL otimizado para um banco de dados relacional em particular.

e.g. full.classname.of.Dialect

Na maioria dos casos, o Hibernate irá atualmente estar apto a escolher a implementação org.hibernate.dialect.Dialect correta baseada no JDBC metadata retornado pelo JDBC driver.

hibernate.show_sqlEscreve todas as instruções SQL no console. Esta é uma alternativa para configurar a categoria de log org.hibernate.SQL to debug.

e.g. true | false

hibernate.format_sqlImprime o SQL formatado no log e recipiente.

e.g. true | false

hibernate.default_schemaQualifica no SQL gerado, os nome das tabelas desqualificadas com o esquema/espaço da tabela dado.

e.g. SCHEMA_NAME

hibernate.default_catalogQualifica no SQL gerado, os nome das tabelas desqualificadas com catálogo dado.

e.g. CATALOG_NAME

hibernate.session_factory_nameO org.hibernate.SessionFactory irá automaticamente se ligar a este nome no JNDI depois de ter sido criado.

e.g. jndi/composite/name

hibernate.max_fetch_depthEstabelece a "profundidade" máxima para árvore de busca de união externa para associações finais únicas (um para um, muitos para um). Um 0 desativa por padrão a busca de união externa.

eg. valores recomendados entre0 e 3

hibernate.default_batch_fetch_sizeDetermina um tamanho padrão para busca de associações em lotes do Hibernate.

eg. valores recomendados 4, 8, 16

hibernate.default_entity_modeDetermina um modo padrão para representação de entidade para todas as sessões abertas desta SessionFactory

dynamic-map, dom4j, pojo

hibernate.order_updatesForça o Hibernate a ordenar os updates SQL pelo valor da chave primária dos ítens a serem atualizados. Isto resultará em menos deadlocks nas transações em sistemas altamente concorrente.

e.g. true | false

hibernate.generate_statisticsSe habilitado, o Hibernate coletará estatísticas úteis para o ajuste do desempenho.

e.g. true | false

hibernate.use_identifier_rollbackSe habilitado, propriedades identificadoras geradas serão zeradas para os valores padrão quando os objetos forem apagados.

e.g. true | false

hibernate.use_sql_commentsSe ligado, o Hibernate irá gerar comentários dentro do SQL, para facilitar a depuração, o valor padrão é false

e.g. true | false

hibernate.id.new_generator_mappingsSetting is relevant when using @GeneratedValue. It indicates whether or not the new IdentifierGenerator implementations are used for javax.persistence.GenerationType.AUTO, javax.persistence.GenerationType.TABLE and javax.persistence.GenerationType.SEQUENCE. Default to false to keep backward compatibility.

e.g. true | false


Nota

We recommend all new projects which make use of to use @GeneratedValue to also set hibernate.id.new_generator_mappings=true as the new generators are more efficient and closer to the JPA 2 specification semantic. However they are not backward compatible with existing databases (if a sequence or a table is used for id generation).

Tabela 3.4. JDBC Hibernate e Propriedades de Conexão

Nome da PropriedadePropósito
hibernate.jdbc.fetch_sizeUm valor maior que zero determina o tamanho da buscado JDBC (chamadas Statement.setFetchSize()).
hibernate.jdbc.batch_sizeUm valor maior que zero habilita o uso das atualizações em lotes JDBC2 pelo Hibernate.

ex. valores recomentados entre 5 e 30

hibernate.jdbc.batch_versioned_dataSet this property to true if your JDBC driver returns correct row counts from executeBatch(). It is usually safe to turn this option on. Hibernate will then use batched DML for automatically versioned data. Defaults to false.

e.g. true | false

hibernate.jdbc.factory_classEscolher um org.hibernate.jdbc.Batcher. Muitas aplicações não irão precisar desta propriedade de configuração.

exemplo classname.of.BatcherFactory

hibernate.jdbc.use_scrollable_resultsetHabilita o uso dos resultados de ajustes roláveis do JDBC2 pelo Hibernate. Essa propriedade somente é necessária quando se usa Conexões JDBC providas pelo usuário. Do contrário, o Hibernate os os metadados da conexão.

e.g. true | false

hibernate.jdbc.use_streams_for_binaryUtilize fluxos para escrever/ler tipos binary ou tipos serializable para/do JDBC. *system-level property*

e.g. true | false

hibernate.jdbc.use_get_generated_keysPossibilita o uso do PreparedStatement.getGeneratedKeys() JDBC3 para recuperar chaves geradas de forma nativa depois da inserção. Requer driver JDBC3+ e JRE1.4+, ajuste para falso se seu driver tiver problemas com gerador de indentificadores Hibernate. Por padrão, tente determinar o driver capaz de usar metadados da conexão.

exemplo true|false

hibernate.connection.provider_classO nome da classe de um org.hibernate.connection.ConnectionProvider, do qual proverá conexões JDBC para o Hibernate.

exemploclassname.of.ConnectionProvider

hibernate.connection.isolationDetermina o nível de isolamento de uma transação JDBC. Verifique java.sql.Connection para valores significativos mas note que a maior parte dos bancos de dados não suportam todos os isolamentos que não são padrões.

exemplo 1, 2, 4, 8

hibernate.connection.autocommitHabilita o auto-commit para conexões no pool JDBC (não recomendado).

e.g. true | false

hibernate.connection.release_modeEspecifica quando o Hibernate deve liberar conexões JDBC. Por padrão, uma conexão JDBC é retida até a sessão estar explicitamente fechada ou desconectada. Para uma fonte de dados JTA do servidor de aplicação, você deve usar after_statement para forçar a liberação da conexões depois de todas as chamadas JDBC. Para uma conexão não-JTA, freqüentemente faz sentido liberar a conexão ao fim de cada transação, usando after_transaction. O auto escolherá after_statement para as estratégias de transaçãoes JTA e CMT e after_transaction para as estratégias de transação JDBC.

exemplo auto (padrão) | on_close | after_transaction | after_statement

This setting only affects Sessions returned from SessionFactory.openSession. For Sessions obtained through SessionFactory.getCurrentSession, the CurrentSessionContext implementation configured for use controls the connection release mode for those Sessions. See Seção 2.3, “Sessões Contextuais”

hibernate.connection.<propertyName>Passar a propriedade JDBC <propertyName> para DriverManager.getConnection().
hibernate.jndi.<propertyName>Passar a propriedade <propertyName> para o JNDI InitialContextFactory.

Tabela 3.5. Propriedades de Cachê do Hibernate

Nome da PropriedadePropósito
hibernate.cache.provider_classO nome da classe de um CacheProvider personalizado.

exemplo classname.of.CacheProvider

hibernate.cache.use_minimal_putsOtimizar operação de cachê de segundo nível para minimizar escritas, ao custo de leituras mais freqüentes. Esta configuração é mais útil para cachês em cluster e, no Hibernate3, é habilitado por padrão para implementações de cache em cluster.

exemplo true|false

hibernate.cache.use_query_cacheHabilita a cache de consultas. Mesmo assim, consultas individuais ainda têm que ser habilitadas para o cache.

exemplo true|false

hibernate.cache.use_second_level_cachePode ser utilizado para desabilitar completamente o cache de segundo nível, o qual é habilitado por padrão para as classes que especificam um mapeamento <cache>.

exemplo true|false

hibernate.cache.query_cache_factoryO nome de classe de uma interface personalizada QueryCache, padroniza para o StandardQueryCache criado automaticamente.

exemplo classname.of.QueryCache

hibernate.cache.region_prefixUm prefixo para usar em nomes regionais de cachê de segundo nível

exemplo prefix

hibernate.cache.use_structured_entriesForça o Hibernate a armazenar dados no cachê de segundo nível em um formato mais humanamente amigável.

exemplo true|false

hibernate.cache.default_cache_concurrency_strategySetting used to give the name of the default org.hibernate.annotations.CacheConcurrencyStrategy to use when either @Cacheable or @Cache is used. @Cache(strategy="..") is used to override this default.


Tabela 3.7. Propriedades Variadas

Nome da PropriedadePropósito
hibernate.current_session_context_classSupply a custom strategy for the scoping of the "current" Session. See Seção 2.3, “Sessões Contextuais” for more information about the built-in strategies.

exemplo jta | thread | managed | custom.Class

hibernate.query.factory_classEscolha a implementação de análise HQL.

exemplo org.hibernate.hql.ast. ASTQueryTranslatorFactory ou org.hibernate.hql.classic. ClassicQueryTranslatorFactory

hibernate.query.substitutionsMapeamento a partir de símbolos em consultas do Hibernate para para símbolos SQL (símbolos devem ser por exemplo, funções ou nome literais).

exemplo hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC

hibernate.hbm2ddl.autoAutomaticamente valida ou exporta DDL esquema para o banco de dados quando o SessionFactory é criado. Com create-drop, o esquema do banco de dados será excluido quando a SessionFactory for fechada explicitamente.

exemplo validate | update | create | create-drop

hibernate.hbm2ddl.import_files

Comma-separated names of the optional files containing SQL DML statements executed during the SessionFactory creation. This is useful for testing or demoing: by adding INSERT statements for example you can populate your database with a minimal set of data when it is deployed.

File order matters, the statements of a give file are executed before the statements of the following files. These statements are only executed if the schema is created ie if hibernate.hbm2ddl.auto is set to create or create-drop.

e.g. /humans.sql,/dogs.sql

hibernate.bytecode.use_reflection_optimizer

Enables the use of bytecode manipulation instead of runtime reflection. This is a System-level property and cannot be set in hibernate.cfg.xml. Reflection can sometimes be useful when troubleshooting. Hibernate always requires either CGLIB or javassist even if you turn off the optimizer.

e.g. true | false

hibernate.bytecode.provider

Both javassist or cglib can be used as byte manipulation engines; the default is javassist.

e.g. javassist | cglib


Você deve sempre determinar a propriedade hibernate.dialect para a subclasse de org.hibernate.dialect.Dialect correta de seu banco de dados. Se você especificar um dialeto, o Hibernate usará padrões lógicos para qualquer um das outras propriedades listadas abaixo, reduzindo o esforço de especificá-los manualmente.


O Hibernate utiliza o Simple Logging Facade for Java (SLF4J) com o objetivo de registrar os diversos eventos de sistema. O SLF4J pode direcionar a sua saída de logging a diversos frameworks de logging (NOP, Simple, log4j version 1.2, JDK 1.4 logging, JCL ou logback) dependendo de sua escolha de vinculação. Com o objetivo de determinar o seu logging, você precisará do slf4j-api.jar em seu classpatch juntamente com o arquivo jar para a sua vinculação preferida - slf4j-log4j12.jar no caso do Log4J. Consulte o SLF4J documentation para maiores detalhes. Para usar o Log4j você precisará também colocar um arquivo log4j.properties em seu classpath. Um exemplo do arquivo de propriedades está distribuído com o Hibernate no diretório src/.

Nós recomendamos que você se familiarize-se com mensagens de log do Hibernate. Tem sido um árduo trabalho fazer o log Hibernate tão detalhado quanto possível, sem fazê-lo ilegível. É um dispositivo de controle de erros essencial. As categorias de log mais interessantes são as seguintes:


Ao desenvolver aplicações com Hibernate, você deve quase sempre trabalhar com o depurador debug habilitado para a categoria org.hibernate.SQL, ou, alternativamente, com a propriedade hibernate.show_sql habilitada.

Uma maneira alternativa de configuração é especificar uma configuração completa em um arquivo chamado hibernate.cfg.xml. Este arquivo pode ser usado como um substituto para o arquivo hibernate.properties ou, se ambos estiverem presentes, para substituir propriedades.

O arquivo XML de configuração deve ser encontrado na raíz do seu CLASSPATH. Veja um exemplo:


<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <!-- a SessionFactory instance listed as /jndi/name -->
    <session-factory
        name="java:hibernate/SessionFactory">

        <!-- properties -->
        <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">false</property>
        <property name="transaction.factory_class">
            org.hibernate.transaction.JTATransactionFactory
        </property>
        <property name="jta.UserTransaction">java:comp/UserTransaction</property>

        <!-- mapping files -->
        <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
        <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>

        <!-- cache settings -->
        <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
        <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
        <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>

    </session-factory>

</hibernate-configuration>

Como você pode ver, a vantagem deste enfoque é a externalização dos nomes dos arquivos de mapeamento para configuração. O hibernate.cfg.xml também é mais conveniente caso você tenha que ajustar o cache do Hibernate. Note que a escolha é sua em usar hibernate.properties ou hibernate.cfg.xml, ambos são equivalentes, exceto os acima mencionados de usar a sintaxe de XML.

Com a configuração do XML, iniciar o Hibernate é então tão simples quanto:

SessionFactory sf = new Configuration().configure().buildSessionFactory();

Você poderá escolher um arquivo de configuração XML diferente, utilizando:

SessionFactory sf = new Configuration()

    .configure("catdb.cfg.xml")
    .buildSessionFactory();

O Hibernate tem os seguintes pontos da integração para a infraestrutura de J2EE:

Dependendo do seu ambiente, você pode ter que ajustar a opção de configuração hibernate.connection.aggressive_release para verdadeiro ( true ), se seu servidor de aplicações lançar exeções "retenção de conexão".

A API Hibernate Session é independente de qualquer sistema de demarcação de transação em sua arquitetura. Se você deixar o Hibernate usar a JDBC diretamente, através de um pool de conexões, você pode inicializar e encerrar suas transações chamando a API JDBC. Se você rodar em um servidor de aplicações J2EE, você poderá usar transações controladas por beans e chamar a API JTA e UserTransaction quando necessário.

Para manter seu código portável entre estes dois (e outros) ambientes, recomendamos a API Hibernate Transaction, que envolve e esconde o sistema subjacente. Você tem que especificar uma classe construtora para instâncias Transaction ajustando a propriedade de configuração do hibernate.transaction.factory_class.

Existem três escolhas, ou internas, padrões:

Você também pode definir suas próprias estratégias de transação (para um serviço de transação CORBA, por exemplo).

Algumas características no Hibernate (ex., o cache de segundo nível, sessões contextuais com JTA, etc.) requerem acesso a JTA TransactionManager em um ambiente controlado. Em um servidor de aplicação você tem que especificar como o Hibernate pode obter uma referência para a TransactionManager, pois o J2EE não padroniza um mecanismo simples:


Uma SessionFactory de Hibernate vinculada à JNDI pode simplificar a localização da fábrica e a criação de novas Sessions. Observe que isto não está relacionado a um Datasource ligado a JNDI, simplesmente ambos usam o mesmo registro.

Se você desejar ter uma SessionFactory limitada a um nome de espaço de JNDI, especifique um nome (ex.: java:hibernate/SessionFactory) usando a propriedade hibernate.session_factory_name. Se esta propriedade for omitida, a SessionFactory não será limitada ao JNDI. Isto é muito útil em ambientes com uma implementação padrão JNDI de somente leitura (ex.: Tomcat).

Ao vincular a SessionFactory ao JNDI, o Hibernate irá utilizar os valores de hibernate.jndi.url, hibernate.jndi.class para instanciar um contexto inicial. Se eles não forem especificados, será usado o padrão InitialContext.

O Hibernate colocará automaticamente a SessionFactory no JNDI depois que você chamar a cfg.buildSessionFactory(). Isto significa que você terá esta chamada em pelo menos algum código de inicialização (ou classe de utilidade) em seu aplicativo, a não ser que você use a implementação JMX com o HibernateService (discutido mais tarde).

Se você usar um JNDI SessionFactory, o EJB ou qualquer outra classe obterá a SessionFactory utilizando um localizador JNDI.

It is recommended that you bind the SessionFactory to JNDI in a managed environment and use a static singleton otherwise. To shield your application code from these details, we also recommend to hide the actual lookup code for a SessionFactory in a helper class, such as HibernateUtil.getSessionFactory(). Note that such a class is also a convenient way to startup Hibernate—see chapter 1.

The easiest way to handle Sessions and transactions is Hibernate's automatic "current" Session management. For a discussion of contextual sessions see Seção 2.3, “Sessões Contextuais”. Using the "jta" session context, if there is no Hibernate Session associated with the current JTA transaction, one will be started and associated with that JTA transaction the first time you call sessionFactory.getCurrentSession(). The Sessions retrieved via getCurrentSession() in the "jta" context are set to automatically flush before the transaction completes, close after the transaction completes, and aggressively release JDBC connections after each statement. This allows the Sessions to be managed by the life cycle of the JTA transaction to which it is associated, keeping user code clean of such management concerns. Your code can either use JTA programmatically through UserTransaction, or (recommended for portable code) use the Hibernate Transaction API to set transaction boundaries. If you run in an EJB container, declarative transaction demarcation with CMT is preferred.

A linha cfg.buildSessionFactory() ainda precisa ser executada em algum local para conseguir uma SessionFactory em JNDI. Você pode escolher fazer isto em um bloqueio de inicializador static, como aquele em HibernateUtil, ou implementar o Hibernate como serviço gerenciado.

O Hibernate é distribuído com o org.hibernate.jmx.HibernateService para implementação em um servidor de aplicativo com capacidades JMX, tal como o JBoss AS. A implementação atual e configuração é comercial. Segue aqui um exemplo do jboss-service.xml para o JBoss 4.0.x:


<?xml version="1.0"?>
<server>

<mbean code="org.hibernate.jmx.HibernateService"
    name="jboss.jca:service=HibernateFactory,name=HibernateFactory">

    <!-- Required services -->
    <depends>jboss.jca:service=RARDeployer</depends>
    <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>

    <!-- Bind the Hibernate service to JNDI -->
    <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>

    <!-- Datasource settings -->
    <attribute name="Datasource">java:HsqlDS</attribute>
    <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>

    <!-- Transaction integration -->
    <attribute name="TransactionStrategy">
        org.hibernate.transaction.JTATransactionFactory</attribute>
    <attribute name="TransactionManagerLookupStrategy">
        org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
    <attribute name="FlushBeforeCompletionEnabled">true</attribute>
    <attribute name="AutoCloseSessionEnabled">true</attribute>

    <!-- Fetching options -->
    <attribute name="MaximumFetchDepth">5</attribute>

    <!-- Second-level caching -->
    <attribute name="SecondLevelCacheEnabled">true</attribute>
    <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
    <attribute name="QueryCacheEnabled">true</attribute>

    <!-- Logging -->
    <attribute name="ShowSqlEnabled">true</attribute>

    <!-- Mapping files -->
    <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>

</mbean>

</server>

Este arquivo é implementado em um diretório chamado META-INF e envolto em um arquivo JAR com a extensão .sar (arquivo de serviço). Você também pode precisar envolver o Hibernate, suas bibliotecas de terceiros solicitadas, suas classes persistentes compiladas, assim como seus arquivos de mapeamento no mesmo arquivo. Seus beans de empresa (geralmente beans de sessão) podem ser mantidos em seus próprios arquivos JAR, mas você poderá incluir estes arquivos EJB JAR no arquivo de serviço principal para conseguir uma única unidade de (hot)-deployable. Consulte a documentação do JBoss AS para maiores informações sobre o serviço JMX e implementação EJB.

Persistent classes are classes in an application that implement the entities of the business problem (e.g. Customer and Order in an E-commerce application). The term "persistent" here means that the classes are able to be persisted, not that they are in the persistent state (see Seção 11.1, “Estado dos objetos no Hibernate” for discussion).

Hibernate works best if these classes follow some simple rules, also known as the Plain Old Java Object (POJO) programming model. However, none of these rules are hard requirements. Indeed, Hibernate assumes very little about the nature of your persistent objects. You can express a domain model in other ways (using trees of java.util.Map instances, for example).

Exemplo 4.1. Simple POJO representing a cat

package eg;

import java.util.Set;
import java.util.Date;
public class Cat {
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
    private int litterId;
    private Cat mother;
    private Set kittens = new HashSet();
    private void setId(Long id) {
        this.id=id;
    }
    public Long getId() {
        return id;
    }
    void setBirthdate(Date date) {
        birthdate = date;
    }
    public Date getBirthdate() {
        return birthdate;
    }
    void setWeight(float weight) {
        this.weight = weight;
    }
    public float getWeight() {
        return weight;
    }
    public Color getColor() {
        return color;
    }
    void setColor(Color color) {
        this.color = color;
    }
    void setSex(char sex) {
        this.sex=sex;
    }
    public char getSex() {
        return sex;
    }
    void setLitterId(int id) {
        this.litterId = id;
    }
    public int getLitterId() {
        return litterId;
    }
    void setMother(Cat mother) {
        this.mother = mother;
    }
    public Cat getMother() {
        return mother;
    }
    void setKittens(Set kittens) {
        this.kittens = kittens;
    }
    public Set getKittens() {
        return kittens;
    }
    // addKitten not needed by Hibernate
    public void addKitten(Cat kitten) {
        kitten.setMother(this);
    kitten.setLitterId( kittens.size() );
        kittens.add(kitten);
    }
}

As quatro regras principais das classes persistentes são descritas em maiores detalhes nas seguintes seções.

Cat has a property named id. This property maps to the primary key column(s) of the underlying database table. The type of the identifier property can be any "basic" type (see ???). See Seção 9.4, “Componentes como identificadores compostos” for information on mapping composite (multi-column) identifiers.

Nota

Identifiers do not necessarily need to identify column(s) in the database physically defined as a primary key. They should just identify columns that can be used to uniquely identify rows in the underlying table.

Recomendamos que você declare propriedades de identificador nomeados de forma consistente nas classes persistentes e que você use um tipo anulável (ou seja, não primitivo).

A central feature of Hibernate, proxies (lazy loading), depends upon the persistent class being either non-final, or the implementation of an interface that declares all public methods. You can persist final classes that do not implement an interface with Hibernate; you will not, however, be able to use proxies for lazy association fetching which will ultimately limit your options for performance tuning. To persist a final class which does not implement a "full" interface you must disable proxy generation. See Exemplo 4.2, “Disabling proxies in hbm.xml” and Exemplo 4.3, “Disabling proxies in annotations”.



If the final class does implement a proper interface, you could alternatively tell Hibernate to use the interface instead when generating the proxies. See Exemplo 4.4, “Proxying an interface in hbm.xml” and Exemplo 4.5, “Proxying an interface in annotations”.



You should also avoid declaring public final methods as this will again limit the ability to generate proxies from this class. If you want to use a class with public final methods, you must explicitly disable proxying. Again, see Exemplo 4.2, “Disabling proxies in hbm.xml” and Exemplo 4.3, “Disabling proxies in annotations”.

Você precisa substituir os métodos equals() e hashCode() se você:

O Hibernate garante a equivalência de identidades persistentes (linha de base de dados) e identidade Java somente dentro de um certo escopo de sessão. Dessa forma, assim que misturarmos instâncias recuperadas em sessões diferentes, devemos implementar equals() e hashCode() se quisermos ter semânticas significativas para os Sets.

A forma mais óbvia é implementar equals()/hashCode() comparando o valor do identificador de ambos objetos. Caso o valor seja o mesmo, ambos devem ter a mesma linha de base de dados, assim eles serão iguais (se ambos forem adicionados a um Set, nós só teremos um elemento no Set). Infelizmente, não podemos usar esta abordagem com os identificadores gerados. O Hibernate atribuirá somente os valores de identificadores aos objetos que forem persistentes, uma instância recentemente criada não terá nenhum valor de identificador. Além disso, se uma instância não for salva e estiver em um Set, salvá-la atribuirá um valor de identificador ao objeto. Se equals() e hashCode() fossem baseados em um valor identificador, o código hash teria mudado, quebrando o contrato do Set. Consulte o website do Hibernate para acessar uma discussão completa sobre este problema. Note que esta não é uma edição do Hibernate, e sim semânticas naturais do Java de igualdade e identidade.

Recomendamos implementar equals() e hashCode() usando Business key equality. A chave de negócios significa que o método equals() compara somente a propriedade que formar uma chave de negócios, uma chave que identificaria nossa instância na realidade (uma chave de candidato natural):

public class Cat {


    ...
    public boolean equals(Object other) {
        if (this == other) return true;
        if ( !(other instanceof Cat) ) return false;
        final Cat cat = (Cat) other;
        if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
        if ( !cat.getMother().equals( getMother() ) ) return false;
        return true;
    }
    public int hashCode() {
        int result;
        result = getMother().hashCode();
        result = 29 * result + getLitterId();
        return result;
    }
}

A business key does not have to be as solid as a database primary key candidate (see Seção 13.1.3, “Considerando a identidade do objeto”). Immutable or unique properties are usually good candidates for a business key.

Entidades persistentes não precisam ser representadas como classes POJO ou como objetos JavaBeans em tempo de espera. O Hibernate também suporta modelos dinâmicos (usando Maps de Maps em tempo de execução) e a representação de entidades como árvores DOM4J. Com esta abordagem, você não escreve classes persistes, somente arquivos de mapeamentos.

By default, Hibernate works in normal POJO mode. You can set a default entity representation mode for a particular SessionFactory using the default_entity_mode configuration option (see Tabela 3.3, “Propriedades de Configuração do Hibernate”).

Os seguintes exemplos demonstram a representação usando Maps. Primeiro, no arquivo de mapeamento, um entity-name precisa ser declarado ao invés de (ou além de) um nome de classe:


<hibernate-mapping>

    <class entity-name="Customer">

        <id name="id"
            type="long"
            column="ID">
            <generator class="sequence"/>
        </id>

        <property name="name"
            column="NAME"
            type="string"/>

        <property name="address"
            column="ADDRESS"
            type="string"/>

        <many-to-one name="organization"
            column="ORGANIZATION_ID"
            class="Organization"/>

        <bag name="orders"
            inverse="true"
            lazy="false"
            cascade="all">
            <key column="CUSTOMER_ID"/>
            <one-to-many class="Order"/>
        </bag>

    </class>
    
</hibernate-mapping>

Note que embora as associações sejam declaradas utilizando nomes de classe, o tipo alvo de uma associação pode também ser uma entidade dinâmica, ao invés de um POJO.

Após ajustar o modo de entidade padrão para dynamic-map para a SessionFactory, você poderá trabalhar com Maps de Maps no período de execução:

Session s = openSession();

Transaction tx = s.beginTransaction();
// Create a customer
Map david = new HashMap();
david.put("name", "David");
// Create an organization
Map foobar = new HashMap();
foobar.put("name", "Foobar Inc.");
// Link both
david.put("organization", foobar);
// Save both
s.save("Customer", david);
s.save("Organization", foobar);
tx.commit();
s.close();

As vantagens de um mapeamento dinâmico são o tempo de retorno rápido para realizar o protótipo sem a necessidade de implementar uma classe de entidade. No entanto, você perde o tipo de tempo de compilação, verificando e muito provavelmente terá que lidar com muitas exceções de tempo de espera. Graças ao mapeamento do Hibernate, o esquema do banco de dados pode ser facilmente normalizado e seguro, permitindo adicionar uma implementação modelo de domínio apropriado na camada do topo num futuro próximo.

Modos de representação de entidade podem ser também ajustados para base por Session:

Session dynamicSession = pojoSession.getSession(EntityMode.MAP);


// Create a customer
Map david = new HashMap();
david.put("name", "David");
dynamicSession.save("Customer", david);
...
dynamicSession.flush();
dynamicSession.close()
...
// Continue on pojoSession

Por favor, note que a chamada para a getSession() usando um EntityMode está na API de Session e não na SessionFactory. Dessa forma, a nova Session compartilha a conexão, transação e outra informação de contexto JDBC adjacente. Isto significa que você não precisará chamar flush() e close() na Session secundária, e também deixar a transação e o manuseio da conexão para a unidade primária do trabalho.

More information about the XML representation capabilities can be found in Capítulo 20, Mapeamento XML.

org.hibernate.tuple.Tuplizer and its sub-interfaces are responsible for managing a particular representation of a piece of data given that representation's org.hibernate.EntityMode. If a given piece of data is thought of as a data structure, then a tuplizer is the thing that knows how to create such a data structure, how to extract values from such a data structure and how to inject values into such a data structure. For example, for the POJO entity mode, the corresponding tuplizer knows how create the POJO through its constructor. It also knows how to access the POJO properties using the defined property accessors.

There are two (high-level) types of Tuplizers:

Users can also plug in their own tuplizers. Perhaps you require that java.util.Map implementation other than java.util.HashMap be used while in the dynamic-map entity-mode. Or perhaps you need to define a different proxy generation strategy than the one used by default. Both would be achieved by defining a custom tuplizer implementation. Tuplizer definitions are attached to the entity or component mapping they are meant to manage. Going back to the example of our Customer entity, Exemplo 4.6, “Specify custom tuplizers in annotations” shows how to specify a custom org.hibernate.tuple.entity.EntityTuplizer using annotations while Exemplo 4.7, “Specify custom tuplizers in hbm.xml” shows how to do the same in hbm.xml



org.hibernate.EntityNameResolver is a contract for resolving the entity name of a given entity instance. The interface defines a single method resolveEntityName which is passed the entity instance and is expected to return the appropriate entity name (null is allowed and would indicate that the resolver does not know how to resolve the entity name of the given entity instance). Generally speaking, an org.hibernate.EntityNameResolver is going to be most useful in the case of dynamic models. One example might be using proxied interfaces as your domain model. The hibernate test suite has an example of this exact style of usage under the org.hibernate.test.dynamicentity.tuplizer2. Here is some of the code from that package for illustration.

/**

 * A very trivial JDK Proxy InvocationHandler implementation where we proxy an
 * interface as the domain model and simply store persistent state in an internal
 * Map.  This is an extremely trivial example meant only for illustration.
 */
public final class DataProxyHandler implements InvocationHandler {
        private String entityName;
        private HashMap data = new HashMap();
        public DataProxyHandler(String entityName, Serializable id) {
                this.entityName = entityName;
                data.put( "Id", id );
        }
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                if ( methodName.startsWith( "set" ) ) {
                        String propertyName = methodName.substring( 3 );
                        data.put( propertyName, args[0] );
                }
                else if ( methodName.startsWith( "get" ) ) {
                        String propertyName = methodName.substring( 3 );
                        return data.get( propertyName );
                }
                else if ( "toString".equals( methodName ) ) {
                        return entityName + "#" + data.get( "Id" );
                }
                else if ( "hashCode".equals( methodName ) ) {
                        return new Integer( this.hashCode() );
                }
                return null;
        }
        public String getEntityName() {
                return entityName;
        }
        public HashMap getData() {
                return data;
        }
}
public class ProxyHelper {
    public static String extractEntityName(Object object) {
        // Our custom java.lang.reflect.Proxy instances actually bundle
        // their appropriate entity name, so we simply extract it from there
        // if this represents one of our proxies; otherwise, we return null
        if ( Proxy.isProxyClass( object.getClass() ) ) {
            InvocationHandler handler = Proxy.getInvocationHandler( object );
            if ( DataProxyHandler.class.isAssignableFrom( handler.getClass() ) ) {
                DataProxyHandler myHandler = ( DataProxyHandler ) handler;
                return myHandler.getEntityName();
            }
        }
        return null;
    }
    // various other utility methods ....
}
/**
 * The EntityNameResolver implementation.
 *
 * IMPL NOTE : An EntityNameResolver really defines a strategy for how entity names
 * should be resolved.  Since this particular impl can handle resolution for all of our
 * entities we want to take advantage of the fact that SessionFactoryImpl keeps these
 * in a Set so that we only ever have one instance registered.  Why?  Well, when it
 * comes time to resolve an entity name, Hibernate must iterate over all the registered
 * resolvers.  So keeping that number down helps that process be as speedy as possible.
 * Hence the equals and hashCode implementations as is
 */
public class MyEntityNameResolver implements EntityNameResolver {
    public static final MyEntityNameResolver INSTANCE = new MyEntityNameResolver();
    public String resolveEntityName(Object entity) {
        return ProxyHelper.extractEntityName( entity );
    }
    public boolean equals(Object obj) {
        return getClass().equals( obj.getClass() );
    }
    public int hashCode() {
        return getClass().hashCode();
    }
}
public class MyEntityTuplizer extends PojoEntityTuplizer {
        public MyEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
                super( entityMetamodel, mappedEntity );
        }
        public EntityNameResolver[] getEntityNameResolvers() {
                return new EntityNameResolver[] { MyEntityNameResolver.INSTANCE };
        }
    public String determineConcreteSubclassEntityName(Object entityInstance, SessionFactoryImplementor factory) {
        String entityName = ProxyHelper.extractEntityName( entityInstance );
        if ( entityName == null ) {
            entityName = super.determineConcreteSubclassEntityName( entityInstance, factory );
        }
        return entityName;
    }
    ...

Com o objetivo de registrar um org.hibernate.EntityNameResolver, os usuários devem tanto:

  1. Implement a custom tuplizer (see Seção 4.5, “Tuplizadores”), implementing the getEntityNameResolvers method

  2. Registrá-lo com o org.hibernate.impl.SessionFactoryImpl (que é a classe de implementação para org.hibernate.SessionFactory) usando o método registerEntityNameResolver.

Object/relational mappings can be defined in three approaches:

Annotations are split in two categories, the logical mapping annotations (describing the object model, the association between two entities etc.) and the physical mapping annotations (describing the physical schema, tables, columns, indexes, etc). We will mix annotations from both categories in the following code examples.

JPA annotations are in the javax.persistence.* package. Hibernate specific extensions are in org.hibernate.annotations.*. You favorite IDE can auto-complete annotations and their attributes for you (even without a specific "JPA" plugin, since JPA annotations are plain Java 5 annotations).

Here is an example of mapping

package eg;


@Entity 
@Table(name="cats") @Inheritance(strategy=SINGLE_TABLE)
@DiscriminatorValue("C") @DiscriminatorColumn(name="subclass", discriminatorType=CHAR)
public class Cat {
   
   @Id @GeneratedValue
   public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;
   public BigDecimal getWeight() { return weight; }
   public void setWeight(BigDecimal weight) { this.weight = weight; }
   private BigDecimal weight;
   @Temporal(DATE) @NotNull @Column(updatable=false)
   public Date getBirthdate() { return birthdate; }
   public void setBirthdate(Date birthdate) { this.birthdate = birthdate; }
   private Date birthdate;
   @org.hibernate.annotations.Type(type="eg.types.ColorUserType")
   @NotNull @Column(updatable=false)
   public ColorType getColor() { return color; }
   public void setColor(ColorType color) { this.color = color; }
   private ColorType color;
   @NotNull @Column(updatable=false)
   public String getSex() { return sex; }
   public void setSex(String sex) { this.sex = sex; }
   private String sex;
   @NotNull @Column(updatable=false)
   public Integer getLitterId() { return litterId; }
   public void setLitterId(Integer litterId) { this.litterId = litterId; }
   private Integer litterId;
   @ManyToOne @JoinColumn(name="mother_id", updatable=false)
   public Cat getMother() { return mother; }
   public void setMother(Cat mother) { this.mother = mother; }
   private Cat mother;
   @OneToMany(mappedBy="mother") @OrderBy("litterId")
   public Set<Cat> getKittens() { return kittens; }
   public void setKittens(Set<Cat> kittens) { this.kittens = kittens; }
   private Set<Cat> kittens = new HashSet<Cat>();
}
@Entity @DiscriminatorValue("D")
public class DomesticCat extends Cat {
   public String getName() { return name; }
   public void setName(String name) { this.name = name }
   private String name;
}
@Entity
public class Dog { ... }

The legacy hbm.xml approach uses an XML schema designed to be readable and hand-editable. The mapping language is Java-centric, meaning that mappings are constructed around persistent class declarations and not table declarations.

Note que, embora muitos usuários do Hibernate escolham gravar o XML manualmente, existem diversas ferramentas para gerar o documento de mapeamento, incluindo o XDoclet Middlegen e AndroMDA.

Vamos iniciar com um exemplo de mapeamento:


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
      "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="eg">

        <class name="Cat"
            table="cats"
            discriminator-value="C">

                <id name="id">
                        <generator class="native"/>
                </id>

                <discriminator column="subclass"
                     type="character"/>

                <property name="weight"/>

                <property name="birthdate"
                    type="date"
                    not-null="true"
                    update="false"/>

                <property name="color"
                    type="eg.types.ColorUserType"
                    not-null="true"
                    update="false"/>

                <property name="sex"
                    not-null="true"
                    update="false"/>

                <property name="litterId"
                    column="litterId"
                    update="false"/>

                <many-to-one name="mother"
                    column="mother_id"
                    update="false"/>

                <set name="kittens"
                    inverse="true"
                    order-by="litter_id">
                        <key column="mother_id"/>
                        <one-to-many class="Cat"/>
                </set>

                <subclass name="DomesticCat"
                    discriminator-value="D">

                        <property name="name"
                            type="string"/>

                </subclass>

        </class>

        <class name="Dog">
                <!-- mapping for Dog could go here -->
        </class>

</hibernate-mapping>

We will now discuss the concepts of the mapping documents (both annotations and XML). We will only describe, however, the document elements and attributes that are used by Hibernate at runtime. The mapping document also contains some extra optional attributes and elements that affect the database schemas exported by the schema export tool (for example, the not-null attribute).

An entity is a regular Java object (aka POJO) which will be persisted by Hibernate.

To mark an object as an entity in annotations, use the @Entity annotation.

@Entity

public class Flight implements Serializable {
    Long id;
    @Id
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
}         

That's pretty much it, the rest is optional. There are however any options to tweak your entity mapping, let's explore them.

@Table lets you define the table the entity will be persisted into. If undefined, the table name is the unqualified class name of the entity. You can also optionally define the catalog, the schema as well as unique constraints on the table.

@Entity

@Table(name="TBL_FLIGHT", 
       schema="AIR_COMMAND", 
       uniqueConstraints=
           @UniqueConstraint(
               name="flight_number", 
               columnNames={"comp_prefix", "flight_number"} ) )
public class Flight implements Serializable {
    @Column(name="comp_prefix")
    public String getCompagnyPrefix() { return companyPrefix; }
    @Column(name="flight_number")
    public String getNumber() { return number; }
}

The constraint name is optional (generated if left undefined). The column names composing the constraint correspond to the column names as defined before the Hibernate NamingStrategy is applied.

@Entity.name lets you define the shortcut name of the entity you can used in JP-QL and HQL queries. It defaults to the unqualified class name of the class.

Hibernate goes beyond the JPA specification and provide additional configurations. Some of them are hosted on @org.hibernate.annotations.Entity:

Some entities are not mutable. They cannot be updated or deleted by the application. This allows Hibernate to make some minor performance optimizations.. Use the @Immutable annotation.

You can also alter how Hibernate deals with lazy initialization for this class. On @Proxy, use lazy=false to disable lazy fetching (not recommended). You can also specify an interface to use for lazy initializing proxies (defaults to the class itself): use proxyClass on @Proxy. Hibernate will initially return proxies (Javassist or CGLIB) that implement the named interface. The persistent object will load when a method of the proxy is invoked. See "Initializing collections and proxies" below.

@BatchSize specifies a "batch size" for fetching instances of this class by identifier. Not yet loaded instances are loaded batch-size at a time (default 1).

You can specific an arbitrary SQL WHERE condition to be used when retrieving objects of this class. Use @Where for that.

In the same vein, @Check lets you define an SQL expression used to generate a multi-row check constraint for automatic schema generation.

There is no difference between a view and a base table for a Hibernate mapping. This is transparent at the database level, although some DBMS do not support views properly, especially with updates. Sometimes you want to use a view, but you cannot create one in the database (i.e. with a legacy schema). In this case, you can map an immutable and read-only entity to a given SQL subselect expression using @org.hibernate.annotations.Subselect:

@Entity

@Subselect("select item.name, max(bid.amount), count(*) "
        + "from item "
        + "join bid on bid.item_id = item.id "
        + "group by item.name")
@Synchronize( {"item", "bid"} ) //tables impacted
public class Summary {
    @Id
    public String getId() { return id; }
    ...
}

Declare as tabelas para sincronizar com esta entidade, garantindo que a auto-liberação ocorra corretamente, e que as consultas para esta entidade derivada não retornem dados desatualizados. O <subselect> está disponível tanto como um atributo como um elemento mapeado aninhado.

We will now explore the same options using the hbm.xml structure. You can declare a persistent class using the class element. For example:

<class
        name="(1)ClassName"
        table=(2)"tableName"
        discri(3)minator-value="discriminator_value"
        mutabl(4)e="true|false"
        schema(5)="owner"
        catalo(6)g="catalog"
        proxy=(7)"ProxyInterface"
        dynami(8)c-update="true|false"
        dynami(9)c-insert="true|false"
        select(10)-before-update="true|false"
        polymo(11)rphism="implicit|explicit"
        where=(12)"arbitrary sql where condition"
        persis(13)ter="PersisterClass"
        batch-(14)size="N"
        optimi(15)stic-lock="none|version|dirty|all"
        lazy="(16)true|false"
        entity(17)-name="EntityName"
        check=(18)"arbitrary sql check condition"
        rowid=(19)"rowid"
        subsel(20)ect="SQL expression"
        abstra(21)ct="true|false"
        node="element-name"
/>

1

name (opcional): O nome da classe Java inteiramente qualificado da classe persistente (ou interface). Se a função é ausente, assume-se que o mapeamento é para entidades não-POJO.

2

table (opcional – padrão para nomes de classes não qualificadas): O nome da sua tabela do banco de dados.

3

discriminator-value (opcional – padrão para o nome da classe): Um valor que distingue subclasses individuais, usadas para o comportamento polimórfico. Valores aceitos incluem null e not null.

4

mutable (opcional - valor padrão true): Especifica quais instâncias da classe são (ou não) mutáveis.

5

schema (opcional): Sobrepõe o nome do esquema especificado pelo elemento raíz <hibernate-mapping>.

6

catalog (opcional): Sobrepõe o nome do catálogo especificado pelo elemento raíz <hibernate-mapping>.

7

proxy (opcional): Especifica uma interface para ser utilizada pelos proxies de inicialização lazy. Você pode especificar o nome da própria classe.

8

dynamic-update (opcional, valor padrão false): Especifica que o SQL de UPDATE deve ser gerado em tempo de execução e conter apenas aquelas colunas cujos valores foram alterados.

9

dynamic-insert (opcional, valor padrão falso): Especifica que o SQL de INSERT deve ser gerado em tempo de execução e conter apenas aquelas colunas cujos valores não estão nulos.

10

select-before-update (opcional, valor padrão false): Especifica que o Hibernate nunca deve executar um SQL de UPDATE a não ser que seja certo que um objeto está atualmente modificado. Em certos casos (na verdade, apenas quando um objeto transiente foi associado a uma nova sessão utilizando update()), isto significa que o Hibernate irá executar uma instrução SQL de SELECT adicional para determinar se um UPDATE é necessário nesse momento.

11

polymorphisms (optional - defaults to implicit): determines whether implicit or explicit query polymorphisms is used.

12

where (opicional): Especifica um comando SQL WHERE arbitrário para ser usado quando da recuperação de objetos desta classe.

13

persister (opcional): Especifica uma ClassPersister customizada.

14

batch-size (opcional, valor padrão 1) Especifica um "tamanho de lote" para a recuperação de instâncias desta classe pela identificação.

15

optimistic-lock (opcional, valor padrão version): Determina a estratégia de bloqueio.

(16)

lazy (opcional): A recuperação lazy pode ser completamente desabilitada, ajustando lazy="false".

(17)

entity-name (optional - defaults to the class name): Hibernate3 allows a class to be mapped multiple times, potentially to different tables. It also allows entity mappings that are represented by Maps or XML at the Java level. In these cases, you should provide an explicit arbitrary name for the entity. See Seção 4.4, “Modelos dinâmicos” and Capítulo 20, Mapeamento XML for more information.

(18)

check (opcional): Uma expressão SQL utilizada para gerar uma restrição de verificação de múltiplas linhas para a geração automática do esquema.

(19)

rowid (opcional): O Hibernate poder usar as então chamadas ROWIDs em bancos de dados que a suportam. Por exemplo, no Oracle, o Hibernate pode utilizar a coluna extra rowid para atualizações mais rápidas se você configurar esta opção para rowid. Um ROWID é uma implementação que representa de maneira detalhada a localização física de uma determinada tuple armazenada.

(20)

subselect (opcional): Mapeia uma entidade imutável e somente de leitura para um subconjunto do banco de dados. Útil se você quiser ter uma visão, ao invés de uma tabela. Veja abaixo para mais informações.

(21)

abstract (opcional): Utilizada para marcar superclasses abstratas em hierarquias <union-subclass>.

É perfeitamente aceitável uma classe persitente nomeada ser uma interface. Você deverá então declarar as classes implementadas desta interface utilizando o elemento <subclass>. Você pode persistir qualquer classe interna estática. Você deverá especificar o nome da classe usando a forma padrão, por exemplo: eg.Foo$Bar.

Here is how to do a virtual view (subselect) in XML:


<class name="Summary">
    <subselect>
        select item.name, max(bid.amount), count(*)
        from item
        join bid on bid.item_id = item.id
        group by item.name
    </subselect>
    <synchronize table="item"/>
    <synchronize table="bid"/>
    <id name="name"/>
    ...
</class>

The <subselect> is available both as an attribute and a nested mapping element.

Mapped classes must declare the primary key column of the database table. Most classes will also have a JavaBeans-style property holding the unique identifier of an instance.

Mark the identifier property with @Id.

@Entity

public class Person {
   @Id Integer getId() { ... }
   ...
}

In hbm.xml, use the <id> element which defines the mapping from that property to the primary key column.

<id
        name="(1)propertyName"
        type="(2)typename"
        column(3)="column_name"
        unsave(4)d-value="null|any|none|undefined|id_value"
        access(5)="field|property|ClassName">
        node="element-name|@attribute-name|element/@attribute|."

        <generator class="generatorClass"/>
</id>

1

name (opcional): O nome da propriedade do identificador.

2

type (opcional): um nome que indica o tipo de Hibernate.

3

column (opcional – padrão para o nome da propridade): O nome coluna chave primária.

4

unsaved-value (opcional - padrão para um valor "sensível"): O valor da propriedade de identificação que indica que a instância foi novamente instanciada (unsaved), diferenciando de instâncias desconectadas que foram salvas ou carregadas em uma sessão anterior.

5

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

Se a função name não for declarada, considera-se que a classe não tem a propriedade de identificação.

The unsaved-value attribute is almost never needed in Hibernate3 and indeed has no corresponding element in annotations.

You can also declare the identifier as a composite identifier. This allows access to legacy data with composite keys. Its use is strongly discouraged for anything else.

You can define a composite primary key through several syntaxes:

As you can see the last case is far from obvious. It has been inherited from the dark ages of EJB 2 for backward compatibilities and we recommend you not to use it (for simplicity sake).

Let's explore all three cases using examples.

Here is a simple example of @EmbeddedId.

@Entity

class User {
   @EmbeddedId
   @AttributeOverride(name="firstName", column=@Column(name="fld_firstname")
   UserId id;
   Integer age;
}
@Embeddable
class UserId implements Serializable {
   String firstName;
   String lastName;
}

You can notice that the UserId class is serializable. To override the column mapping, use @AttributeOverride.

An embedded id can itself contains the primary key of an associated entity.

@Entity

class Customer {
   @EmbeddedId CustomerId id;
   boolean preferredCustomer;
   @MapsId("userId")
   @JoinColumns({
      @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
      @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
   })
   @OneToOne User user;
}
@Embeddable
class CustomerId implements Serializable {
   UserId userId;
   String customerNumber;
   //implements equals and hashCode
}
@Entity 
class User {
   @EmbeddedId UserId id;
   Integer age;
}
@Embeddable
class UserId implements Serializable {
   String firstName;
   String lastName;
   //implements equals and hashCode
}

In the embedded id object, the association is represented as the identifier of the associated entity. But you can link its value to a regular association in the entity via the @MapsId annotation. The @MapsId value correspond to the property name of the embedded id object containing the associated entity's identifier. In the database, it means that the Customer.user and the CustomerId.userId properties share the same underlying column (user_fk in this case).

In practice, your code only sets the Customer.user property and the user id value is copied by Hibernate into the CustomerId.userId property.

While not supported in JPA, Hibernate lets you place your association directly in the embedded id component (instead of having to use the @MapsId annotation).

@Entity

class Customer {
   @EmbeddedId CustomerId id;
   boolean preferredCustomer;
}
@Embeddable
class CustomerId implements Serializable {
   @OneToOne
   @JoinColumns({
      @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
      @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
   }) 
   User user;
   String customerNumber;
   //implements equals and hashCode
}
@Entity 
class User {
   @EmbeddedId UserId id;
   Integer age;
}
@Embeddable
class UserId implements Serializable {
   String firstName;
   String lastName;
   //implements equals and hashCode
}

Let's now rewrite these examples using the hbm.xml syntax.


<composite-id
        name="propertyName"
        class="ClassName"
        mapped="true|false"
        access="field|property|ClassName"
        node="element-name|.">

        <key-property name="propertyName" type="typename" column="column_name"/>
        <key-many-to-one name="propertyName" class="ClassName" column="column_name"/>
        ......
</composite-id>

First a simple example:


<class name="User">
   <composite-id name="id" class="UserId">
      <key-property name="firstName" column="fld_firstname"/>
      <key-property name="lastName"/>
   </composite-id>
</class>

Then an example showing how an association can be mapped.


<class name="Customer">
   <composite-id name="id" class="CustomerId">
      <key-property name="firstName" column="userfirstname_fk"/>
      <key-property name="lastName" column="userfirstname_fk"/>
      <key-property name="customerNumber"/>
   </composite-id>

   <property name="preferredCustomer"/>

   <many-to-one name="user">
      <column name="userfirstname_fk" updatable="false" insertable="false"/>
      <column name="userlastname_fk" updatable="false" insertable="false"/>
   </many-to-one>
</class>

<class name="User">
   <composite-id name="id" class="UserId">
      <key-property name="firstName"/>
      <key-property name="lastName"/>
   </composite-id>

   <property name="age"/>
</class>

Notice a few things in the previous example:

The last example shows how to map association directly in the embedded id component.


<class name="Customer">
   <composite-id name="id" class="CustomerId">
      <key-many-to-one name="user">
         <column name="userfirstname_fk"/>
         <column name="userlastname_fk"/>
      </key-many-to-one>
      <key-property name="customerNumber"/>
   </composite-id>

   <property name="preferredCustomer"/>
</class>

<class name="User">
   <composite-id name="id" class="UserId">
      <key-property name="firstName"/>
      <key-property name="lastName"/>
   </composite-id>

   <property name="age"/>
</class>

This is the recommended approach to map composite identifier. The following options should not be considered unless some constraint are present.

Another, arguably more natural, approach is to place @Id on multiple properties of your entity. This approach is only supported by Hibernate (not JPA compliant) but does not require an extra embeddable component.

@Entity

class Customer implements Serializable {
   @Id @OneToOne
   @JoinColumns({
      @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
      @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
   })
   User user;
  
   @Id String customerNumber;
   boolean preferredCustomer;
   //implements equals and hashCode
}
@Entity 
class User {
   @EmbeddedId UserId id;
   Integer age;
}
@Embeddable
class UserId implements Serializable {
   String firstName;
   String lastName;
   //implements equals and hashCode
}

In this case Customer is its own identifier representation: it must implement Serializable and must implement equals() and hashCode().

In hbm.xml, the same mapping is:


<class name="Customer">
   <composite-id>
      <key-many-to-one name="user">
         <column name="userfirstname_fk"/>
         <column name="userlastname_fk"/>
      </key-many-to-one>
      <key-property name="customerNumber"/>
   </composite-id>

   <property name="preferredCustomer"/>
</class>

<class name="User">
   <composite-id name="id" class="UserId">
      <key-property name="firstName"/>
      <key-property name="lastName"/>
   </composite-id>

   <property name="age"/>
</class>

@IdClass on an entity points to the class (component) representing the identifier of the class. The properties marked @Id on the entity must have their corresponding property on the @IdClass. The return type of search twin property must be either identical for basic properties or must correspond to the identifier class of the associated entity for an association.

@Entity

@IdClass(CustomerId.class)
class Customer implements Serializable {
   @Id @OneToOne
   @JoinColumns({
      @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
      @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
   }) 
   User user;
  
   @Id String customerNumber;
   boolean preferredCustomer;
}
class CustomerId implements Serializable {
   UserId user;
   String customerNumber;
   //implements equals and hashCode
}
@Entity 
class User {
   @EmbeddedId UserId id;
   Integer age;
   //implements equals and hashCode
}
@Embeddable
class UserId implements Serializable {
   String firstName;
   String lastName;
   //implements equals and hashCode
}

Customer and CustomerId do have the same properties customerNumber as well as user. CustomerId must be Serializable and implement equals() and hashCode().

While not JPA standard, Hibernate let's you declare the vanilla associated property in the @IdClass.

@Entity

@IdClass(CustomerId.class)
class Customer implements Serializable {
   @Id @OneToOne
   @JoinColumns({
      @JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
      @JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
   }) 
   User user;
  
   @Id String customerNumber;
   boolean preferredCustomer;
}
class CustomerId implements Serializable {
   @OneToOne User user;
   String customerNumber;
   //implements equals and hashCode
}
@Entity 
class User {
   @EmbeddedId UserId id;
   Integer age;
   //implements equals and hashCode
}
@Embeddable
class UserId implements Serializable {
  String firstName;
  String lastName;
}

This feature is of limited interest though as you are likely to have chosen the @IdClass approach to stay JPA compliant or you have a quite twisted mind.

Here are the equivalent on hbm.xml files:


<class name="Customer">
   <composite-id class="CustomerId" mapped="true">
      <key-many-to-one name="user">
         <column name="userfirstname_fk"/>
         <column name="userlastname_fk"/>
      </key-many-to-one>
      <key-property name="customerNumber"/>
   </composite-id>

   <property name="preferredCustomer"/>
</class>

<class name="User">
   <composite-id name="id" class="UserId">
      <key-property name="firstName"/>
      <key-property name="lastName"/>
   </composite-id>

   <property name="age"/>
</class>

Hibernate can generate and populate identifier values for you automatically. This is the recommended approach over "business" or "natural" id (especially composite ids).

Hibernate offers various generation strategies, let's explore the most common ones first that happens to be standardized by JPA:

To mark an id property as generated, use the @GeneratedValue annotation. You can specify the strategy used (default to AUTO) by setting strategy.

@Entity

public class Customer {
   @Id @GeneratedValue
   Integer getId() { ... };
}
@Entity 
public class Invoice {
   @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
   Integer getId() { ... };
}

SEQUENCE and TABLE require additional configurations that you can set using @SequenceGenerator and @TableGenerator:

  • name: name of the generator

  • table / sequenceName: name of the table or the sequence (defaulting respectively to hibernate_sequences and hibernate_sequence)

  • catalog / schema:

  • initialValue: the value from which the id is to start generating

  • allocationSize: the amount to increment by when allocating id numbers from the generator

In addition, the TABLE strategy also let you customize:

  • pkColumnName: the column name containing the entity identifier

  • valueColumnName: the column name containing the identifier value

  • pkColumnValue: the entity identifier

  • uniqueConstraints: any potential column constraint on the table containing the ids

To link a table or sequence generator definition with an actual generated property, use the same name in both the definition name and the generator value generator as shown below.

@Id 

@GeneratedValue(
    strategy=GenerationType.SEQUENCE, 
    generator="SEQ_GEN")
@javax.persistence.SequenceGenerator(
    name="SEQ_GEN",
    sequenceName="my_sequence",
    allocationSize=20
)
public Integer getId() { ... }        

The scope of a generator definition can be the application or the class. Class-defined generators are not visible outside the class and can override application level generators. Application level generators are defined in JPA's XML deployment descriptors (see XXXXXX ???):

<table-generator name="EMP_GEN"

            table="GENERATOR_TABLE"
            pk-column-name="key"
            value-column-name="hi"
            pk-column-value="EMP"
            allocation-size="20"/>
//and the annotation equivalent
@javax.persistence.TableGenerator(
    name="EMP_GEN",
    table="GENERATOR_TABLE",
    pkColumnName = "key",
    valueColumnName = "hi"
    pkColumnValue="EMP",
    allocationSize=20
)
<sequence-generator name="SEQ_GEN" 
    sequence-name="my_sequence"
    allocation-size="20"/>
//and the annotation equivalent
@javax.persistence.SequenceGenerator(
    name="SEQ_GEN",
    sequenceName="my_sequence",
    allocationSize=20
)
         

If a JPA XML descriptor (like META-INF/orm.xml) is used to define the generators, EMP_GEN and SEQ_GEN are application level generators.

Nota

Package level definition is not supported by the JPA specification. However, you can use the @GenericGenerator at the package level (see ???).

These are the four standard JPA generators. Hibernate goes beyond that and provide additional generators or additional options as we will see below. You can also write your own custom identifier generator by implementing org.hibernate.id.IdentifierGenerator.

To define a custom generator, use the @GenericGenerator annotation (and its plural counter part @GenericGenerators) that describes the class of the identifier generator or its short cut name (as described below) and a list of key/value parameters. When using @GenericGenerator and assigning it via @GeneratedValue.generator, the @GeneratedValue.strategy is ignored: leave it blank.

@Id @GeneratedValue(generator="system-uuid")

@GenericGenerator(name="system-uuid", strategy = "uuid")
public String getId() {
@Id @GeneratedValue(generator="trigger-generated")
@GenericGenerator(
    name="trigger-generated", 
    strategy = "select",
    parameters = @Parameter(name="key", value = "socialSecurityNumber")
)
public String getId() {

The hbm.xml approach uses the optional <generator> child element inside <id>. If any parameters are required to configure or initialize the generator instance, they are passed using the <param> element.


<id name="id" type="long" column="cat_id">
        <generator class="org.hibernate.id.TableHiLoGenerator">
                <param name="table">uid_table</param>
                <param name="column">next_hi_value_column</param>
        </generator>
</id>

Todos os geradores implementam a interface org.hibernate.id.IdentifierGenerator. Esta é uma interface bem simples. Algumas aplicações podem prover suas próprias implementações especializadas, entretanto, o Hibernate disponibiliza um conjunto de implementações internamente. Há nomes de atalhos para estes geradores internos, conforme segue abaixo:

increment

gera identificadores dos tipos long, short ou int que são únicos apenas quando nenhum outro processo está inserindo dados na mesma tabela. Não utilize em ambientes de cluster.

identity

suporta colunas de identidade em DB2, MySQL, Servidor MS SQL, Sybase e HypersonicSQL. O identificador retornado é do tipo long, short ou int.

sequence

utiliza uma seqüência em DB2, PostgreSQL, Oracle, SAP DB, McKoi ou um gerador no Interbase. O identificador de retorno é do tipo long, short ou int.

hilo

utiliza um algoritmo hi/lo para gerar de forma eficiente identificadores do tipo long, short ou int, a partir de uma tabela e coluna fornecida (por padrão hibernate_unique_key e next_hi) como fonte para os valores hi. O algoritmo hi/lo gera identificadores que são únicos apenas para um banco de dados específico.

seqhilo

utiliza um algoritmo hi/lo para gerar de forma eficiente identificadores do tipo long, short ou int, a partir de uma seqüência de banco de dados fornecida.

uuid

Generates a 128-bit UUID based on a custom algorithm. The value generated is represented as a string of 32 hexidecimal digits. Users can also configure it to use a separator (config parameter "separator") which separates the hexidecimal digits into 8{sep}8{sep}4{sep}8{sep}4. Note specifically that this is different than the IETF RFC 4122 representation of 8-4-4-4-12. If you need RFC 4122 compliant UUIDs, consider using "uuid2" generator discussed below.

uuid2

Generates a IETF RFC 4122 compliant (variant 2) 128-bit UUID. The exact "version" (the RFC term) generated depends on the pluggable "generation strategy" used (see below). Capable of generating values as java.util.UUID, java.lang.String or as a byte array of length 16 (byte[16]). The "generation strategy" is defined by the interface org.hibernate.id.UUIDGenerationStrategy. The generator defines 2 configuration parameters for defining which generation strategy to use:

Out of the box, comes with the following strategies:

guid

utiliza um string GUID gerado pelo banco de dados no Servidor MS SQL e MySQL.

native

seleciona entre identity, sequenceou hilo dependendo das capacidades do banco de dados utilizado.

assigned

deixa a aplicação definir um identificador para o objeto antes que o save() seja chamado. Esta é a estratégia padrão caso nenhum elemento <generator> seja especificado.

select

retorna a chave primária recuperada por um trigger do banco de dados, selecionando uma linha pela chave única e recuperando o valor da chave primária.

foreign

utiliza o identificador de um outro objeto associado. Normalmente utilizado em conjunto com uma associação de chave primária do tipo <one-to-one>.

sequence-identity

uma estratégia de geração de seqüência especializada que use uma seqüência de banco de dados para a geração de valor atual, mas combina isto com JDBC3 getGeneratedKeys para de fato retornar o valor do identificador gerado como parte da execução de instrução de inserção. Esta estratégia é somente conhecida para suportar drivers da Oracle 10g, focados em JDK 1.4. Note que os comentários sobre estas instruções de inserção estão desabilitados devido a um bug nos drivers da Oracle.

Iniciando com a liberação 3.2.3, existem dois novos geradores que representam uma reavaliação de dois diferentes aspectos da geração identificadora. O primeiro aspecto é a portabilidade do banco de dados, o segundo é a otimização. A otimização significa que você não precisa questionar o banco de dados a cada solicitação para um novo valor de identificador. Estes dois geradores possuem por intenção substituir alguns dos geradores nomeados acima, começando em 3.3.x. No entanto, eles estão incluídos nas liberações atuais e podem ser referenciados pelo FQN.

A primeira destas novas gerações é a org.hibernate.id.enhanced.SequenceStyleGenerator que primeiramente é uma substituição para o gerador sequence e, segundo, um melhor gerador de portabilidade que o native. Isto é devido ao native normalmente escolher entre identity e sequence, que são semânticas extremamente diferentes das quais podem causar problemas súbitos em portabilidade de observação de aplicativos. No entanto, o org.hibernate.id.enhanced.SequenceStyleGenerator atinge a portabilidade numa maneira diferente. Ele escolhe entre uma tabela ou uma seqüência no banco de dados para armazenar seus valores de incrementação, dependendo nas capacidades do dialeto sendo usado. A diferença entre isto e o native é que o armazenamento baseado na tabela e seqüência possuem exatamente a mesma semântica. Na realidade, as seqüências são exatamente o que o Hibernate tenta imitar com os próprios geradores baseados na tabela. Este gerador possui um número de parâmetros de configuração:

O segundo destes novos geradores é o org.hibernate.id.enhanced.TableGenerator, que primeiramente é uma substituição para o gerador table, mesmo que isto funcione muito mais como um org.hibernate.id.MultipleHiLoPerTableGenerator, e segundo, como uma reimplementação do org.hibernate.id.MultipleHiLoPerTableGenerator que utiliza a noção dos otimizadores pugláveis. Basicamente, este gerador define uma tabela capacitada de manter um número de valores de incremento simultâneo pelo uso múltiplo de filas de chaves distintas. Este gerador possui um número de parâmetros de configuração.

  • table_name (opcional - padrão para hibernate_sequences): O nome da tabela a ser usado.

  • value_column_name (opcional - padrão para next_val): o nome da coluna na tabela que é usado para manter o valor.

  • segment_column_name (opcional - padrão para sequence_name) O nome da coluna da tabela que é usado para manter a "chave de segmento". Este é o valor que identifica qual valor de incremento a ser usado.

  • base (opcional - padrão para default) O valor da "chave de segmento" para o segmento pelo qual nós queremos obter os valores de incremento para este gerador.

  • segment_value_length (opcional - padrão para 255): Usado para a geração do esquema. O tamanho da coluna para criar esta coluna de chave de segmento.

  • initial_value (opcional - valor padrão para 1): O valor inicial a ser restaurado a partir da tabela.

  • increment_size (opcional - padrão para 1): O valor pelo qual as chamadas subseqüentes para a tabela devem diferir-se.

  • optimizer (optional - defaults to ??): See Seção 5.1.2.3.1, “Otimização do Gerador de Identificação”.

For identifier generators that store values in the database, it is inefficient for them to hit the database on each and every call to generate a new identifier value. Instead, you can group a bunch of them in memory and only hit the database when you have exhausted your in-memory value group. This is the role of the pluggable optimizers. Currently only the two enhanced generators (Seção 5.1.2.3, “Aprimoração dos geradores de identificador” support this operation.

  • none (geralmente este é o padrão, caso nenhum otimizador for especificado): isto não executará quaisquer otimizações e alcançará o banco de dados para cada e toda solicitação.

  • hilo: aplica-se ao algoritmo em volta dos valores restaurados do banco de dados. Espera-se que os valores a partir do banco de dados para este otimizador sejam seqüenciais. Os valores restaurados a partir da estrutura do banco de dados para este otimizador indica um "número de grupo". O increment_size é multiplicado pelo valor em memória para definir um grupo "hi value".

  • pooled: assim como o caso do hilo, este otimizador tenta minimizar o número de tentativas no banco de dados. No entanto, nós simplesmente implementamos o valor de inicialização para o "próximo grupo" na estrutura do banco de dados ao invés do valor seqüencial na combinação com um algoritmo de agrupamento em memória. Neste caso, o increment_size refere-se aos valores de entrada a partir do banco de dados.

When using long transactions or conversations that span several database transactions, it is useful to store versioning data to ensure that if the same entity is updated by two conversations, the last to commit changes will be informed and not override the other conversation's work. It guarantees some isolation while still allowing for good scalability and works particularly well in read-often write-sometimes situations.

You can use two approaches: a dedicated version number or a timestamp.

A versão ou timestamp de uma propriedade nunca deve ser nula para uma instância desconectada, assim o Hibernate irá identificar qualquer instância com uma versão nula ou timestamp como transiente, não importando qual outra estratégia unsaved-value tenha sido especificada. A declaração de uma versão nula ou a propriedade timestamp é um caminho fácil para tratar problemas com reconexões transitivas no Hibernate, especialmente úteis para pessoas utilizando identificadores atribuídos ou chaves compostas.

You can add optimistic locking capability to an entity using the @Version annotation:

@Entity

public class Flight implements Serializable {
...
    @Version
    @Column(name="OPTLOCK")
    public Integer getVersion() { ... }
}           

The version property will be mapped to the OPTLOCK column, and the entity manager will use it to detect conflicting updates (preventing lost updates you might otherwise see with the last-commit-wins strategy).

The version column may be a numeric. Hibernate supports any kind of type provided that you define and implement the appropriate UserVersionType.

The application must not alter the version number set up by Hibernate in any way. To artificially increase the version number, check in Hibernate Entity Manager's reference documentation LockModeType.OPTIMISTIC_FORCE_INCREMENT or LockModeType.PESSIMISTIC_FORCE_INCREMENT.

If the version number is generated by the database (via a trigger for example), make sure to use @org.hibernate.annotations.Generated(GenerationTime.ALWAYS).

To declare a version property in hbm.xml, use:

<version
        column(1)="version_column"
        name="(2)propertyName"
        type="(3)typename"
        access(4)="field|property|ClassName"
        unsave(5)d-value="null|negative|undefined"
        genera(6)ted="never|always"
        insert(7)="true|false"
        node="element-name|@attribute-name|element/@attribute|."
/>

1

column (opcional - tem como padrão o nome da propriedade name): O nome da coluna mantendo o número da versão.

2

name: O nome da propriedade da classe persistente.

3

type (opcional - padrão para integer): O tipo do número da versão.

4

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

5

unsaved-value (opcional – valor padrão para undefined ): Um valor para a propriedade versão que indica que uma instância foi instanciada recentemente (unsaved), distinguindo de instâncias desconectadas que foram salvas ou carregadas em sessões anteriores. (undefined especifica que o valor da propriedade de identificação deve ser utilizado).

6

generated (opcional - valor padrão never): Especifica que este valor de propriedade da versão é na verdade gerado pelo banco de dados. Veja o generated properties para maiores informações.

7

insert (opcional - padrão para true): Especifica se a coluna de versão deve ser incluída na instrução de inserção do SQL. Pode ser configurado como false se a coluna do banco de dados estiver definida com um valor padrão de 0.

Alternatively, you can use a timestamp. Timestamps are a less safe implementation of optimistic locking. However, sometimes an application might use the timestamps in other ways as well.

Simply mark a property of type Date or Calendar as @Version.

@Entity

public class Flight implements Serializable {
...
    @Version
    public Date getLastUpdate() { ... }
}           

When using timestamp versioning you can tell Hibernate where to retrieve the timestamp value from - database or JVM - by optionally adding the @org.hibernate.annotations.Source annotation to the property. Possible values for the value attribute of the annotation are org.hibernate.annotations.SourceType.VM and org.hibernate.annotations.SourceType.DB. The default is SourceType.DB which is also used in case there is no @Source annotation at all.

Like in the case of version numbers, the timestamp can also be generated by the database instead of Hibernate. To do that, use @org.hibernate.annotations.Generated(GenerationTime.ALWAYS).

In hbm.xml, use the <timestamp> element:

<timestamp
        column(1)="timestamp_column"
        name="(2)propertyName"
        access(3)="field|property|ClassName"
        unsave(4)d-value="null|undefined"
        source(5)="vm|db"
        genera(6)ted="never|always"
        node="element-name|@attribute-name|element/@attribute|."
/>

1

column (opcional - padrão para o nome da propriedade): O nome da coluna que mantém o timestamp.

2

name: O nome da propriedade no estilo JavaBeans do tipo Date ou Timestamp da classe persistente.

3

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

4

unsaved-value (opcional - padrão para null): Um valor de propriedade da versão que indica que uma instância foi recentemente instanciada (unsaved), distinguindo-a de instâncias desconectadas que foram salvas ou carregadas em sessões prévias. Undefined especifica que um valor de propriedade de identificação deve ser utilizado.

5

source (opcional - padrão para vm): De onde o Hibernate deve recuperar o valor timestamp? Do banco de dados ou da JVM atual? Timestamps baseados em banco de dados levam a um overhead porque o Hibernate precisa acessar o banco de dados para determinar o "próximo valor", mas é mais seguro para uso em ambientes de cluster. Observe também, que nem todos os Dialects suportam a recuperação do carimbo de data e hora atual do banco de dados, enquanto outros podem não ser seguros para utilização em bloqueios, pela falta de precisão (Oracle 8, por exemplo).

6

generated (opcional - padrão para never): Especifica que o valor da propriedade timestamp é gerado pelo banco de dados. Veja a discussão do generated properties para maiores informações.

You need to decide which property needs to be made persistent in a given entity. This differs slightly between the annotation driven metadata and the hbm.xml files.

In the annotations world, every non static non transient property (field or method depending on the access type) of an entity is considered persistent, unless you annotate it as @Transient. Not having an annotation for your property is equivalent to the appropriate @Basic annotation.

The @Basic annotation allows you to declare the fetching strategy for a property. If set to LAZY, specifies that this property should be fetched lazily when the instance variable is first accessed. It requires build-time bytecode instrumentation, if your classes are not instrumented, property level lazy loading is silently ignored. The default is EAGER. You can also mark a property as not optional thanks to the @Basic.optional attribute. This will ensure that the underlying column are not nullable (if possible). Note that a better approach is to use the @NotNull annotation of the Bean Validation specification.

Let's look at a few examples:

public transient int counter; //transient property


private String firstname; //persistent property
@Transient
String getLengthInMeter() { ... } //transient property
String getName() {... } // persistent property
@Basic
int getLength() { ... } // persistent property
@Basic(fetch = FetchType.LAZY)
String getDetailedComment() { ... } // persistent property
@Temporal(TemporalType.TIME)
java.util.Date getDepartureTime() { ... } // persistent property           
@Enumerated(EnumType.STRING)
Starred getNote() { ... } //enum persisted as String in database

counter, a transient field, and lengthInMeter, a method annotated as @Transient, and will be ignored by the Hibernate. name, length, and firstname properties are mapped persistent and eagerly fetched (the default for simple properties). The detailedComment property value will be lazily fetched from the database once a lazy property of the entity is accessed for the first time. Usually you don't need to lazy simple properties (not to be confused with lazy association fetching). The recommended alternative is to use the projection capability of JP-QL (Java Persistence Query Language) or Criteria queries.

JPA support property mapping of all basic types supported by Hibernate (all basic Java types , their respective wrappers and serializable classes). Hibernate Annotations supports out of the box enum type mapping either into a ordinal column (saving the enum ordinal) or a string based column (saving the enum string representation): the persistence representation, defaulted to ordinal, can be overridden through the @Enumerated annotation as shown in the note property example.

In plain Java APIs, the temporal precision of time is not defined. When dealing with temporal data you might want to describe the expected precision in database. Temporal data can have DATE, TIME, or TIMESTAMP precision (ie the actual date, only the time, or both). Use the @Temporal annotation to fine tune that.

@Lob indicates that the property should be persisted in a Blob or a Clob depending on the property type: java.sql.Clob, Character[], char[] and java.lang.String will be persisted in a Clob. java.sql.Blob, Byte[], byte[] and Serializable type will be persisted in a Blob.

@Lob

public String getFullText() {
    return fullText;
}
@Lob
public byte[] getFullCode() {
    return fullCode;
}

If the property type implements java.io.Serializable and is not a basic type, and if the property is not annotated with @Lob, then the Hibernate serializable type is used.

You can also manually specify a type using the @org.hibernate.annotations.Type and some parameters if needed. @Type.type could be:

If you do not specify a type, Hibernate will use reflection upon the named property and guess the correct Hibernate type. Hibernate will attempt to interpret the name of the return class of the property getter using, in order, rules 2, 3, and 4.

@org.hibernate.annotations.TypeDef and @org.hibernate.annotations.TypeDefs allows you to declare type definitions. These annotations can be placed at the class or package level. Note that these definitions are global for the session factory (even when defined at the class level). If the type is used on a single entity, you can place the definition on the entity itself. Otherwise, it is recommended to place the definition at the package level. In the example below, when Hibernate encounters a property of class PhoneNumer, it delegates the persistence strategy to the custom mapping type PhoneNumberType. However, properties belonging to other classes, too, can delegate their persistence strategy to PhoneNumberType, by explicitly using the @Type annotation.

@TypeDef(

   name = "phoneNumber",
   defaultForType = PhoneNumber.class,
   typeClass = PhoneNumberType.class
)
@Entity
public class ContactDetails {
   [...]
   private PhoneNumber localPhoneNumber;
   @Type(type="phoneNumber")
   private OverseasPhoneNumber overseasPhoneNumber;
   [...]
}

The following example shows the usage of the parameters attribute to customize the TypeDef.

//in org/hibernate/test/annotations/entity/package-info.java

@TypeDefs(
    {
    @TypeDef(
        name="caster",
        typeClass = CasterStringType.class,
        parameters = {
            @Parameter(name="cast", value="lower")
        }
    )
    }
)
package org.hibernate.test.annotations.entity;
//in org/hibernate/test/annotations/entity/Forest.java
public class Forest {
    @Type(type="caster")
    public String getSmallText() {
    ...
}      

When using composite user type, you will have to express column definitions. The @Columns has been introduced for that purpose.

@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")

@Columns(columns = {
    @Column(name="r_amount"),
    @Column(name="r_currency")
})
public MonetaryAmount getAmount() {
    return amount;
}
public class MonetaryAmount implements Serializable {
    private BigDecimal amount;
    private Currency currency;
    ...
}

By default the access type of a class hierarchy is defined by the position of the @Id or @EmbeddedId annotations. If these annotations are on a field, then only fields are considered for persistence and the state is accessed via the field. If there annotations are on a getter, then only the getters are considered for persistence and the state is accessed via the getter/setter. That works well in practice and is the recommended approach.

However in some situations, you need to:

The best use case is an embeddable class used by several entities that might not use the same access type. In this case it is better to force the access type at the embeddable class level.

To force the access type on a given class, use the @Access annotation as showed below:

@Entity

public class Order {
   @Id private Long id;
   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }
   @Embedded private Address address;
   public Address getAddress() { return address; }
   public void setAddress() { this.address = address; }
}
@Entity
public class User {
   private Long id;
   @Id public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }
   private Address address;
   @Embedded public Address getAddress() { return address; }
   public void setAddress() { this.address = address; }
}
@Embeddable
@Access(AcessType.PROPERTY)
public class Address {
   private String street1;
   public String getStreet1() { return street1; }
   public void setStreet1() { this.street1 = street1; }
   private hashCode; //not persistent
}

You can also override the access type of a single property while keeping the other properties standard.

@Entity

public class Order {
   @Id private Long id;
   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }
   @Transient private String userId;
   @Transient private String orderId;
   @Access(AccessType.PROPERTY)
   public String getOrderNumber() { return userId + ":" + orderId; }
   public void setOrderNumber() { this.userId = ...; this.orderId = ...; }
}

In this example, the default access type is FIELD except for the orderNumber property. Note that the corresponding field, if any must be marked as @Transient or transient.

The column(s) used for a property mapping can be defined using the @Column annotation. Use it to override default values (see the JPA specification for more information on the defaults). You can use this annotation at the property level for properties that are:

@Entity

public class Flight implements Serializable {
...
@Column(updatable = false, name = "flight_name", nullable = false, length=50)
public String getName() { ... }
            

The name property is mapped to the flight_name column, which is not nullable, has a length of 50 and is not updatable (making the property immutable).

This annotation can be applied to regular properties as well as @Id or @Version properties.

@Column(
    name="colu(1)mnName";
    boolean un(2)ique() default false;
    boolean nu(3)llable() default true;
    boolean in(4)sertable() default true;
    boolean up(5)datable() default true;
    String col(6)umnDefinition() default "";
    String tab(7)le() default "";
    int length(8)() default 255;
    int precis(9)ion() default 0; // decimal precision
    int scale((10)) default 0; // decimal scale

1

name (optional): the column name (default to the property name)

2

unique (optional): set a unique constraint on this column or not (default false)

3

nullable (optional): set the column as nullable (default true).

4

insertable (optional): whether or not the column will be part of the insert statement (default true)

5

updatable (optional): whether or not the column will be part of the update statement (default true)

6

columnDefinition (optional): override the sql DDL fragment for this particular column (non portable)

7

table (optional): define the targeted table (default primary table)

8

length (optional): column length (default 255)

8

precision (optional): column decimal precision (default 0)

10

scale (optional): column decimal scale if useful (default 0)

O elemento <property> declara uma propriedade de estilo JavaBean de uma classe.

<property
        name="(1)propertyName"
        column(2)="column_name"
        type="(3)typename"
        update(4)="true|false"
        insert(4)="true|false"
        formul(5)a="arbitrary SQL expression"
        access(6)="field|property|ClassName"
        lazy="(7)true|false"
        unique(8)="true|false"
        not-nu(9)ll="true|false"
        optimi(10)stic-lock="true|false"
        genera(11)ted="never|insert|always"
        node="element-name|@attribute-name|element/@attribute|."
        index="index_name"
        unique_key="unique_key_id"
        length="L"
        precision="P"
        scale="S"
/>

1

name: o nome da propriedade, iniciando com letra minúscula.

2

column (opcional - padrão para o nome da propriedade): O nome da coluna mapeada do banco de dados. Isto pode também ser especificado pelo(s) elemento(s) <column> aninhados.

3

type (opcional): um nome que indica o tipo de Hibernate.

4

update, insert (opcional - padrão para true): especifica que as colunas mapeadas devem ser incluídas nas instruções SQL de UPDATE e/ou INSERT. Ajustar ambas para false permite uma propridade "derivada" pura, cujo valor é inicializado de outra propriedade, que mapeie a mesma coluna(s) ou por uma disparo ou outra aplicação.

5

formula (opcional): uma instrução SQL que definie o valor para uma propriedade calculada. Propriedades calculadas não possuem uma coluna de mapeamento para elas.

6

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

7

lazy (opcional - padrão para false): Especifica que esta propriedade deve ser atingida de forma lenta quando a instância da variável é acessada pela primeira vez. Isto requer instrumentação bytecode em tempo de criação.

8

unique (opcional): Habilita a geração de DDL de uma única restrição para as colunas. Da mesma forma, permita que isto seja o alvo de uma property-ref.

9

not-null (opcional): Habilita a geração de DDL de uma restrição de nulidade para as colunas.

10

optimistic-lock (opcional - padrão para true): Especifica se mudanças para esta propriedade requerem ou não bloqueio otimista. Em outras palavras, determina se um incremento de versão deve ocorrer quando esta propriedade está suja.

11

generated (opcional - padrão para never): Especifica que o valor da propriedade é na verdade gerado pelo banco de dados. Veja a discussão do generated properties para maiores informações.

typename pode ser:

Se você não especificar um tipo, o Hibernate irá utilizar reflexão sobre a propriedade nomeada para ter uma idéia do tipo de Hibernate correto. O Hibernate tentará interpretar o nome da classe retornada, usando as regras 2, 3 e 4 nesta ordem. Em certos casos, você ainda precisará do atributo type. Por exemplo, para distinguir entre Hibernate.DATE e Hibernate.TIMESTAMP, ou para especificar um tipo customizado.

A função access permite que você controle como o Hibernate irá acessar a propriedade em tempo de execução. Por padrão, o Hibernate irá chamar os métodos get/set da propriedades. Se você especificar access="field", o Hibernate irá bipassar os metodos get/set, acessando o campo diretamente, usando reflexão. Você pode especificar sua própria estratégia para acesso da propriedade criando uma classe que implemente a interface org.hibernate.property.PropertyAccessor.

Um recurso especialmente poderoso é o de propriedades derivadas. Estas propriedades são por definição somente leitura, e o valor da propriedade é calculado em tempo de execução. Você declara este cálculo como uma expressão SQL, que traduz para cláusula SELECT de uma subconsulta da consulta SQL que carrega a instância:


<property name="totalPrice"
    formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
                WHERE li.productId = p.productId
                AND li.customerId = customerId
                AND li.orderNumber = orderNumber )"/>

Observe que você pode referenciar as entidades da própria tabela, através da não declaração de um alias para uma coluna particular. Isto seria o customerId no exemplo dado. Observe também que você pode usar o mapeamento de elemento aninhado <formula>, se você não gostar de usar o atributo.

Embeddable objects (or components) are objects whose properties are mapped to the same table as the owning entity's table. Components can, in turn, declare their own properties, components or collections

It is possible to declare an embedded component inside an entity and even override its column mapping. Component classes have to be annotated at the class level with the @Embeddable annotation. It is possible to override the column mapping of an embedded object for a particular entity using the @Embedded and @AttributeOverride annotation in the associated property:

@Entity

public class Person implements Serializable {
    // Persistent component using defaults
    Address homeAddress;
    @Embedded
    @AttributeOverrides( {
            @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
            @AttributeOverride(name="name", column = @Column(name="bornCountryName") )
    } )
    Country bornIn;
    ...
}          
@Embeddable

public class Address implements Serializable {
    String city;
    Country nationality; //no overriding here
}            
@Embeddable

public class Country implements Serializable {
    private String iso2;
    @Column(name="countryName") private String name;
    public String getIso2() { return iso2; }
    public void setIso2(String iso2) { this.iso2 = iso2; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    ...
}            

An embeddable object inherits the access type of its owning entity (note that you can override that using the @Access annotation).

The Person entity has two component properties, homeAddress and bornIn. homeAddress property has not been annotated, but Hibernate will guess that it is a persistent component by looking for the @Embeddable annotation in the Address class. We also override the mapping of a column name (to bornCountryName) with the @Embedded and @AttributeOverride annotations for each mapped attribute of Country. As you can see, Country is also a nested component of Address, again using auto-detection by Hibernate and JPA defaults. Overriding columns of embedded objects of embedded objects is through dotted expressions.

@Embedded

    @AttributeOverrides( {
            @AttributeOverride(name="city", column = @Column(name="fld_city") ),
            @AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),
            @AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )
            //nationality columns in homeAddress are overridden
    } )
    Address homeAddress;

Hibernate Annotations supports something that is not explicitly supported by the JPA specification. You can annotate a embedded object with the @MappedSuperclass annotation to make the superclass properties persistent (see @MappedSuperclass for more informations).

You can also use association annotations in an embeddable object (ie @OneToOne, @ManyToOne, @OneToMany or @ManyToMany). To override the association columns you can use @AssociationOverride.

If you want to have the same embeddable object type twice in the same entity, the column name defaulting will not work as several embedded objects would share the same set of columns. In plain JPA, you need to override at least one set of columns. Hibernate, however, allows you to enhance the default naming mechanism through the NamingStrategy interface. You can write a strategy that prevent name clashing in such a situation. DefaultComponentSafeNamingStrategy is an example of this.

If a property of the embedded object points back to the owning entity, annotate it with the @Parent annotation. Hibernate will make sure this property is properly loaded with the entity reference.

In XML, use the <component> element.

<component
        name="(1)propertyName"
        class=(2)"className"
        insert(3)="true|false"
        update(4)="true|false"
        access(5)="field|property|ClassName"
        lazy="(6)true|false"
        optimi(7)stic-lock="true|false"
        unique(8)="true|false"
        node="element-name|."
>

        <property ...../>
        <many-to-one .... />
        ........
</component>

1

name: O nome da propriedade.

2

class (opcional – padrão para o tipo de propriedade determinada por reflection): O nome da classe (filha) do componente.

3

insert: As colunas mapeadas aparecem nos SQL de INSERTs?

4

update: As colunas mapeadas aparecem nos SQL de UPDATEs?

5

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

6

lazy (opcional - padrão para false): Especifica que este componente deve ter uma busca lazy quando a função for acessada pela primeira vez. Isto requer instrumentação bytecode de tempo de construção.

7

optimistic-lock (opcional – padrão para true): Especifica que atualizações para este componente requerem ou não aquisição de um bloqueio otimista. Em outras palavras, determina se uma versão de incremento deve ocorrer quando esta propriedade estiver suja.

8

unique (opcional – valor padrão false): Especifica que existe uma unique restrição em todas as colunas mapeadas do componente.

A tag filha <property> acrescenta a propriedade de mapeamento da classe filha para colunas de uma tabela.

O elemento <component> permite um sub-elemento <parent> mapeie uma propriedade da classe do componente como uma referencia de volta para a entidade que o contém.

The <dynamic-component> element allows a Map to be mapped as a component, where the property names refer to keys of the map. See Seção 9.5, “Componentes Dinâmicos” for more information. This feature is not supported in annotations.

Java is a language supporting polymorphism: a class can inherit from another. Several strategies are possible to persist a class hierarchy:

With this approach the properties of all the subclasses in a given mapped class hierarchy are stored in a single table.

Each subclass declares its own persistent properties and subclasses. Version and id properties are assumed to be inherited from the root class. Each subclass in a hierarchy must define a unique discriminator value. If this is not specified, the fully qualified Java class name is used.

@Entity

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="planetype",
    discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("Plane")
public class Plane { ... }
@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }          

In hbm.xml, for the table-per-class-hierarchy mapping strategy, the <subclass> declaration is used. For example:

<subclass
        name="(1)ClassName"
        discri(2)minator-value="discriminator_value"
        proxy=(3)"ProxyInterface"
        lazy="(4)true|false"
        dynamic-update="true|false"
        dynamic-insert="true|false"
        entity-name="EntityName"
        node="element-name"
        extends="SuperclassName">

        <property .... />
        .....
</subclass>

1

name: O nome de classe completamente qualificada da subclasse.

2

discriminator-value (opcional – padrão para o nome da classe): Um valor que distingue subclasses individuais.

3

proxy (opcional): Especifica a classe ou interface que usará os proxies de inicialização lazy.

4

lazy (opcional, padrão para true): Configurar lazy="false" desabilitará o uso de inicialização lazy.

For information about inheritance mappings see Capítulo 10, Mapeamento de Herança .

Discriminators are required for polymorphic persistence using the table-per-class-hierarchy mapping strategy. It declares a discriminator column of the table. The discriminator column contains marker values that tell the persistence layer what subclass to instantiate for a particular row. Hibernate Core supports the follwoing restricted set of types as discriminator column: string, character, integer, byte, short, boolean, yes_no, true_false.

Use the @DiscriminatorColumn to define the discriminator column as well as the discriminator type.

You can also use @DiscriminatorFormula to express in SQL a virtual discriminator column. This is particularly useful when the discriminator value can be extracted from one or more columns of the table. Both @DiscriminatorColumn and @DiscriminatorFormula are to be set on the root entity (once per persisted hierarchy).

@org.hibernate.annotations.DiscriminatorOptions allows to optionally specify Hibernate specific discriminator options which are not standardized in JPA. The available options are force and insert. The force attribute is useful if the table contains rows with "extra" discriminator values that are not mapped to a persistent class. This could for example occur when working with a legacy database. If force is set to true Hibernate will specify the allowed discriminator values in the SELECT query, even when retrieving all instances of the root class. The second option - insert - tells Hibernate whether or not to include the discriminator column in SQL INSERTs. Usually the column should be part of the INSERT statement, but if your discriminator column is also part of a mapped composite identifier you have to set this option to false.

Finally, use @DiscriminatorValue on each class of the hierarchy to specify the value stored in the discriminator column for a given entity. If you do not set @DiscriminatorValue on a class, the fully qualified class name is used.

@Entity

@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="planetype",
    discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("Plane")
public class Plane { ... }
@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }          

In hbm.xml, the <discriminator> element is used to define the discriminator column or formula:

<discriminator
        column(1)="discriminator_column"
        type="(2)discriminator_type"
        force=(3)"true|false"
        insert(4)="true|false"
        formul(5)a="arbitrary sql expression"
/>

1

column (opcional - padrão para class): O nome da coluna discriminadora.

2

type (opcional - padrão para string): O nome que indica o tipo Hibernate.

3

force (opcional - valor padrão false): "Força" o Hibernate a especificar valores discriminadores permitidos mesmo quando recuperando todas as instâncias da classe raíz.

4

insert (opcional - valor padrão para true) Ajuste para false se sua coluna discriminadora também fizer parte do identificador composto mapeado. (Isto informa ao Hibernate para não incluir a coluna em comandos SQL INSERTs).

5

formula (opcional): Uma expressão SQL arbitrária que é executada quando um tipo tem que ser avaliado. Permite discriminação baseada em conteúdo.

Valores atuais de uma coluna discriminada são especificados pela função discriminator-value da <class> e elementos da <subclass>.

Usando o atributo formula você pode declarar uma expressão SQL arbitrária que será utilizada para avaliar o tipo de uma linha. Por exemplo:


<discriminator
    formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
    type="integer"/>

Each subclass can also be mapped to its own table. This is called the table-per-subclass mapping strategy. An inherited state is retrieved by joining with the table of the superclass. A discriminator column is not required for this mapping strategy. Each subclass must, however, declare a table column holding the object identifier. The primary key of this table is also a foreign key to the superclass table and described by the @PrimaryKeyJoinColumns or the <key> element.

@Entity @Table(name="CATS")

@Inheritance(strategy=InheritanceType.JOINED)
public class Cat implements Serializable { 
    @Id @GeneratedValue(generator="cat-uuid") 
    @GenericGenerator(name="cat-uuid", strategy="uuid")
    String getId() { return id; }
    ...
}
@Entity @Table(name="DOMESTIC_CATS")
@PrimaryKeyJoinColumn(name="CAT")
public class DomesticCat extends Cat { 
    public String getName() { return name; }
}            

In hbm.xml, use the <joined-subclass> element. For example:

<joined-subclass
        name="(1)ClassName"
        table=(2)"tablename"
        proxy=(3)"ProxyInterface"
        lazy="(4)true|false"
        dynamic-update="true|false"
        dynamic-insert="true|false"
        schema="schema"
        catalog="catalog"
        extends="SuperclassName"
        persister="ClassName"
        subselect="SQL expression"
        entity-name="EntityName"
        node="element-name">

        <key .... >

        <property .... />
        .....
</joined-subclass>

1

name: O nome de classe completamente qualificada da subclasse.

2

table: O nome da tabela da subclasse.

3

proxy (opcional): Especifica a classe ou interface que usará os proxies de inicialização lazy.

4

lazy (opcional, padrão para true): Configurar lazy="false" desabilitará o uso de inicialização lazy.

Use the <key> element to declare the primary key / foreign key column. The mapping at the start of the chapter would then be re-written as:


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="eg">

        <class name="Cat" table="CATS">
                <id name="id" column="uid" type="long">
                        <generator class="hilo"/>
                </id>
                <property name="birthdate" type="date"/>
                <property name="color" not-null="true"/>
                <property name="sex" not-null="true"/>
                <property name="weight"/>
                <many-to-one name="mate"/>
                <set name="kittens">
                        <key column="MOTHER"/>
                        <one-to-many class="Cat"/>
                </set>
                <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
                    <key column="CAT"/>
                    <property name="name" type="string"/>
                </joined-subclass>
        </class>

        <class name="eg.Dog">
                <!-- mapping for Dog could go here -->
        </class>

</hibernate-mapping>

For information about inheritance mappings see Capítulo 10, Mapeamento de Herança .

A third option is to map only the concrete classes of an inheritance hierarchy to tables. This is called the table-per-concrete-class strategy. Each table defines all persistent states of the class, including the inherited state. In Hibernate, it is not necessary to explicitly map such inheritance hierarchies. You can map each class as a separate entity root. However, if you wish use polymorphic associations (e.g. an association to the superclass of your hierarchy), you need to use the union subclass mapping.

@Entity

@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Flight implements Serializable { ... }            

Or in hbm.xml:

<union-subclass
        name="(1)ClassName"
        table=(2)"tablename"
        proxy=(3)"ProxyInterface"
        lazy="(4)true|false"
        dynamic-update="true|false"
        dynamic-insert="true|false"
        schema="schema"
        catalog="catalog"
        extends="SuperclassName"
        abstract="true|false"
        persister="ClassName"
        subselect="SQL expression"
        entity-name="EntityName"
        node="element-name">

        <property .... />
        .....
</union-subclass>

1

name: O nome de classe completamente qualificada da subclasse.

2

table: O nome da tabela da subclasse.

3

proxy (opcional): Especifica a classe ou interface que usará os proxies de inicialização lazy.

4

lazy (opcional, padrão para true): Configurar lazy="false" desabilitará o uso de inicialização lazy.

A coluna discriminatória não é requerida para esta estratégia de mapeamento.

For information about inheritance mappings see Capítulo 10, Mapeamento de Herança .

This is sometimes useful to share common properties through a technical or a business superclass without including it as a regular mapped entity (ie no specific table for this entity). For that purpose you can map them as @MappedSuperclass.

@MappedSuperclass

public class BaseEntity {
    @Basic
    @Temporal(TemporalType.TIMESTAMP)
    public Date getLastUpdate() { ... }
    public String getLastUpdater() { ... }
    ...
}
@Entity class Order extends BaseEntity {
    @Id public Integer getId() { ... }
    ...
}

In database, this hierarchy will be represented as an Order table having the id, lastUpdate and lastUpdater columns. The embedded superclass property mappings are copied into their entity subclasses. Remember that the embeddable superclass is not the root of the hierarchy though.

You can override columns defined in entity superclasses at the root entity level using the @AttributeOverride annotation.

@MappedSuperclass

public class FlyingObject implements Serializable {
    public int getAltitude() {
        return altitude;
    }
    @Transient
    public int getMetricAltitude() {
        return metricAltitude;
    }
    @ManyToOne
    public PropulsionType getPropulsion() {
        return metricAltitude;
    }
    ...
}
@Entity
@AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
@AssociationOverride( 
   name="propulsion", 
   joinColumns = @JoinColumn(name="fld_propulsion_fk") 
)
public class Plane extends FlyingObject {
    ...
}

The altitude property will be persisted in an fld_altitude column of table Plane and the propulsion association will be materialized in a fld_propulsion_fk foreign key column.

You can define @AttributeOverride(s) and @AssociationOverride(s) on @Entity classes, @MappedSuperclass classes and properties pointing to an @Embeddable object.

In hbm.xml, simply map the properties of the superclass in the <class> element of the entity that needs to inherit them.

While not recommended for a fresh schema, some legacy databases force your to map a single entity on several tables.

Using the @SecondaryTable or @SecondaryTables class level annotations. To express that a column is in a particular table, use the table parameter of @Column or @JoinColumn.

@Entity

@Table(name="MainCat")
@SecondaryTables({
    @SecondaryTable(name="Cat1", pkJoinColumns={
        @PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
    ),
    @SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
})
public class Cat implements Serializable {
    private Integer id;
    private String name;
    private String storyPart1;
    private String storyPart2;
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    
    @Column(table="Cat1")
    public String getStoryPart1() {
        return storyPart1;
    }
    @Column(table="Cat2")
    public String getStoryPart2() {
        return storyPart2;
    }
}

In this example, name will be in MainCat. storyPart1 will be in Cat1 and storyPart2 will be in Cat2. Cat1 will be joined to MainCat using the cat_id as a foreign key, and Cat2 using id (ie the same column name, the MainCat id column has). Plus a unique constraint on storyPart2 has been set.

There is also additional tuning accessible via the @org.hibernate.annotations.Table annotation:

Make sure to use the secondary table name in the appliesto property

@Entity

@Table(name="MainCat")
@SecondaryTable(name="Cat1")
@org.hibernate.annotations.Table(
   appliesTo="Cat1",
   fetch=FetchMode.SELECT,
   optional=true)
public class Cat implements Serializable {
    private Integer id;
    private String name;
    private String storyPart1;
    private String storyPart2;
    @Id @GeneratedValue
    public Integer getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    
    @Column(table="Cat1")
    public String getStoryPart1() {
        return storyPart1;
    }
    @Column(table="Cat2")
    public String getStoryPart2() {
        return storyPart2;
    }
}

In hbm.xml, use the <join> element.

<join
        table=(1)"tablename"
        schema(2)="owner"
        catalo(3)g="catalog"
        fetch=(4)"join|select"
        invers(5)e="true|false"
        option(6)al="true|false">

        <key ... />

        <property ... />
        ...
</join>

1

table: O nome da tabela associada.

2

schema (opcional): Sobrepõe o nome do esquema especificado pelo elemento raíz <hibernate-mapping>.

3

catalog (opcional): Sobrepõe o nome do catálogo especificado pelo elemento raíz <hibernate-mapping>.

4

fetch(opcional – valor padrão join): Se ajustado para join, o padrão, o Hibernate irá usar uma união interna para restaurar um join definido por uma classe ou suas subclasses e uma união externa para um join definido por uma subclasse. Se ajustado para select, então o Hibernate irá usar uma seleção seqüencial para um <join> definida numa subclasse, que será emitido apenas se uma linha representar uma instância da subclasse. Uniões internas ainda serão utilizadas para restaurar um <join> definido pela classe e suas superclasses.

5

inverse (opcional – padrão para false): Se habilitado, o Hibernate não tentará inserir ou atualizar as propriedades definidas por esta união.

6

optional (opcional – padrão para false): Se habilitado, o Hibernate irá inserir uma linha apenas se as propriedades, definidas por esta junção, não forem nulas. Isto irá sempre usar uma união externa para recuperar as propriedades.

Por exemplo, a informação de endereço para uma pessoa pode ser mapeada para uma tabela separada, enquanto preservando o valor da semântica de tipos para todas as propriedades:


<class name="Person"
    table="PERSON">

    <id name="id" column="PERSON_ID">...</id>

    <join table="ADDRESS">
        <key column="ADDRESS_ID"/>
        <property name="address"/>
        <property name="zip"/>
        <property name="country"/>
    </join>
    ...

Esta característica é útil apenas para modelos de dados legados. Nós recomendamos menos tabelas do que classes e um modelo de domínio fine-grained. Porém, é útil para ficar trocando entre estratégias de mapeamento de herança numa hierarquia simples, como explicaremos mais a frente.

To link one entity to an other, you need to map the association property as a to one association. In the relational model, you can either use a foreign key or an association table, or (a bit less common) share the same primary key value between the two entities.

To mark an association, use either @ManyToOne or @OnetoOne.

@ManyToOne and @OneToOne have a parameter named targetEntity which describes the target entity name. You usually don't need this parameter since the default value (the type of the property that stores the association) is good in almost all cases. However this is useful when you want to use interfaces as the return type instead of the regular entity.

Setting a value of the cascade attribute to any meaningful value other than nothing will propagate certain operations to the associated object. The meaningful values are divided into three categories.

By default, single point associations are eagerly fetched in JPA 2. You can mark it as lazily fetched by using @ManyToOne(fetch=FetchType.LAZY) in which case Hibernate will proxy the association and load it when the state of the associated entity is reached. You can force Hibernate not to use a proxy by using @LazyToOne(NO_PROXY). In this case, the property is fetched lazily when the instance variable is first accessed. This requires build-time bytecode instrumentation. lazy="false" specifies that the association will always be eagerly fetched.

With the default JPA options, single-ended associations are loaded with a subsequent select if set to LAZY, or a SQL JOIN is used for EAGER associations. You can however adjust the fetching strategy, ie how data is fetched by using @Fetch. FetchMode can be SELECT (a select is triggered when the association needs to be loaded) or JOIN (use a SQL JOIN to load the association while loading the owner entity). JOIN overrides any lazy attribute (an association loaded through a JOIN strategy cannot be lazy).

An ordinary association to another persistent class is declared using a

and a foreign key in one table is referencing the primary key column(s) of the target table.

@Entity

public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
    @JoinColumn(name="COMP_ID")
    public Company getCompany() {
        return company;
    }
    ...
}            

The @JoinColumn attribute is optional, the default value(s) is the concatenation of the name of the relationship in the owner side, _ (underscore), and the name of the primary key column in the owned side. In this example company_id because the property name is company and the column id of Company is id.

@Entity

public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class )
    @JoinColumn(name="COMP_ID")
    public Company getCompany() {
        return company;
    }
    ...
}
public interface Company {
    ...
}

You can also map a to one association through an association table. This association table described by the @JoinTable annotation will contains a foreign key referencing back the entity table (through @JoinTable.joinColumns) and a a foreign key referencing the target entity table (through @JoinTable.inverseJoinColumns).

@Entity

public class Flight implements Serializable {
    @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
    @JoinTable(name="Flight_Company",
        joinColumns = @JoinColumn(name="FLIGHT_ID"),
        inverseJoinColumns = @JoinColumn(name="COMP_ID")
    )
    public Company getCompany() {
        return company;
    }
    ...
}       

You can mark an association as mandatory by using the optional=false attribute. We recommend to use Bean Validation's @NotNull annotation as a better alternative however. As a consequence, the foreign key column(s) will be marked as not nullable (if possible).

When Hibernate cannot resolve the association because the expected associated element is not in database (wrong id on the association column), an exception is raised. This might be inconvenient for legacy and badly maintained schemas. You can ask Hibernate to ignore such elements instead of raising an exception using the @NotFound annotation.


Sometimes you want to delegate to your database the deletion of cascade when a given entity is deleted. In this case Hibernate generates a cascade delete constraint at the database level.


Foreign key constraints, while generated by Hibernate, have a fairly unreadable name. You can override the constraint name using @ForeignKey.


Sometimes, you want to link one entity to an other not by the target entity primary key but by a different unique key. You can achieve that by referencing the unique key column(s) in @JoinColumn.referenceColumnName.

@Entity

class Person {
   @Id Integer personNumber;
   String firstName;
   @Column(name="I")
   String initial;
   String lastName;
}
@Entity
class Home {
   @ManyToOne
   @JoinColumns({
      @JoinColumn(name="first_name", referencedColumnName="firstName"),
      @JoinColumn(name="init", referencedColumnName="I"),
      @JoinColumn(name="last_name", referencedColumnName="lastName"),
   })
   Person owner
}

This is not encouraged however and should be reserved to legacy mappings.

In hbm.xml, mapping an association is similar. The main difference is that a @OneToOne is mapped as <many-to-one unique="true"/>, let's dive into the subject.

<many-to-one
        name="(1)propertyName"
        column(2)="column_name"
        class=(3)"ClassName"
        cascad(4)e="cascade_style"
        fetch=(5)"join|select"
        update(6)="true|false"
        insert(6)="true|false"
        proper(7)ty-ref="propertyNameFromAssociatedClass"
        access(8)="field|property|ClassName"
        unique(9)="true|false"
        not-nu(10)ll="true|false"
        optimi(11)stic-lock="true|false"
        lazy="(12)proxy|no-proxy|false"
        not-fo(13)und="ignore|exception"
        entity(14)-name="EntityName"
        formul(15)a="arbitrary SQL expression"
        node="element-name|@attribute-name|element/@attribute|."
        embed-xml="true|false"
        index="index_name"
        unique_key="unique_key_id"
        foreign-key="foreign_key_name"
/>

1

name: O nome da propriedade.

2

column (opcional): O nome da coluna da chave exterior. Isto pode também ser especificado através de elementos aninhados <column>.

3

class (opcional – padrão para o tipo de propriedade determinado pela reflexão): O nome da classe associada.

4

cascade (opcional): Especifica qual operação deve ser cascateada do objeto pai para o objeto associado.

5

fetch (opcional - padrão para select): Escolhe entre recuperação da união exterior ou recuperação seqüencial de seleção.

6

update, insert (opcional - valor padrão true): especifica que as colunas mapeadas devem ser incluídas em instruções SQL de UPDATE e/ou INSERT. Com o ajuste de ambas para false você permite uma associação "derivada" pura cujos valores são inicializados de algumas outras propriedades que mapeiam a(s) mesma(s) coluna(s) ou por um trigger ou outra aplicação.

7

property-ref: (opcional) O nome de uma propriedade da classe associada que esteja unida à esta chave exterior. Se não for especificada, a chave primária da classe associada será utilizada.

8

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

9

unique (opcional): Habilita a geração DDL de uma restrição única para a coluna da chave exterior. Além disso, permite ser o alvo de uma property-ref. Isso torna a multiplicidade da associação efetivamente um para um.

10

not-null (opcional): Habilita a geração DDL de uma restrição de nulidade para as colunas de chaves exteriores.

11

optimistic-lock (opcional - padrão para true): Especifica se mudanças para esta propriedade requerem ou não bloqueio otimista. Em outras palavras, determina se um incremento de versão deve ocorrer quando esta propriedade está suja.

12

lazy(opcional – padrão para proxy): Por padrão, associações de ponto único são envoltas em um proxie. lazy="no-proxy" especifica que a propriedade deve ser trazida de forma tardia quando a instância da variável é acessada pela primeira vez. Isto requer instrumentação bytecode em tempo de criação. O lazy="false" especifica que a associação será sempre procurada.

13

not-found (opcional - padrão para exception): Especifica como as chaves exteriores que informam que linhas que estejam faltando serão manuseadas. O ignore tratará a linha faltante como uma associação nula.

14

entity-name (opcional): O nome da entidade da classe associada.

15

formula (optional): Uma instrução SQL que define um valor para uma chave exterior computed.

Setting a value of the cascade attribute to any meaningful value other than none will propagate certain operations to the associated object. The meaningful values are divided into three categories. First, basic operations, which include: persist, merge, delete, save-update, evict, replicate, lock and refresh; second, special values: delete-orphan; and third,all comma-separated combinations of operation names: cascade="persist,merge,evict" or cascade="all,delete-orphan". See Seção 11.11, “Persistência Transitiva” for a full explanation. Note that single valued, many-to-one and one-to-one, associations do not support orphan delete.

Segue abaixo uma amostra de uma típica declaração many-to-one:


<many-to-one name="product" class="Product" column="PRODUCT_ID"/>

O atributo property-ref deve apenas ser usado para mapear dados legados onde uma chave exterior se refere à uma chave exclusiva da tabela associada que não seja a chave primária. Este é um modelo relacional desagradável. Por exemplo, suponha que a classe Product tenha um número seqüencial exclusivo, que não seja a chave primária. O atributo unique controla a geração de DDL do Hibernate com a ferramenta SchemaExport.


<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>

Então o mapeamento para OrderItem poderia usar:


<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>

No entanto, isto não é recomendável.

Se a chave exclusiva referenciada engloba múltiplas propriedades da entidade associada, você deve mapear as propriedades referenciadas dentro de um elemento chamado <properties>

Se a chave exclusiva referenciada é a propriedade de um componente, você pode especificar um caminho para a propriedade:


<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>

The second approach is to ensure an entity and its associated entity share the same primary key. In this case the primary key column is also a foreign key and there is no extra column. These associations are always one to one.


Nota

Many people got confused by these primary key based one to one associations. They can only be lazily loaded if Hibernate knows that the other side of the association is always present. To indicate to Hibernate that it is the case, use @OneToOne(optional=false).

In hbm.xml, use the following mapping.

<one-to-one
        name="(1)propertyName"
        class=(2)"ClassName"
        cascad(3)e="cascade_style"
        constr(4)ained="true|false"
        fetch=(5)"join|select"
        proper(6)ty-ref="propertyNameFromAssociatedClass"
        access(7)="field|property|ClassName"
        formul(8)a="any SQL expression"
        lazy="(9)proxy|no-proxy|false"
        entity(10)-name="EntityName"
        node="element-name|@attribute-name|element/@attribute|."
        embed-xml="true|false"
        foreign-key="foreign_key_name"
/>

1

name: O nome da propriedade.

2

class (opcional – padrão para o tipo de propriedade determinado pela reflexão): O nome da classe associada.

3

cascade (opcional): Especifica qual operação deve ser cascateada do objeto pai para o objeto associado.

4

constrained (opcional): Especifica que uma restrição de chave exterior na chave primária da tabela mapeada referencia a tabela da classe associada. Esta opção afeta a ordem em que save() e delete() são cascateadas, e determina se a associação pode sofrer o proxie. Isto também é usado pela ferramenta schema export.

5

fetch (opcional - padrão para select): Escolhe entre recuperação da união exterior ou recuperação seqüencial de seleção.

6

property-ref(opcional): O nome da propriedade da classe associada que é ligada à chave primária desta classe. Se não for especificada, a chave primária da classe associada é utilizada.

7

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

8

formula (opcional): Quase todas associações um-pra-um mapeiam para a chave primária da entidade dona. Caso este não seja o caso, você pode especificar uma outra coluna, colunas ou expressões para unir utilizando uma fórmula SQL. Veja org.hibernate.test.onetooneformula para exemplo.

9

lazy (opcional – valor padrão proxy): Por padrão, as associações de ponto único estão em proxy. lazy="no-proxy" especifica que a propriedade deve ser recuperada de forma preguiçosa quando a variável da instância for acessada pela primeira vez. Isto requer instrumentação de bytecode de tempo de construção. lazy="false" especifica que a associação terá sempre uma busca antecipada (eager fetched). Note que se constrained="false", será impossível efetuar o proxing e o Hibernate irá realizar uma busca antecipada na associação.

10

entity-name (opcional): O nome da entidade da classe associada.

Associações de chave primária não necessitam de uma coluna extra de tabela. Se duas linhas forem relacionadas pela associação, então as duas linhas da tabela dividem o mesmo valor da chave primária. Assim, se você quiser que dois objetos sejam relacionados por uma associação de chave primária, você deve ter certeza que foram atribuídos com o mesmo valor identificador.

Para uma associação de chave primária, adicione os seguintes mapeamentos em Employee e Person, respectivamente:


<one-to-one name="person" class="Person"/>

<one-to-one name="employee" class="Employee" constrained="true"/>

Agora devemos assegurar que as chaves primárias de linhas relacionadas nas tabelas PERSON e EMPLOYEE são iguais. Nós usamos uma estratégia especial de geração de identificador do Hibernate chamada foreign:


<class name="person" table="PERSON">
    <id name="id" column="PERSON_ID">
        <generator class="foreign">
            <param name="property">employee</param>
        </generator>
    </id>
    ...
    <one-to-one name="employee"
        class="Employee"
        constrained="true"/>
</class>

Uma nova instância de Person é atribuída com o mesmo valor da chave primária da instância de Employee referenciada com a propriedade employee daquela Person.

Although we recommend the use of surrogate keys as primary keys, you should try to identify natural keys for all entities. A natural key is a property or combination of properties that is unique and non-null. It is also immutable. Map the properties of the natural key as @NaturalId or map them inside the <natural-id> element. Hibernate will generate the necessary unique key and nullability constraints and, as a result, your mapping will be more self-documenting.

@Entity

public class Citizen {
    @Id
    @GeneratedValue
    private Integer id;
    private String firstname;
    private String lastname;
    
    @NaturalId
    @ManyToOne
    private State state;
    @NaturalId
    private String ssn;
    ...
}
//and later on query
List results = s.createCriteria( Citizen.class )
                .add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", ste ) )
                .list();

Or in XML,


<natural-id mutable="true|false"/>
        <property ... />
        <many-to-one ... />
        ......
</natural-id>

Nós recomendamos com ênfase que você implemente equals() e hashCode() para comparar as propriedades da chave natural da entidade.

Este mapeamento não pretende ser utilizado com entidades com chaves naturais primárias.

There is one more type of property mapping. The @Any mapping defines a polymorphic association to classes from multiple tables. This type of mapping requires more than one column. The first column contains the type of the associated entity. The remaining columns contain the identifier. It is impossible to specify a foreign key constraint for this kind of association. This is not the usual way of mapping polymorphic associations and you should use this only in special cases. For example, for audit logs, user session data, etc.

The @Any annotation describes the column holding the metadata information. To link the value of the metadata information and an actual entity type, The @AnyDef and @AnyDefs annotations are used. The metaType attribute allows the application to specify a custom type that maps database column values to persistent classes that have identifier properties of the type specified by idType. You must specify the mapping from values of the metaType to class names.

@Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )

@AnyMetaDef( 
    idType = "integer", 
    metaType = "string", 
    metaValues = {
        @MetaValue( value = "S", targetEntity = StringProperty.class ),
        @MetaValue( value = "I", targetEntity = IntegerProperty.class )
    } )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
    return mainProperty;
}

Note that @AnyDef can be mutualized and reused. It is recommended to place it as a package metadata in this case.

//on a package

@AnyMetaDef( name="property" 
    idType = "integer", 
    metaType = "string", 
    metaValues = {
        @MetaValue( value = "S", targetEntity = StringProperty.class ),
        @MetaValue( value = "I", targetEntity = IntegerProperty.class )
    } )
package org.hibernate.test.annotations.any;
//in a class
    @Any( metaDef="property", metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
    @JoinColumn( name = "property_id" )
    public Property getMainProperty() {
        return mainProperty;
    }

The hbm.xml equivalent is:


<any name="being" id-type="long" meta-type="string">
    <meta-value value="TBL_ANIMAL" class="Animal"/>
    <meta-value value="TBL_HUMAN" class="Human"/>
    <meta-value value="TBL_ALIEN" class="Alien"/>
    <column name="table_name"/>
    <column name="id"/>
</any>
<any
        name="(1)propertyName"
        id-typ(2)e="idtypename"
        meta-t(3)ype="metatypename"
        cascad(4)e="cascade_style"
        access(5)="field|property|ClassName"
        optimi(6)stic-lock="true|false"
>
        <meta-value ... />
        <meta-value ... />
        .....
        <column .... />
        <column .... />
        .....
</any>

1

name: o nome da propriedade.

2

id-type: o tipo identificador.

3

meta-type (opcional – padrão para string): Qualquer tipo que é permitido para um mapeamento discriminador.

4

cascade (opcional – valor padrão none): o estilo cascata.

5

access (opcional - padrão para property): A estratégia que o Hiberante deve utilizar para acessar o valor da propriedade.

6

optimistic-lock (opcional - valor padrãotrue): Especifica que as atualizações para esta propriedade requerem ou não aquisição da bloqueio otimista. Em outras palavras, define se uma versão de incremento deve ocorrer se esta propriedade for suja.

O elemento <properties> permite a definição de um grupo com nome, lógico de propriedades de uma classe. A função mais importante do construtor é que ele permite que a combinação de propriedades seja o objetivo de uma property-ref. É também um modo conveninente para definir uma restrição única de múltiplas colunas. Por exemplo:

<properties
        name="(1)logicalName"
        insert(2)="true|false"
        update(3)="true|false"
        optimi(4)stic-lock="true|false"
        unique(5)="true|false"
>

        <property ...../>
        <many-to-one .... />
        ........
</properties>

1

name: O nome lógico do agrupamento. Isto não é o nome atual de propriedade.

2

insert: As colunas mapeadas aparecem nos SQL de INSERTs?

3

update: As colunas mapeadas aparecem nos SQL de UPDATEs?

4

optimistic-lock (opcional – padrão para true): Especifica que atualizações para estes componentes requerem ou não aquisição de um bloqueio otimista. Em outras palavras, determina se uma versão de incremento deve ocorrer quando estas propriedades estiverem sujas.

5

unique (opcional – valor padrão false): Especifica que existe uma unique restrição em todas as colunas mapeadas do componente.

Por exemplo, se temos o seguinte mapeamento de <properties>:


<class name="Person">
    <id name="personNumber"/>

    ...
    <properties name="name"
            unique="true" update="false">
        <property name="firstName"/>
        <property name="initial"/>
        <property name="lastName"/>
    </properties>
</class>

Então podemos ter uma associação de dados legados que referem a esta chave exclusiva da tabela Person, ao invés de se referirem a chave primária:


<many-to-one name="owner"
         class="Person" property-ref="name">
    <column name="firstName"/>
    <column name="initial"/>
    <column name="lastName"/>
</many-to-one>

Nós não recomendamos o uso deste tipo de coisa fora do contexto de mapeamento de dados legados.

The hbm.xml structure has some specificities naturally not present when using annotations, let's describe them briefly.

Todos os mapeamentos de XML devem declarar o doctype exibido. O DTD atual pode ser encontrado na URL abaixo, no diretório hibernate-x.x.x/src/org/ hibernate ou no hibernate3.jar. O Hibernate sempre irá procurar pelo DTD inicialmente no seu classpath. Se você tentar localizar o DTD usando uma conexão de internet, compare a declaração do seu DTD com o conteúdo do seu classpath.

O Hibernate irá primeiro tentar solucionar os DTDs em seus classpath. Isto é feito, registrando uma implementação org.xml.sax.EntityResolver personalizada com o SAXReader que ele utiliza para ler os arquivos xml. Este EntityResolver personalizado, reconhece dois nomes de espaço de sistemas Id diferentes:

Um exemplo de utilização do espaço de nome do usuário:


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
    <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
]>

<hibernate-mapping package="your.domain">
    <class name="MyEntity">
        <id name="id" type="my-custom-id-type">
            ...
        </id>
    <class>
    &types;
</hibernate-mapping>

Onde types.xml é um recurso no pacote your.domain e contém um typedef personalizado.

Este elemento possui diversos atributos opcionais. Os atributos schema e catalog especificam que tabelas referenciadas neste mapeamento pertencem ao esquema e/ou ao catálogo nomeado. Se especificados, os nomes das tabelas serão qualificados no esquema ou catálogo dado. Se não, os nomes das tabelas não serão qualificados. O atributo default-cascade especifica qual estilo de cascata será considerado pelas propriedades e coleções que não especificarem uma função cascade. A função auto-import nos deixa utilizar nomes de classes não qualificados na linguagem de consulta, por padrão.

<hibernate-mapping
         schem(1)a="schemaName"
         catal(2)og="catalogName"
         defau(3)lt-cascade="cascade_style"
         defau(4)lt-access="field|property|ClassName"
         defau(5)lt-lazy="true|false"
         auto-(6)import="true|false"
         packa(7)ge="package.name"
 />

1

schema (opcional): O nome do esquema do banco de dados.

2

catalog (opcional): O nome do catálogo do banco de dados.

3

default-cascade (opcional – o padrão é none): Um estilo cascata padrão.

4

default-access (opcional – o padrão é property): A estratégia que o Hibernate deve utilizar para acessar todas as propridades. Pode ser uma implementação personalizada de PropertyAccessor.

5

default-lazy (opcional - o padrão é true): O valor padrão para atributos lazy não especificados da classe e dos mapeamentos de coleções.

6

auto-import (opcional - o padrão é true): Especifica se podemos usar nomes de classes não qualificados, das classes deste mapeamento, na linguagem de consulta.

7

package (opcional): Especifica um prefixo do pacote a ser considerado para nomes de classes não qualificadas no documento de mapeamento.

Se você tem duas classes persistentes com o mesmo nome (não qualificadas), você deve ajustar auto-import="false". Caso você tentar ajustar duas classes para o mesmo nome "importado", isto resultará numa exceção.

Observe que o elemento hibernate-mapping permite que você aninhe diversos mapeamentos de <class> persistentes, como mostrado abaixo. Entretanto, é uma boa prática (e esperado por algumas ferramentas) o mapeamento de apenas uma classe persistente simples (ou uma hierarquia de classes simples) em um arquivo de mapeamento e nomeá-la após a superclasse persistente, por exemplo: Cat.hbm.xml, Dog.hbm.xml, ou se estiver usando herança, Animal.hbm.xml.

The <key> element is featured a few times within this guide. It appears anywhere the parent mapping element defines a join to a new table that references the primary key of the original table. It also defines the foreign key in the joined table:

<key
        column(1)="columnname"
        on-del(2)ete="noaction|cascade"
        proper(3)ty-ref="propertyName"
        not-nu(4)ll="true|false"
        update(5)="true|false"
        unique(6)="true|false"
/>

1

column (opcional): O nome da coluna da chave exterior. Isto pode também ser especificado através de elementos aninhados <column>.

2

on-delete (opcional, padrão para noaction): Especifica se a restrição da chave exterior no banco de dados está habilitada para o deletar cascade.

3

property-ref (opcional): Especifica que a chave exterior se refere a colunas que não são chave primária da tabela original. Útil para os dados legados.

4

not-null (opcional): Especifica que a coluna da chave exterior não aceita valores nulos. Isto é implícito em qualquer momento que a chave exterior também fizer parte da chave primária.

5

update (opcional): Especifica que a chave exterior nunca deve ser atualizada. Isto está implícito em qualquer momento que a chave exterior também fizer parte da chave primária.

6

unique (opcional): Especifica que a chave exterior deve ter uma restrição única. Isto é, implícito em qualquer momento que a chave exterior também fizer parte da chave primária.

Nós recomendamos que para sistemas que o desempenho deletar seja importante, todas as chaves devem ser definidas on-delete="cascade". O Hibernate irá usar uma restrição a nível de banco de dados ON CASCADE DELETE, ao invés de muitas instruções DELETE. Esteja ciente que esta característica é um atalho da estratégia usual de bloqueio otimista do Hibernate para dados versionados.

As funções not-null e update são úteis quando estamos mapeando uma associação unidirecional um para muitos. Se você mapear uma associação unidirecional um para muitos para uma chave exterior não-nula, você deve declarar a coluna chave usando <key not-null="true">.

Os objetos de nível de linguagem Java são classificados em dois grupos, em relação ao serviço de persistência:

Uma entidade existe independentemente de qualquer outro objeto guardando referências para a entidade. Em contraste com o modelo usual de Java que um objeto não referenciado é coletado pelo coletor de lixo. Entidades devem ser explicitamente salvas ou deletadas (exceto em operações de salvamento ou deleção que possam ser executada em cascata de uma entidade pai para seus filhos). Isto é diferente do modelo ODMG de persistência do objeto por acessibilidade e se refere mais à forma como os objetos de aplicações são geralmente usados em grandes sistemas. Entidades suportam referências circulares e comuns. Eles podem ser versionados.

O estado persistente da entidade consiste de referências para outras entidades e instâncias de tipos de valor. Valores são primitivos: coleções (não o que tem dentro de uma coleção), componentes e certos objetos imutáveis. Entidades distintas, valores (em coleções e componentes particulares) são persistidos e apagados por acessibilidade. Visto que objetos de valor (e primitivos) são persistidos e apagados junto com as entidades que os contém e não podem ser versionados independentemente. Valores têm identidade não independente, assim eles não podem ser comuns para duas entidades ou coleções.

Até agora, estivemos usando o termo "classe persistente" para referir às entidades. Continuaremos a fazer isto. No entanto, nem todas as classes definidas pelo usuário com estados persistentes são entidades. Um componente é uma classe de usuário definida com valores semânticos. Uma propriedade de Java de tipo java.lang.String também tem um valor semântico. Dada esta definição, nós podemos dizer que todos os tipos (classes) fornecidos pelo JDK têm tipo de valor semântico em Java, enquanto que tipos definidos pelo usuário, podem ser mapeados com entidade ou valor de tipo semântico. Esta decisão pertence ao desenvolvedor da aplicação. Uma boa dica para uma classe de entidade em um modelo de domínio são referências comuns para uma instância simples daquela classe, enquanto a composição ou agregação geralmente se traduz para um tipo de valor.

Iremos rever ambos os conceitos durante todo o guia de referência.

O desafio é mapear o sistema de tipo de Java e a definição do desenvolvedor de entidades e tipos de valor para o sistema de tipo SQL/banco de dados. A ponte entre ambos os sistemas é fornecida pelo Hibernate. Para entidades que usam <class>, < subclass> e assim por diante. Para tipos de valores nós usamos <property>, <component>, etc, geralmente com uma função type. O valor desta função é o nome de um tipo de mapeamento do Hibernate. O Hibernate fornece muitos mapeamentos imediatos para tipos de valores do JDK padrão. Você pode escrever os seus próprios tipos de mapeamentos e implementar sua estratégia de conversão adaptada, como você.

Todos os tipos internos do hibernate exceto coleções, suportam semânticas nulas com a exceção das coleções.

Os tipos de mapeamento básicos fazem parte da categorização do seguinte:

integer, long, short, float, double, character, byte, boolean, yes_no, true_false

Tipos de mapeamentos de classes primitivas ou wrapper Java específicos (vendor-specific) para tipos de coluna SQL. Boolean, boolean, yes_no são todas codificações alternativas para um boolean ou java.lang.Boolean do Java.

string

Um tipo de mapeamento de java.lang.String para VARCHAR (ou VARCHAR2 no Oracle).

date, time, timestamp

Tipos de mapeamento de java.util.Date e suas subclasses para os tipos SQL DATE, TIME e TIMESTAMP (ou equivalente).

calendar, calendar_date

Tipo de mapeamento de java.util.Calendar para os tipos SQL TIMESTAMP e DATE (ou equivalente).

big_decimal, big_integer

Tipo de mapeamento de java.math.BigDecimal and java.math.BigInteger para NUMERIC (ou NUMBER no Oracle).

locale, timezone, currency

Tipos de mapeamentos de java.util.Locale, java.util.TimeZone e java.util.Currency para VARCHAR (ou VARCHAR2 no Oracle). Instâncias de f Locale e Currency são mapeados para seus códigos ISO. Instâncias de TimeZone são mapeados para seu ID.

class

Um tipo de mapeamento de java.lang.Class para VARCHAR (ou VARCHAR2 no Oracle). Uma Class é mapeada pelo seu nome qualificado (completo).

binary

Mapeia matrizes de bytes para um tipo binário de SQL apropriado.

text

Maps long Java strings to a SQL LONGVARCHAR or TEXT type.

image

Maps long byte arrays to a SQL LONGVARBINARY.

serializable

Mapeia tipos Java serializáveis para um tipo binário SQL apropriado. Você pode também indicar o tipo serializable do Hibernate com o nome da classe ou interface Java serializável que não é padrão para um tipo básico.

clob, blob

Tipos de mapeamentos para as classes JDBC java.sql.Clob and java.sql.Blob. Estes tipos podem ser inconvenientes para algumas aplicações, visto que o objeto blob ou clob não pode ser reusado fora de uma transação. Além disso, o suporte de driver é imcompleto e inconsistente.

materialized_clob

Maps long Java strings to a SQL CLOB type. When read, the CLOB value is immediately materialized into a Java string. Some drivers require the CLOB value to be read within a transaction. Once materialized, the Java string is available outside of the transaction.

materialized_blob

Maps long Java byte arrays to a SQL BLOB type. When read, the BLOB value is immediately materialized into a byte array. Some drivers require the BLOB value to be read within a transaction. Once materialized, the byte array is available outside of the transaction.

imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date, imm_serializable, imm_binary

Mapeamento de tipos para, os geralmente considerados, tipos mutáveis de Java. Isto é onde o Hibernate faz determinadas otimizações apropriadas somente para tipos imutáveis de Java, e a aplicação trata o objeto como imutável. Por exemplo, você não deve chamar Date.setTime() para uma instância mapeada como imm_timestamp. Para mudar o valor da propriedade, e ter a mudança feita persistente, a aplicação deve atribuir um novo objeto (nonidentical) à propriedade.

Identificadores únicos das entidades e coleções podem ser de qualquer tipo básico exceto binary, blob ou clob. (Identificadores compostos também são permitidos. Leia abaixo para maiores informações.

Os tipos de valores básicos têm suas constantes Type correspondentes definidas em org.hibernate.Hibernate. Por exemplo, Hibernate.STRING representa o tipo string.

É relativamente fácil para desenvolvedores criarem seus próprios tipos de valores. Por exemplo, você pode querer persistir propriedades do tipo java.lang.BigInteger para colunas VARCHAR. O Hibernate não fornece um tipo correspondente para isso. Mas os tipos adaptados não são limitados a mapeamento de uma propriedade, ou elemento de coleção, a uma única coluna da tabela. Assim, por exemplo, você pode ter uma propriedade Java getName()/setName() do tipo java.lang.String que é persistido para colunas FIRST_NAME, INITIAL, SURNAME.

Para implementar um tipo personalizado, implemente org.hibernate.UserType ou org.hibernate.CompositeUserType e declare propriedades usando o nome qualificado da classe do tipo. Veja org.hibernate.test.DoubleStringType para outras funcionalidades.


<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
    <column name="first_string"/>
    <column name="second_string"/>
</property>

Observe o uso da tag <column> para mapear uma propriedade para colunas múltiplas.

As interfaces CompositeUserType, EnhancedUserType, UserCollectionType, e UserVersionType fornecem suporte para usos mais especializados.

Você mesmo pode fornecer parâmetros a um UserType no arquivo de mapeamento. Para isto, seu UserType deve implementar a interface org.hibernate.usertype.ParameterizedType. Para fornecer parâmetros a seu tipo personalizado, você pode usar o elemento <type> em seus arquivos de mapeamento.


<property name="priority">
    <type name="com.mycompany.usertypes.DefaultValueIntegerType">
        <param name="default">0</param>
    </type>
</property>

O UserType pode agora recuperar o valor para o parâmetro chamado padrão da Propriedade do passado a ele.

Se você usar freqüentemente um determinado UserType, pode ser útil definir um nome mais curto para ele. Você pode fazer isto usando o elemento <typedef>. Typedefs atribui um nome a um tipo personalizado, e pode também conter uma lista de valores de parâmetro padrão se o tipo for parametrizado.


<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
    <param name="default">0</param>
</typedef>

<property name="priority" type="default_zero"/>

Também é possível substituir os parâmetros fornecidos em um tipo de definição em situações de caso a caso, utilizando tipos de parâmetros no mapeamento da propriedade.

Apesar da rica variedade, os tipos construídos do Hibernate e suporte para componentes raramente irão utilizar um tipo de padrão, no entanto, é considerado uma boa idéia, utilizar tipos customizados para classes não entidade que ocorrem com freqüência em seu aplicativo. Por exemplo, uma classe MonetaryAmount é um bom candidato para um CompositeUserType, apesar de poder ter sido mapeado facilmente como um componente. Uma motivação para isto é a abstração. Com um tipo padronizado, seus documentos de mapeamento seriam colocados à prova contra mudanças possíveis na forma de representação de valores monetários.

Propriedades Geradas são propriedades que possuem seus valores gerados pelo banco de dados. Como sempre, os aplicativos do Hibernate precisavam renovar objetos que contenham qualquer propriedade para qual o banco de dados estivesse gerando valores. No entanto, vamos permitir que o aplicativo delegue esta responsabilidade ao Hibernate. Essencialmente, quando o Hibernate edita um SQL INSERT ou UPDATE para uma entidade que tem propriedades geradas definidas, ele edita imediatamente depois uma seleção para recuperar os valores gerados.

As propriedades marcadas como geradas devem ser não-inseríveis e não-atualizáveis. Somente versions, timestamps, e simple properties podem ser marcadas como geradas.

never (padrão) - significa que o valor de propriedade dado não é gerado dentro do banco de dados.

insert: informa que o valor de propriedade dado é gerado ao inserir, mas não é novamente gerado nas próximas atualizações. Propriedades do tipo data criada, se encaixam nesta categoria. Note que embora as propriedades version e timestamp podem ser marcadas como geradas, esta opção não está disponível.

always - informa que o valor da propriedade é gerado tanto ao inserir quanto ao atualizar.

To mark a property as generated, use @Generated.

Hibernate allows you to customize the SQL it uses to read and write the values of columns mapped to simple properties. For example, if your database provides a set of data encryption functions, you can invoke them for individual columns like this:

@Entity

class CreditCard {
   @Column(name="credit_card_num")
   @ColumnTransformer(
      read="decrypt(credit_card_num)", 
      write="encrypt(?)")
   public String getCreditCardNumber() { return creditCardNumber; }
   public void setCreditCardNumber(String number) { this.creditCardNumber = number; }
   private String creditCardNumber;
}

or in XML


<property name="creditCardNumber">
        <column 
          name="credit_card_num"
          read="decrypt(credit_card_num)"
          write="encrypt(?)"/>
</property>

Nota

You can use the plural form @ColumnTransformers if more than one columns need to define either of these rules.

If a property uses more that one column, you must use the forColumn attribute to specify which column, the expressions are targeting.

@Entity

class User {
   @Type(type="com.acme.type.CreditCardType")
   @Columns( {
      @Column(name="credit_card_num"),
      @Column(name="exp_date") } )
   @ColumnTransformer(
      forColumn="credit_card_num", 
      read="decrypt(credit_card_num)", 
      write="encrypt(?)")
   public CreditCard getCreditCard() { return creditCard; }
   public void setCreditCard(CreditCard card) { this.creditCard = card; }
   private CreditCard creditCard;
}

O Hibernate aplica automaticamente as expressöes personalizadas a todo instante que a propriedade é referenciada numa consulta. Esta funcionalidade é parecida a uma formula de propriedade-derivada com duas diferenças:

  • Esta propriedade é suportada por uma ou mais colunas que são exportadas como parte da geração do esquema automático.

  • Esta propriedade é de gravação-leitura, e não de leitura apenas.

Caso a expressão writeseja especificada, deverá conter um '?' para o valor.