Author: xhuang(a)jboss.com
Date: 2007-10-25 20:48:48 -0400 (Thu, 25 Oct 2007)
New Revision: 14136
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/association_mapping.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/basic_mapping.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/batch.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/best_practices.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/collection_mapping.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/component_mapping.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/configuration.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/events.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_mappings.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_parentchild.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_weblog.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/filters.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/inheritance_mapping.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/performance.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/persistent_classes.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/preface.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_criteria.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_hql.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_sql.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/session_api.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/toolset_guide.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/transactions.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/tutorial.xml
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/xml.xml
Log:
Remove ^M characters, match with latest English XML
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/association_mapping.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/association_mapping.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/association_mapping.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="associations">
+<chapter id="associations">
<title>Mapeamento de Associações</title>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/basic_mapping.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/basic_mapping.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/basic_mapping.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,3494 +1,3660 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="mapping">
- <title>Mapeamento O/R Bassico</title>
-
- <sect1 id="mapping-declaration" revision="1">
- <title>Declaração de mapeamento</title>
-
- <para>
- Object/relational mappings are usually defined in an XML document. The
mapping
- document is designed to be readable and hand-editable. The mapping language
is
- Java-centric, meaning that mappings are constructed around persistent class
- declarations, not table declarations.
- </para>
-
- <para>
- Note that, even though many Hibernate users choose to write the XML by hand,
- a number of tools exist to generate the mapping document, including XDoclet,
- Middlegen and AndroMDA.
- </para>
-
- <para>
- Lets kick off with an example mapping:
- </para>
-
- <programlisting id="mapping-declaration-ex1"
revision="1"><![CDATA[<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/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>]]></programlisting>
-
- <para>
- Discutir agora o conteúdo deste documento de mapeamento. Iremos apenas
descrever
- os elementos do documento e atributos que são utilizados pelo Hibernate em
tempo
- de execução. O documento de mapeamento também contém alguns atributos
adicionais
- e opcionais além de elementos que afetam os esquemas de banco de dados
exportados
- pela ferramenta de exportação de esquemas. (Por exemplo, o atributo
- <literal>not-null</literal>).
- </para>
-
-
-
- <sect2 id="mapping-declaration-doctype" revision="3">
- <title>Doctype</title>
-
- <para>
- Todos os mapeamentos de XML devem declarar o doctype exibido. O DTD atual
pode
- ser encontrado na URL abaixo, no diretório
<literal>hibernate-x.x.x/src/org/
- hibernate </literal> ou no
<literal>hibernate3.jar</literal>. 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
- </para>
-
- <sect3 id="mapping-declaration-entity-resolution">
- <title>EntityResolver</title>
- <para>
- As mentioned previously, Hibernate will first attempt to resolve DTDs
in its classpath. The
- manner in which it does this is by registering a custom
<literal>org.xml.sax.EntityResolver</literal>
- implementation with the SAXReader it uses to read in the xml files.
This custom
- <literal>EntityResolver</literal> recognizes two
different systemId namespaces.
- </para>
- <itemizedlist>
- <listitem>
- <para>
- a <literal>hibernate namespace</literal> is
recognized whenever the
- resolver encounteres a systemId starting with
-
<
literal>http://hibernate.sourceforge.net/</literal>; the resolver
- attempts to resolve these entities via the classlaoder which
loaded
- the Hibernate classes.
- </para>
- </listitem>
- <listitem>
- <para>
- a <literal>user namespace</literal> is recognized
whenever the
- resolver encounteres a systemId using a
<literal>classpath://</literal>
- URL protocol; the resolver will attempt to resolve these
entities
- via (1) the current thread context classloader and (2) the
- classloader which loaded the Hibernate classes.
- </para>
- </listitem>
- </itemizedlist>
- <para>
- An example of utilizing user namespacing:
- </para>
- <programlisting><![CDATA[<?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>]]></programlisting>
- <para>
- Where <literal>types.xml</literal> is a resource in the
<literal>your.domain</literal>
- package and contains a custom <xref
linkend="mapping-types-custom">typedef</xref>.
- </para>
- </sect3>
- </sect2>
-
- <sect2 id="mapping-declaration-mapping" revision="3">
- <title>hibernate-mapping</title>
-
- <para>
- Este elemento tem diversos atributos opcionais. Os atributos
- <literal>schema</literal> e
<literal>catalog</literal> especificam que tabelas
- referenciadas neste mapeamento pertencem ao esquema e/ou ao catalogo
nomeado.
- Se especificados, os nomes das tabelas irão ser qualificados no schema ou
catalog dado.
- Se não, os nomes das tabelas não serão qualificados. O atributo
<literal>default-cascade
- </literal> especifica qual estilo de cascata será assumido pelas
propriedades e
- coleções que não especificarm um atributo
<literal>cascade</literal>. O atributo
- <literal>auto-import</literal> nos deixa utilizar nomes de
classes não qualificados
- na linguagem de consulta, por default.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="hm1" coords="2 55"/>
- <area id="hm2" coords="3 55"/>
- <area id="hm3" coords="4 55"/>
- <area id="hm4" coords="5 55"/>
- <area id="hm5" coords="6 55"/>
- <area id="hm6" coords="7 55"/>
- <area id="hm7" coords="8 55"/>
- </areaspec>
- <programlisting><![CDATA[<hibernate-mapping
- schema="schemaName"
- catalog="catalogName"
- default-cascade="cascade_style"
- default-access="field|property|ClassName"
- default-lazy="true|false"
- auto-import="true|false"
- package="package.name"
- />]]></programlisting>
- <calloutlist>
- <callout arearefs="hm1">
- <para>
- <literal>schema</literal> (opcional): O nome do
esquema do banco de dados.
- </para>
- </callout>
- <callout arearefs="hm2">
- <para>
- <literal>catalog</literal> (opcional): O nome
do catálogo do banco de dados.
- </para>
- </callout>
- <callout arearefs="hm3">
- <para>
- <literal>default-cascade</literal> (opcional –
default é <literal>nenhum
- </literal>): Um estilo cascata default.
- </para>
- </callout>
- <callout arearefs="hm4">
- <para>
- <literal>default-access</literal> (opcional –
default é <literal>property</literal>):
- A estratégia que o Hibernate deve utilizar para acessar
todas as propridades. Pode
- ser uma implementação própria de
<literal>PropertyAccessor</literal>.
- </para>
- </callout>
- <callout arearefs="hm5">
- <para>
- <literal>default-lazy</literal> (opcional -
default é <literal>true</literal>):
- O valor default para atributos
<literal>lazy</literal> da classe e dos
- mapeamentos de coleções.
- </para>
- </callout>
- <callout arearefs="hm6">
- <para>
- <literal>auto-import</literal> ((opcional -
default é <literal>true</literal>):
- Especifica se nós podemos usar nomes de classess não
qualificados
- (das classes deste mapeamento) na linguagem de consulta.
- </para>
- </callout>
- <callout arearefs="hm7">
- <para>
- <literal>package</literal> (opcional):
Especifica um prefixo da package para
- assumir para nomes de classes não qualificadas no documento
de mapeamento.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Se voce tem duas classes persistentes com o mesmo nome (não
qualificadas), você deve
- setar <literal>auto-import="false"</literal>. O
Hibernate irá gerar uma exceção se
- você tentar setar duas classes para o mesmo nome "importado".
- </para>
-
- <para>
- Observe que o elemento <literal>hibernate-mapping</literal>
permite a você
- aninhar diversos mapeamentos de
<literal><class></literal> 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 nomea-la
após
- a superclasse persistente, por exemplo:
<literal>Cat.hbm.xml</literal>,
- <literal>Dog.hbm.xml</literal>, ou se estiver usando
herança,
- <literal>Animal.hbm.xml</literal>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-class" revision="3">
- <title>class</title>
-
- <para>
- Você pode declarar uma classe persistente utilizando o elemento
- <literal>class</literal>:
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="class1" coords="2 55"/>
- <area id="class2" coords="3 55" />
- <area id="class3" coords="4 55"/>
- <area id="class4" coords="5 55" />
- <area id="class5" coords="6 55"/>
- <area id="class6" coords="7 55" />
- <area id="class7" coords="8 55"/>
- <area id="class8" coords="9 55" />
- <area id="class9" coords="10 55" />
- <area id="class10" coords="11 55"/>
- <area id="class11" coords="12 55"/>
- <area id="class12" coords="13 55"/>
- <area id="class13" coords="14 55"/>
- <area id="class14" coords="15 55"/>
- <area id="class15" coords="16 55"/>
- <area id="class16" coords="17 55"/>
- <area id="class17" coords="18 55"/>
- <area id="class18" coords="19 55"/>
- <area id="class19" coords="20 55"/>
- <area id="class20" coords="21 55"/>
- <area id="class21" coords="22 55"/>
- </areaspec>
- <programlisting><![CDATA[<class
- name="ClassName"
- table="tableName"
- discriminator-value="discriminator_value"
- mutable="true|false"
- schema="owner"
- catalog="catalog"
- proxy="ProxyInterface"
- dynamic-update="true|false"
- dynamic-insert="true|false"
- select-before-update="true|false"
- polymorphism="implicit|explicit"
- where="arbitrary sql where condition"
- persister="PersisterClass"
- batch-size="N"
- optimistic-lock="none|version|dirty|all"
- lazy="true|false"
- entity-name="EntityName"
- check="arbitrary sql check condition"
- rowid="rowid"
- subselect="SQL expression"
- abstract="true|false"
- node="element-name"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="class1">
- <para>
- <literal>name</literal> (opcional): O nome da
classe Java inteiramente qualificado
- da classe persistente (ou interface); Se o atributo é
ausente, assume-se que o
- mapeamento é para intidades não-POJO.
- </para>
- </callout>
- <callout arearefs="class2">
- <para>
- <literal>table</literal> (opcional – default para
nomes de classes não
- qualificadas) O nome da sua tabela do banco de dados.
- </para>
- </callout>
- <callout arearefs="class3">
- <para>
- <literal>discriminator-value</literal> (opcional
– default para o nome da classe):
- Um valor que distingue subclasses individuais, usadas para o
comportamento polimorfico.
- Valores aceitos incluem <literal>null</literal> e
<literal>not null</literal>
- </para>
- </callout>
- <callout arearefs="class4">
- <para>
- <literal>mutable</literal> (opcional - valor
default <literal>true</literal>):
- Especifica que instancias da classe são (ou não) mutáveis
- </para>
- </callout>
- <callout arearefs="class5">
- <para>
- <literal>schema</literal> (opcional): Sobrepõe o
nome do esquema especificado
- pelo elemento root
<literal><hibernate-mapping></literal>.
- </para>
- </callout>
- <callout arearefs="class6">
- <para>
- <literal>catalog</literal> (opcional): Sobrepõe o
nome do catálogo especificado
- pelo elemento root
<literal><hibernate-mapping></literal>.
- </para>
- </callout>
- <callout arearefs="class7">
- <para>
- <literal>proxy</literal> (opcional): Especifica
um interface para ser
- utilizada pelos proxies de inicialização tardia. Você pode
especificar o
- nome da própria classe.
- </para>
- </callout>
- <callout arearefs="class8">
- <para>
- <literal>dynamic-update</literal> (opcional,
valor default <literal>false</literal>):
- Especifica que o SQL de <literal>UPDATE</literal>
deve ser gerado em tempo de
- execução e conter apenas aquelas colunas cujos valores foram
alterados.
- </para>
- </callout>
- <callout arearefs="class9">
- <para>
- <literal>dynamic-insert</literal> (opcional,
valor default <literal>false</literal>):
- Especifica que o SQL de
<literal>INSERT</literal> deve ser gerado em tempo de
- execução e conter apenas aquelas colunas cujos valores não
estão nulos.
- </para>
- </callout>
- <callout arearefs="class10">
- <para>
- <literal>select-before-update</literal>
(opcional, valor default <literal>false</literal>):
- Especifica que o Hibernate
<emphasis>never</emphasis> deve executar um SQL de
- <literal>UPDATE</literal> a não ser que com
certeza um objeto está atualmente modificado.
- Em certos casos (atualmente, apenas quando um objeto
transiente foi associado com uma nova
- sessão utilizando <literal>update()</literal>),
isto significa que o Hibernate ira executar
- uma instrução SQL de <literal>SELECT</literal>
adicional para determinar se um
- <literal>UPDATE</literal> é necessário nesse
momento.
- </para>
- </callout>
- <callout arearefs="class11">
- <para>
- <literal>polymorphism</literal> (opcional,
default para <literal>implicit</literal>):
- Determina se deve ser utilizado a query polimorfica implicita
ou explicitamente.
- </para>
- </callout>
- <callout arearefs="class12">
- <para>
- <literal>where</literal> (opicional) especifica
um comando SQL <literal>WHERE</literal>
- arbitrário para ser usado quando da recuperação de objetos
desta classe.
- </para>
- </callout>
- <callout arearefs="class13">
- <para>
- <literal>persister</literal> (opcional):
Espeicifca uma <literal>ClassPersister</literal>
- customizada.
- </para>
- </callout>
- <callout arearefs="class14">
- <para>
- <literal>batch-size</literal> (opcional, valor
default <literal>1</literal>) especifica um
- "tamanho de lote" para a recuperação de instancias
desta classe pelo identificador.
- </para>
- </callout>
- <callout arearefs="class15">
- <para>
- <literal>optimistic-lock</literal> (octional,
valor default <literal>version</literal>):
- Determina a estratégia de bloqueio.
- </para>
- </callout>
- <callout arearefs="class16">
- <para>
- <literal>lazy</literal> (opcional): A recuperação
tardia pode ser completamente
- desabilitada, setando
<literal>lazy="false"</literal>.
- </para>
- </callout>
- <callout arearefs="class17">
- <para>
- <literal>entity-name</literal> (opcional, default
para o nome da classe): O
- Hibernate3 permite uma classe ser mapeada multiplas vezes,
(potencialmente,para
- diferentes tabelas), e permite mapeamentos de entidades que
são representadas
- por Maps ou XML no nível Java. Nestes casos, você deve
especificar um nome
- arbitrário explicitamente para a entidade. Veja <xref
linkend="persistent-classes-dynamicmodels"/>
- e <xref linkend="xml"/> para maiores
informações.
- </para>
- </callout>
- <callout arearefs="class18">
- <para>
- <literal>check</literal> (opcional): Uma
expressão SQL utilizada para gerar uma
- constraint de <emphasis>verificação</emphasis> de
múltiplas linhas para a geração
- automática do esquema.
- </para>
- </callout>
- <callout arearefs="class19">
- <para>
- <literal>rowid</literal> (opcional): O Hibernate
poder usar as assim 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
<literal>rowid</literal>. Um ROWID é uma implementação
- que representa de maneira detalhada a localização física de
uma determinada
- tupla armazenado.
- </para>
- </callout>
- <callout arearefs="class20">
- <para>
- <literal>subselect</literal> (optional): Maps an
immutable and read-only entity
- to a database subselect. Useful if you want to have a view
instead of a base table,
- but don't. See below for more information.
- <literal>subselect</literal> (opcional): Mapeia
uma entidade imutavel e somente
- de leitura para um subconjunto do banco de dados. Útil se
você quiser ter uma
- view em vez de uma tabela. Veja abaixo para mais
informações.
- </para>
- </callout>
- <callout arearefs="class21">
- <para>
- <literal>abstract</literal> (opcional): Utilizada
para marcar superclasses
- abstratas em hierarquias
<literal><union-subclass></literal>.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- É perfeitamente aceitável para uma classe persitente nomeada ser uma
interface. Você deverá
- então declarar as classes implementadas desta interface utilizando o
elemento
- <literal><subclass></literal>. Você pode
persistir qualquer classe de aninhada
- <emphasis>estatica</emphasis>. Você deverá especificar o nome
da classe usando a forma
- padrão, por exemplo: <literal>eg.Foo$Bar</literal>.
- </para>
-
- <para>
- Classes imutáveis,
<literal>mutable="false"</literal>, não podem ser modificadas ou
excluídas
- pela aplicação. Isso permite ao Hibernate fazer alguns aperfeiçoamentos
de performance.
- </para>
-
- <para>
- O atributo opcional <literal>proxy</literal> habilita a
inicialização tardia das
- instâncias persistentes da classe. O Hibernate irá retornar CGLIB proxies
como implementado
- na interface nomeada. O objeto persistente atual será carregado quando
um método do proxy
- for invocado. Veja "Inicializando coleções e proxies" abaixo.
- </para>
-
- <para>Polimorfismo <emphasis>implícito</emphasis> significa
que instâncias de uma classe
- serão retornada por uma query que dá nome a qualquer superclasse ou
interface implementada,
- ou a classe e as instancias de qualquer subclasse da classe será
retornada por umq query
- que nomeia a classe por si. Polimorfismo
<emphasis>explícito</emphasis> significa que
- instancias da classe serão retornadas apenas por queries que
explicitamente nomeiam a
- classe e que queries que nomeiam as classes irão retornar apenas
instancias de subclasses
- mapeadas dentro da declaração
<literal><class></literal> como uma
- <literal><subclass></literal> ou
<literal><joined-subclass></literal>.
- Para a maioria dos casos, o valor default
<literal>polymorphism="implicit"</literal>,
- é apropriado. Polimorfismo explicito é útil quando duas classes distintas
estão mapeadas
- para a mesma tabela (isso permite um classe "peso leve" que
contem um subconjunto
- de colunas da tabela).
- </para>
-
- <para>
- O atributo <literal>persister</literal> deixa você customizar
a estratégia de persistência
- utilizada para a classe. Você pode, por exemplo, especificar sua prórpia
subclasse do
- <literal>org.hibernate.persister.EntityPersister</literal> ou
você pode criar
- uma implementação completamente nova da interface
- <literal>org.hibernate.persister.ClassPersister</literal> que
implementa a persistência
- através de, por exemplo, chamadas a stored procedeures, serialização de
arquivos flat ou
- LDAP. Veja
<literal>org.hibernate.test.CustomPersister</literal> para um exemplo
- simples (de "persistencia" para uma
<literal>Hashtable</literal>).
- </para>
-
- <para>
- Observe que as configurações
<literal>dynamic-update</literal> e
- <literal>dynamic-insert</literal> não sao herdadas pelas
subclasses e assim podem tambem
- ser especificadas em elementos
<literal><subclass></literal> or
- <literal><joined-subclass></literal>. Estas
configurações podem incrementar a
- performance em alguns casos, mas pode realmente diminuir a performance em
outras.
- Use-as de forma bastante criteriosa.
- </para>
-
- <para>
- O uso de <literal>select-before-update</literal> geralmente
irá diminuir a performance. Ela é
- muito útil para prevenir que uma trigger de atualização no banco de dados
seja ativada
- desnecessariamente, se você reconectar um nó de uma instancia
desconectada em uma
- <literal>Session</literal>.
- </para>
-
- <para>
- Se você ativar <literal>dynamic-update</literal>, você terá
de escolher
- a estratégia de bloqueio otimista:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <literal>version</literal> verifica a versão e a hora
das colunas
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>all</literal> cverifica todas as colunas
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>dirty</literal> verifica as colunas
modificadas, permitindo
- alguns updates concorrentes
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>none</literal> não utiliza o bloqueio
otimista
- </para>
- </listitem>
- </itemizedlist>
- <para>
- Nós <emphasis>recomendamos</emphasis> com muita enfase que
você utilize a
- versão e a hora das colunas para o bloqueio otimista com o Hibernate.
- Esta é a melhor estratégia com respeito a performance e é a única
estratégia
- que trata corretamente as modificações efetuadas em instancias
desconectadas
- (por exemplo, quando <literal>Session.merge()</literal> é
utilizado).
-
- </para>
-
- <para>
- Não ha diferença entre uma view e uma tabela para o mapeamento do
Hibernate, e como
- esperado isto é transparente no nível do banco de dados (observe que
alguns bancos de
- dados não suportam views apropriadamente, especialmente com updates).
Algumas vezes,
- você quer utilizar uma view, ma snão pode cria-la no banco de dados (por
exemplo,
- com um esquema legado). Neste caso, você pode mapear uma entidade
imutável e de
- somente leitura, para uma dada expressão SQL, que representa um
subselect:
- </para>
-
- <programlisting><![CDATA[<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>]]></programlisting>
-
- <para>
- Declare as tabelas para sincronizar com esta entidade, garantindo que o
auto-flush
- ocorra corretamente, e que as queries para esta entidade derivada não
retornem dados
- desatualizados. O
<literal><subselect></literal> está disponível tanto como um
- atributo como um elemento mapeado nested.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-id" revision="4">
- <title>id</title>
-
- <para>
- Classes mapeadas <emphasis>precisam</emphasis> declarar a
coluna de chave primaria da
- tabela do banco de dados. Muitas classes irão tambem ter uma propriedade
ao estilo
- Java-Beans declarando o identificador unico de uma instancia. O elemento
- <literal><id></literal> define o mapeamento
desta propriedade para a chave primária.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="id1" coords="2 70"/>
- <area id="id2" coords="3 70" />
- <area id="id3" coords="4 70"/>
- <area id="id4" coords="5 70" />
- <area id="id5" coords="6 70" />
- </areaspec>
- <programlisting><![CDATA[<id
- name="propertyName"
- type="typename"
- column="column_name"
- unsaved-value="null|any|none|undefined|id_value"
- access="field|property|ClassName">
- node="element-name|@attribute-name|element/(a)attribute|."
-
- <generator class="generatorClass"/>
-</id>]]></programlisting>
- <calloutlist>
- <callout arearefs="id1">
- <para>
- <literal>name</literal> (opcional): O nome do
identificador.
- </para>
- </callout>
- <callout arearefs="id2">
- <para>
- <literal>type</literal> (opcional): Um nome que
indica o tipo no Hibernate.
- </para>
- </callout>
- <callout arearefs="id3">
- <para>
- <literal>column</literal> (opcional – default
para o a propridade name): O
- nome coluna chave primaria.
- </para>
- </callout>
- <callout arearefs="id4">
- <para>
- <literal>unsaved-value</literal> (opcional -
default para um valor "sensível"):
- Uma propriedade de identificação que indica que a instancia
foi novamente
- instanciada (unsaved), diferenciando de instancias
desconectadas que foram
- salvas ou carregadas em uma sessão anterior.
- </para>
- </callout>
- <callout arearefs="id5">
- <para>
- <literal>access</literal> (opcional - valor
default <literal>property</literal>): A
- estratégia que o Hiberante deve utilizar para acessar o valor
da propriedade
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Se o atributo <literal>name</literal> não for declarado,
assume-se que a classe não tem
- a propriedade de identificação.
- </para>
-
- <para>
- O atributo <literal>unsaved-value</literal> não é mais
necessário no Hibernate 3.
- </para>
-
- <para>
- Há declaração alternativa
<literal><composite-id></literal> permite o acesso a
- dados legados com chaves compostas. Nós desencorajamos fortemente o seu
uso por
- qualquer pessoa.
- </para>
-
- <sect3 id="mapping-declaration-id-generator"
revision="2">
- <title>Generator</title>
-
- <para>
- O elemento filho opcional
<literal><generator></literal> nomeia uma classe Java
- usada para gerar identificadores unicos para instancias de uma classe
persistente.
- Se algum parâmetro é requerido para configurar ou inicializar a
instancia geradora,
- eles são passados utilizando o elemento
<literal><param></literal>.
- </para>
-
- <programlisting><![CDATA[<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>]]></programlisting>
-
- <para>
- Todos os generators implementam a interface
<literal>org.hibernate.id.IdentifierGenerator</literal>.
- Esta é uma interface bem simples; algumas aplicações podem prover sua
própria implementação
- esepecializada. Entretanto, o Hibernate disponibiliza um conjunto de
implementações internamente.
- Há nomes de atalhos para estes generators próprios:
- <variablelist>
- <varlistentry>
-
<term><literal>increment</literal></term>
- <listitem>
- <para>
- gera identificadores dos tipos
<literal>long</literal>, <literal>short</literal> ou
- <literal>int</literal> que são unicos apenas
quando nenhum outro processo está
- inserindo dados na mesma tabela. <emphasis>Não
utilize em ambientes
- de cluster.</emphasis>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>identity</literal></term>
- <listitem>
- <para>
- suporta colunas de identidade em DB2, MySQL, MS SQL
Server, Sybase e
- HypersonicSQL. O identificador retornado é do tipo
<literal>long</literal>,
- <literal>short</literal> ou
<literal>int</literal>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>sequence</literal></term>
- <listitem>
- <para>
- utiliza uma sequence em DB2, PostgreSQL, Oracle, SAP DB,
McKoi ou um
- generator no Interbase. O identificador de retorno é do
tipo <literal>
- long</literal>,
<literal>short</literal> ou <literal>int</literal>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>hilo</literal></term>
- <listitem>
- <para
id="mapping-declaration-id-hilodescription" revision="1">
- utiliza um algoritmo hi/lo para gerar de forma eficiente
identificadores do tipo
- <literal>long</literal>,
<literal>short</literal> ou <literal>int</literal>,
- a partir de uma tabela e coluna fornecida (por default
- <literal>hibernate_unique_key</literal> e
<literal>next_hi</literal>)
- como fonte para os valores hi. O algoritmo hi/lo gera
identificadores que são
- únicos apenas para um banco de dados particular.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>seqhilo</literal></term>
- <listitem>
- <para>
- utiliza um algoritmo hi/lo para gerar de forma eficinete
identificadores do tipo
- <literal>long</literal>,
<literal>short</literal> ou <literal>int</literal>,
- a partir de uma sequence de banco de dados fornecida.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>uuid</literal></term>
- <listitem>
- <para>
- utiliza um algortimo UUID de 128-bits para gerar
identificadores do
- tipo string, unicos em uma rede(o endereço IP é
utilizado). O UUID é
- codificado como um string de digitos hexadecimais de
tamanho 32.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>guid</literal></term>
- <listitem>
- <para>
- utiliza um string GUID gerado pelo banco de dados no MS
SQL Server
- e MySQL.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>native</literal></term>
- <listitem>
- <para>
- seleciona entre <literal>identity</literal>,
<literal>sequence</literal>
- ou <literal>hilo</literal> dependendo das
capacidades do banco de dados
- utilizado.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>assigned</literal></term>
- <listitem>
- <para>
- deixa a aplicação definir um identificador para o objeto
antes que o
- <literal>save()</literal> seja chamado. Esta
é a estratégia default
- se nenhum elemento
<literal><generator></literal> é especificado.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>select</literal></term>
- <listitem>
- <para>
- retorna a chave primaria recuperada por uma trigger do
banco de
- dados, selecionado uma linha pela chave única e
recuperando o valor
- da chave primária.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>foreign</literal></term>
- <listitem>
- <para>
- utiliza o identificador de um outro objeto associado.
Normalmente utilizado
- em conjunto com uma associaçõa de chave primária do tipo
-
<literal><one-to-one></literal>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
-
<term><literal>sequence-identity</literal></term>
- <listitem>
- <para>
- a specialized sequence generation strategy which utilizes
a
- database sequence for the actual value generation, but
combines
- this with JDBC3 getGeneratedKeys to actually return the
generated
- identifier value as part of the insert statement
execution. This
- strategy is only known to be supported on Oracle 10g
drivers
- targetted for JDK 1.4. Note comments on these insert
statements
- are disabled due to a bug in the Oracle drivers.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- </para>
- </sect3>
-
- <sect3 id="mapping-declaration-id-hilo"
revision="1">
- <title>Algoritmo Hi/lo</title>
- <para>
- Os geradores <literal>hilo</literal> e
<literal>seqhilo</literal> fornecem duas
- implementações alternativas do algoritmo hi/lo, uma solução
preferencial para a geração
- de identificadores. A primeira implementação requer uma tabela
especial do banco de
- dados para manter o proximo valor "hi" disponível. A
segunda utiliza uma seqüência
- do estilo Oracle (quando suportado).
- </para>
-
- <programlisting><![CDATA[<id name="id"
type="long" column="cat_id">
- <generator class="hilo">
- <param name="table">hi_value</param>
- <param name="column">next_value</param>
- <param name="max_lo">100</param>
- </generator>
-</id>]]></programlisting>
-
- <programlisting><![CDATA[<id name="id"
type="long" column="cat_id">
- <generator class="seqhilo">
- <param name="sequence">hi_value</param>
- <param name="max_lo">100</param>
- </generator>
-</id>]]></programlisting>
-
- <para>
- Infelizemente, voce não pode utilizar
<literal>hilo</literal> quando estiver
- fornecendo sia propria <literal>Connection</literal>
para o Hibernate. Quando o
- Hibernate está usando um datasource do servidor de aplicações para
obter conexões
- suportadas com JTA, você precisa configurar adequadamente o
-
<literal>hibernate.transaction.manager_lookup_class</literal>.
- </para>
- </sect3>
-
- <sect3 id="mapping-declaration-id-uuid">
- <title>UUID algorithm</title>
- <para>
- O UUID contem: o endereço IP, hora de inicio da JVM (com precisão de
um quarto
- de segundo), a hora do sistema e um valor contador (unico dentro da
JVM).
- Não é possivel obter o endereço MAC ou um endereço de memória do
código Java,
- assim este é o melhor que pode ser feito sem utilizar JNI.
- </para>
- </sect3>
-
- <sect3 id="mapping-declaration-id-sequences">
- <title>Colunas de identidade e sequencias</title>
- <para>
- Para bancos de dados que suportam colunas de identidade (DB2, MySQL,
Sybase,
- MS SQL), você pode utilizar uma geração de chave
<literal>identity</literal>.
- Para bancos de dados que suportam sequencias (DB2, Oracle,
PostgreSQL, Interbase,
- McKoi, SAP DB) voce pode utilizar a geração de chaves no estilo
- <literal>sequence</literal>. As duas estratégias requerem
duas consultas SQL
- para inserir um novo objeto.
- </para>
-
- <programlisting><![CDATA[<id name="id"
type="long" column="person_id">
- <generator class="sequence">
- <param name="sequence">person_id_sequence</param>
- </generator>
-</id>]]></programlisting>
-
- <programlisting><![CDATA[<id name="id"
type="long" column="person_id" unsaved-value="0">
- <generator class="identity"/>
-</id>]]></programlisting>
-
- <para>
- Para desenvolvimento multi-plataforma, a estratégia
<literal>native</literal>
- irá escolher entre as estratégias i
<literal>identity</literal>,
- <literal>sequence</literal> e
<literal>hilo</literal>, dependendo das
- capacidades do banco de dados utilizado.
- </para>
- </sect3>
-
- <sect3 id="mapping-declaration-id-assigned">
- <title>Identificadores especificados</title>
- <para>
- Se você quer que a aplicação especifique os identificadores
- (em vez do Hibernate gerá-los) você deve utilizar o gerador
- <literal>assigned</literal>. Este gerador especial irá
utilizar o valor
- do identificador especificado para a propriedade de identificação do
objeto.
- Este gerador é usado quando a chave primaria é a chave natural em vez
de uma
- surrogate key. Este é o comportamento padrão se você não especificar
- um elemento
<literal><generator></literal>.
- </para>
-
- <para>
- Escolher o gerador <literal>assigned</literal> faz com
que o Hibernate
- utilize
<literal>unsaved-value="undefined"</literal>, forçando o Hibernate
- ir até o banco de dados para determinar se uma instância está
transiente ou
- desasociada, a menos que haja uma versão ou uma propriedade
timestamp,
- ou você pode definir
<literal>Interceptor.isUnsaved()</literal>.
- </para>
- </sect3>
-
- <sect3 id="mapping-declaration-id-select">
- <title>Chaves primárias geradas por triggers</title>
- <para>
- Apenas para sistemas legados (o Hibernate nao gera DDL com
triggers).
- </para>
-
- <programlisting><![CDATA[<id name="id"
type="long" column="person_id">
- <generator class="select">
- <param name="key">socialSecurityNumber</param>
- </generator>
-</id>]]></programlisting>
-
- <para>
- No exemplo acima, há uma única propriedade com valor nomeada
- <literal>socialSecurityNumber</literal> definida pela
classe,
- uma chave natural, e uma surrogate key nomeada
- <literal>person_id</literal> cujo valor é gerado pro uma
trigger.
- </para>
-
- </sect3>
-
- </sect2>
-
- <sect2 id="mapping-declaration-compositeid"
revision="3">
- <title>composite-id</title>
-
- <programlisting><![CDATA[<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>]]></programlisting>
-
- <para>
- Para tabelas com uma chave composta, você pode mapear múltiplas
propriedades
- da classe como propriedades de identificação. O elemento
- <literal><composite-id></literal> aceita o
mapeamento da propriedade
- <literal><key-property></literal> e mapeamentos
- <literal><key-many-to-one></literal>como
elements filhos.
- </para>
-
- <programlisting><![CDATA[<composite-id>
- <key-property name="medicareNumber"/>
- <key-property name="dependent"/>
-</composite-id>]]></programlisting>
-
- <para>
- Sua classe persistente <emphasis>precisa</emphasis> sobre
escrever
- <literal>equals()</literal> e
<literal>hashCode()</literal> para implementar
- identificadores compostos igualmente. E precisa também implementar
- <literal>Serializable</literal>.
- </para>
-
- <para>
- Infelizmente, esta solução para um identificador composto significa que
um objeto
- persistente é seu próprio identificador. Não há outro "handle"
que o próprio objeto.
- Você mesmo precisa instanciar uma instância de outra classe persistente e
preencher
- suas propriedades de identificação antes que você possa dar um
<literal>load()</literal>
- para o estado persistente associado com uma chave composta. Nos chamamos
esta
- solução de identificador composto
<emphasis>embedded</emphasis> e não aconselhamos
- para aplicações sérias.
- </para>
-
- <para>
- Uma segunda solução é o que podemos chamar de identificador composto
- <emphasis>mapped</emphasis> quando a propriedades de
identificação nomeadas dentro do
- elemento <literal><composite-id></literal>
estão duplicadas tando na classe
- persistente como em uma classe de identificação separada.
- </para>
-
- <programlisting><![CDATA[<composite-id
class="MedicareId" mapped="true">
- <key-property name="medicareNumber"/>
- <key-property name="dependent"/>
-</composite-id>]]></programlisting>
-
- <para>
- No exemplo, ambas as classes de identificação compostas,
<literal>MedicareId</literal>,
- e a própria classe entidade tem propriedades nomeadas
<literal>medicareNumber</literal>
- e <literal>dependent</literal>. A classe identificadora
precisa sobrepor
- <literal>equals()</literal> e
<literal>hashCode()</literal> e implementar
- <literal>Serializable</literal>. A desvantagem desta solução
é obvia –
- duplicação de código.
- </para>
-
- <para>
- Os seguintes atributos ão utilizados para especificar o mapeamento de
- um identificador composto:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>mapped</literal> mapped (opcional, valor
default <literal>false
- </literal>): indica que um identificar composto mapeado é
usado, e que as
- propriedades de mapeamento contidas refere-se tanto a classe
entidade e
- a classe de identificação composta.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>class</literal> (opcional, mas requerida
para um identificar composto
- mapeado): A classe usada como um identificador composto.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Nós iremos descrever uma terceira e as vezes mais conveniente solução,
onde o
- identificador composto é implementado como uma classe componente na
- <xref linkend="components-compositeid"/>. Os atributos
descritos abaixo aplicam-se
- apenas para esta solução:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>name</literal> (opcional, requerida para
esta solução): Uma
- propriedade do tipo componente que armazena o identificador
composto
- (veja capítulo 9)
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>access</literal> (opcional - valor default
<literal>property</literal>):
- A estartégia Hibernate que deve ser utilizada para acessar o
valor da propriedade.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>class</literal> (opcional - valor default
para o tipo de propriedade
- determiando por reflexão) : A classe componente utilizada como um
identificador
- composto (veja a próxima sessão).
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Esta terceira solução, um <emphasis>componente de
identificação</emphasis>, é o que nós
- recomendamos para a maioria das aplicações.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-discriminator"
revision="3">
- <title>discriminator</title>
-
- <para>
- O elemento <literal><discriminator></literal>
é necessário para persistência
- polimórfica utilizando a estratégia de mapeamento
table-per-class-hierarchy e declara
- uma coluna discriminadora da tabela. A coluna discriminadora contem
valores de marcação
- que dizem a camada de persistência qual subclasse instanciar para uma
linha particular.
- Um restrito conjunto de tipos que podem ser utilizados:
<literal>string</literal>,
- <literal>character</literal>,
<literal>integer</literal>, <literal>byte</literal>,
- <literal>short</literal>,
<literal>boolean</literal>,
- <literal>yes_no</literal>,
<literal>true_false</literal>.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="discriminator1" coords="2 60"/>
- <area id="discriminator2" coords="3 60" />
- <area id="discriminator3" coords="4 60" />
- <area id="discriminator4" coords="5 60" />
- <area id="discriminator5" coords="6 60" />
- </areaspec>
- <programlisting><![CDATA[<discriminator
- column="discriminator_column"
- type="discriminator_type"
- force="true|false"
- insert="true|false"
- formula="arbitrary sql expression"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="discriminator1">
- <para>
- <literal>column</literal> (opcional - valor
default <literal>class</literal>)
- o nome da coluna discriminadora
- </para>
- </callout>
- <callout arearefs="discriminator2">
- <para>
- <literal>type</literal> (opcional - valor default
<literal>string</literal>)
- o nome que indica o tipo Hibernate
- </para>
- </callout>
- <callout arearefs="discriminator3">
- <para>
- <literal>force</literal> (opcional - valor
default <literal>false</literal>)
- "força" o Hibernate a especificar valores
discriminadores permitidos mesmo
- quando recuperando todas as instancias da classe root.
- </para>
- </callout>
- <callout arearefs="discriminator4">
- <para>
- <literal>insert</literal> (opcional - valor
default para <literal>true</literal>)
- sete isto para <literal>false</literal> se sua
coluna discriminadora é também
- parte do identificador composto mapeado. (Diz ao Hibernate
para não incluir a
- coluna em comandos SQL
<literal>INSERT</literal>s).
- </para>
- </callout>
- <callout arearefs="discriminator5">
- <para>
- <literal>formula</literal> (opcional) uma
expressão SQL arbitraria que é e
- xecutada quando um tipo tem que ser avaliado. Permite
discriminação baseada
- em conteúdo.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Valores atuais de uma coluna discriminada são especificados pelo atributo
- <literal>discriminator-value</literal> da
<literal><class></literal>
- e elementos da <literal><subclass></literal>.
- </para>
-
- <para>
- O atributo <literal>force</literal> é util (apenas) em
tabelas contendo linhas com
- valores discriminadores "extras" que não estão mapeados para
uma classe persistente.
- Este não é geralmente o caso.
- </para>
-
- <para>
- Usando o atributo <literal>formula</literal> voce pode
declarar uma expressão SQL
- arbitrária que sera utilizada para avaliar o tipo de uma linha :
- </para>
-
- <programlisting><![CDATA[<discriminator
- formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0
else 1 end"
- type="integer"/>]]></programlisting>
-
- </sect2>
-
- <sect2 id="mapping-declaration-version" revision="4">
- <title>version (optional)</title>
-
- <para>
- O elemento <literal><version></literal> é
opcional e indica que a tabela
- possui dados versionados. Isto é particularmente útil se você planeja
utilizar
- <emphasis>transações longas</emphasis> (veja abaixo):
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="version1" coords="2 70"/>
- <area id="version2" coords="3 70"/>
- <area id="version3" coords="4 70"/>
- <area id="version4" coords="5 70"/>
- <area id="version5" coords="6 70"/>
- <area id="version6" coords="7 70"/>
- <area id="version7" coords="8 70"/>
- </areaspec>
- <programlisting><![CDATA[<version
- column="version_column"
- name="propertyName"
- type="typename"
- access="field|property|ClassName"
- unsaved-value="null|negative|undefined"
- generated="never|always"
- insert="true|false"
- node="element-name|@attribute-name|element/(a)attribute|."
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="version1">
- <para>
- <literal>column</literal> (opcional - default a a
propriedade name): O nome da
- coluna mantendo o numero da versão
- </para>
- </callout>
- <callout arearefs="version2">
- <para>
- <literal>name</literal>: O nome da propriedade da
classe persistente.
- </para>
- </callout>
- <callout arearefs="version3">
- <para>
- <literal>type</literal> (opcional - valor default
para <literal>integer</literal>):
- O tipo do numero da versão
- </para>
- </callout>
- <callout arearefs="version4">
- <para>
- <literal>access</literal> (opcional - valor
default <literal>property</literal>):
- A estratégia Hibernate que deve ser usada para acessar o
valor da propriedade.
- </para>
- </callout>
- <callout arearefs="version5">
- <para>
- <literal>unsaved-value</literal> (opcional –
valor default para <literal>undefined
- </literal>): Um valor para a propriedade versão que
indica que uma instancia é
- uma nova instanciada (unsaved), distinguindo de instancias
desconectadas que foram
- salvas ou carregadas em sessões anteriores.
((<literal>undefined</literal> especifica
- que o valor da propriedade de identificação deve ser
utilizado).
- </para>
- </callout>
- <callout arearefs="version6">
- <para>
- <literal>generated</literal> (optional - defaults
to <literal>never</literal>):
- Specifies that this version property value is actually
generated by the database.
- See the discussion of <xref
linkend="mapping-generated">generated properties</xref>.
- <literal>generated</literal> (opcional - valor
default <literal>never</literal>):
- Especifica que valor para a propriedade versão é na verdade
gerado pelo banco de
- dados. Veja a discussão da Seção
- <xref linkend="mapping-generated">generated
properties</xref>.
- </para>
- </callout>
- <callout arearefs="version7">
- <para>
- <literal>insert</literal> (opcional - valor
default para <literal>true</literal>):
- Especifica se a coluna de versão deve ser incluída no comando
SQL de insert.
- Pode ser configurado como
<literal>false</literal> se a coluna do banco de dados
- está definida com um valor default de
<literal>0</literal>.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Números de versão podem ser dos tipos Hibernate
<literal>long</literal>,
- <literal>integer</literal>,
<literal>short</literal>, <literal>timestamp</literal> ou
- <literal>calendar</literal>.
- </para>
-
- <para>
- A versão de uma propriedade timestamp nunca deve ser nula para uma
instancia
- desconectada, assim o Hibernate irá identificar qualquer instância com
uma versão
- nula ou timestamp como transiente, não importando qual estratégia para
foi
- especificada para <literal>unsaved-value</literal>.
<emphasis>Declarando 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 assinaldados ou chaves compostas!</emphasis>
- </para>
- </sect2>
-
- <sect2 id="mapping-declaration-timestamp" revision="4"
>
- <title>timestamp (optional)</title>
-
- <para>
- O elemento opcional
<literal><timestamp></literal> indica que uma tabela contém
- dados timestamped. Isso tem por objetivo dar uma alternativa para
versionamento. Timestamps
- são por natureza uma implementação menos segura do locking otimista.
Entretanto, algumas
- vezes a aplicação pode usar timestamps em outros caminhos.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="timestamp1" coords="2 70"/>
- <area id="timestamp2" coords="3 70" />
- <area id="timestamp3" coords="4 70" />
- <area id="timestamp4" coords="5 70" />
- <area id="timestamp5" coords="6 70" />
- <area id="timestamp6" coords="7 70" />
- </areaspec>
- <programlisting><![CDATA[<timestamp
- column="timestamp_column"
- name="propertyName"
- access="field|property|ClassName"
- unsaved-value="null|undefined"
- source="vm|db"
- generated="never|always"
- node="element-name|@attribute-name|element/(a)attribute|."
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="timestamp1">
- <para>
- <literal>column</literal> (opcional - valor
default para a propriedade name):
- O nome da coluna que mantem o timestamp.
- </para>
- </callout>
- <callout arearefs="timestamp2">
- <para>
- <literal>name</literal>: O nome da propriedade no
estilo JavaBeans do
- tipo <literal>Date</literal> ou
<literal>Timestamp</literal> da classe
- persistente Java.
- </para>
- </callout>
- <callout arearefs="timestamp3">
- <para>
- <literal>access</literal> (opcional - valor
default para <literal>property</literal>):
- A estretagia Hibernate que deve ser utilizada para acessar o
valor da propriedade.
- </para>
- </callout>
- <callout arearefs="timestamp4">
- <para>
- <literal>unsaved-value</literal> (opcional -
valor default <literal>null</literal>):
- Uma propriedade para a versão de que indica que uma instância
é uma nova instanciada
- (unsaved), distinguindo-a de instancias desconectadas que
foram salvas ou carregadas
- em sessões previas. (<literal>undefined</literal>
especifica que um valor de
- propriedade de identificação deve ser utilizado)
- </para>
- </callout>
- <callout arearefs="timestamp5">
- <para>
- <literal>source</literal> (opcional - valor
default para <literal>vm</literal>):
- De onde o Hibernate deve recuperar o valor timestamp? Do
banco de dados ou da JVM
- corrente? 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
- <literal>Dialect</literal>s suportam a
recuperação do timestamp corrente do banco
- de dados, enquando outros podem não ser seguros para
utilização em bloqueios
- pela falta de precisão (Oracle 8 por exemplo)
- </para>
- </callout>
- <callout arearefs="timestamp6">
- <para>
- <literal>generated</literal> (opcional - valor
default <literal>never</literal>):
- Especifica que o valor da propriedade timestamp é gerado pelo
banco de dados.
- Veja a discussão <xref
linkend="mapping-generated">generated properties</xref>.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Observe que <literal><timestamp></literal> é
equivalente a
- <literal><version
type="timestamp"></literal>. E
- <literal><timestamp
source="db"></literal> é equivalente a
- <literal><version
type="dbtimestamp"></literal>.
- </para>
- </sect2>
-
-
- <sect2 id="mapping-declaration-property" revision="4">
- <title>property</title>
-
- <para>
- O elemento <literal><property></literal>
declara uma propriedade
- persistente de uma classe, no estilo JavaBean.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="property1" coords="2 70"/>
- <area id="property2" coords="3 70"/>
- <area id="property3" coords="4 70"/>
- <areaset id="property4-5" coords="">
- <area id="property4" coords='5 70'/>
- <area id="property5" coords='6 70'/>
- </areaset>
- <area id="property6" coords="7 70"/>
- <area id="property7" coords="8 70"/>
- <area id="property8" coords="9 70"/>
- <area id="property9" coords="10 70"/>
- <area id="property10" coords="11 70"/>
- <area id="property11" coords="12 70"/>
- <area id="property12" coords="13 70"/>
- </areaspec>
- <programlisting><![CDATA[<property
- name="propertyName"
- column="column_name"
- type="typename"
- update="true|false"
- insert="true|false"
- formula="arbitrary SQL expression"
- access="field|property|ClassName"
- lazy="true|false"
- unique="true|false"
- not-null="true|false"
- optimistic-lock="true|false"
- generated="never|insert|always"
- node="element-name|@attribute-name|element/(a)attribute|."
- index="index_name"
- unique_key="unique_key_id"
- length="L"
- precision="P"
- scale="S"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="property1">
- <para>
- <literal>name</literal>: o nome da propriedade,
iniciando com letra minúscula.
- </para>
- </callout>
- <callout arearefs="property2">
- <para>
- <literal>column</literal> (opcional - default
para a propriedade name): o nome
- da coluna mapeada do banco de dados, Isto pode também ser
especificado pelo(s)
- elemento(s)
<literal><column></literal> aninhados.
-
- </para>
- </callout>
- <callout arearefs="property3">
- <para>
- <literal>type</literal> (opcional): um nome que
indica o tipo Hibernate.
- </para>
- </callout>
- <callout arearefs="property4-5">
- <para>
- <literal>update, insert</literal> (opcional -
valor default <literal>true</literal>):
- especifica que as colunas mapeadas devem ser incluidas nas
instruções SQL de
- <literal>UPDATE</literal> e/ou
<literal>INSERT</literal> . Setar ambas para to
- <literal>false</literal> permite uma propridade
"derivada" pura cujo valor é
- inicializado de outra propriedade que mapeie a mesma
coluna(s) ou por uma trigger
- ou outra aplicação.
- </para>
- </callout>
- <callout arearefs="property6">
- <para>
- <literal>formula</literal> (opcional): uma
expressão SQL que definie o valor para
- uma propriedade <emphasis>calculada</emphasis>.
Propriedades calculadas nao tem
- uma coluna de mapeamento para elas.
- </para>
- </callout>
- <callout arearefs="property7">
- <para>
- <literal>access</literal> (opcional – valor
default <literal>property</literal>):
- A estratégia que o Hibernate deve utilizar para acessar o
valor da propriedade
- </para>
- </callout>
- <callout arearefs="property8">
- <para>
- <literal>lazy</literal> (opcional - valor default
para <literal>false</literal>):
- Especifica que esta propriedade deve ser trazida de forma
"lazy" quando a
- instancia da variável é acessada pela primeira vez (requer
instrumentação
- bytecode em tempo de criação).
- </para>
- </callout>
- <callout arearefs="property9">
- <para>
- <literal>unique</literal> (opcional): Habilita a
geração de DDL de uma
- unica constraint para as colunas. Assim, permite que isto
seja o
- alvo de uma <literal>property-ref</literal>.
- </para>
- </callout>
- <callout arearefs="property10">
- <para>
- <literal>not-null</literal> (opcional): Habilita
a geração de DDL de uma
- constraint de nulidade para as colunas.
- </para>
- </callout>
- <callout arearefs="property11">
- <para>
- <literal>optimistic-lock</literal> (opcional -
valor default <literal>true</literal>):
- 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.
- </para>
- </callout>
- <callout arearefs="property12">
- <para>
- <literal>generated</literal> (opcional - valor
default <literal>never</literal>):
- Especifica que o valor da propriedade é na verdade gerado
pelo banco de dados.
- Veja a discussão da seção
- <xref linkend="mapping-generated">generated
properties</xref>.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- <emphasis>typename</emphasis> pode ser:
- </para>
-
- <orderedlist spacing="compact">
- <listitem>
- <para>
- The name of a Hibernate basic type (eg. <literal>integer,
string, character,
- date, timestamp, float, binary, serializable, object,
blob</literal>).
- O nome do tipo basico do Hibernate (ex., <literal>integer,
string, character,
- date, timestamp, float, binary, serializable, object,
blob</literal>).
- </para>
- </listitem>
- <listitem>
- <para>
- O nome da classe Java com um tipo básico default (ex.
<literal>int, float,
- char, java.lang.String, java.util.Date, java.lang.Integer,
java.sql.Clob</literal>).
- </para>
- </listitem>
- <listitem>
- <para>
- O nome da classe Java serializable
- </para>
- </listitem>
- <listitem>
- <para>
- O nome da classe de um tipo customizado (ex.
<literal>com.illflow.type.MyCustomType</literal>).
- </para>
- </listitem>
- </orderedlist>
-
- <para>
- Se você não especificar um tipo, o Hibernate ira utilizar reflexão sobre
a
- propriedade nomeada para ter uma idéia do tipo Hibernate correto. O
Hibernate ira
- tentar interpretar o nome da classe retornada, usando as regras 2, 3 e 4
nesta ordem.
- Entretanto, isto não é sempre suficiente Em certos casos, você ainda irá
necessitar
- do atributo <literal>type</literal>. (Por exemplo, para
distinguir entre
- <literal>Hibernate.DATE</literal> ou
<literal>Hibernate.TIMESTAMP</literal>,
- ou para espcificar uma tipo ciustomizado.)
- </para>
-
- <para>
- O atributo <literal>access</literal> permite voce controlar
como o Hibernate irá
- acessar a propriedade em tempo de execução. Por default, o Hibernate irá
chamar os
- métodos get/set da propriedades. Se voce especificar
<literal>access="field"</literal>,
- o Hibernate ira bipassar os metodos get/set, acessnado o campo
diretamente,
- usando reflexão. Voc epode especificar sua própria estratégia para acesso
da
- propriedade criando uma classe que implemente a interface
- <literal>org.hibernate.property.PropertyAccessor</literal>.
- </para>
-
- <para>
- Um recurso especialmente poderoso é o de propriedades derivadas. Estas
propriedades
- são por definição read-only, e o valor da propriedade é calculado em
tempo de execução.
- Você declara este calculo como uma expressão SQL, que traduz para
clausula
- <literal>SELECT</literal> de uma subquery daquery SQL que
carrega a instancia:
- </para>
-
- <programlisting><![CDATA[
-<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
)"/>]]></programlisting>
-
- <para>
- 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 (
- <literal>customerId</literal> no exemplo dado). Observe
tambem que voce pode usar o
- mapeamento de elemento aninhado
<literal><formula></literal>, se você não
- gostar de usar o atributo.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-manytoone"
revision="5">
- <title>many-to-one</title>
-
- <para>
- Uma associação ordinária para outra classe persistente é declarada usando
o
- elemento <literal>many-to-one</literal>. O modelo relacional
é uma
- associação many-to-one: a uma chave estrangeira de uma tabela
referenciando
- a chave primaria da tabela destino.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="manytoone1" coords="2 70"/>
- <area id="manytoone2" coords="3 70"/>
- <area id="manytoone3" coords="4 70"/>
- <area id="manytoone4" coords="5 70"/>
- <area id="manytoone5" coords="6 70"/>
- <areaset id="manytoone6-7" coords="">
- <area id="manytoone6" coords='7 70'/>
- <area id="manytoone7" coords='8 70'/>
- </areaset>
- <area id="manytoone8" coords="9 70"/>
- <area id="manytoone9" coords="10 70"/>
- <area id="manytoone10" coords="11 70"/>
- <area id="manytoone11" coords="12 70"/>
- <area id="manytoone12" coords="13 70"/>
- <area id="manytoone13" coords="14 70"/>
- <area id="manytoone14" coords="15 70"/>
- <area id="manytoone15" coords="16 70"/>
- <area id="manytoone16" coords="17 70"/>
- </areaspec>
- <programlisting><![CDATA[<many-to-one
- name="propertyName"
- column="column_name"
- class="ClassName"
- cascade="cascade_style"
- fetch="join|select"
- update="true|false"
- insert="true|false"
- property-ref="propertyNameFromAssociatedClass"
- access="field|property|ClassName"
- unique="true|false"
- not-null="true|false"
- optimistic-lock="true|false"
- lazy="proxy|no-proxy|false"
- not-found="ignore|exception"
- entity-name="EntityName"
- formula="arbitrary SQL expression"
- node="element-name|@attribute-name|element/(a)attribute|."
- embed-xml="true|false"
- index="index_name"
- unique_key="unique_key_id"
- foreign-key="foreign_key_name"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="manytoone1">
- <para>
- <literal>name</literal>: O nome da propriedade.
- </para>
- </callout>
- <callout arearefs="manytoone2">
- <para>
- <literal>column</literal> (opcional): O nome da
coluna foreign key. Isto
- pode também ser especificado através de elementos aninhados
- <literal><column></literal>.
- </para>
- </callout>
- <callout arearefs="manytoone3">
- <para>
- <literal>class</literal> (opcional – default para
o tipo de propriedade
- determinado pela reflexão). O nome da classe associada.
- </para>
- </callout>
- <callout arearefs="manytoone4">
- <para>
- <literal>cascade</literal> (opcional): Especifica
quais operações dever
- ser em cascata do objeto pai para o objeto associado.
- </para>
- </callout>
- <callout arearefs="manytoone5">
- <para>
- <literal>fetch</literal> (opcional - default para
<literal>select</literal>):
- Escolhe entre recuperação outer-join ou recuperação
seqüencial.
- </para>
- </callout>
- <callout arearefs="manytoone6-7">
- <para>
- <literal>update, insert</literal> (opcional -
valor default <literal>true</literal>):
- especifica que as colunas mapeadas dever ser incluidas em
instruções SQL de
- <literal>UPDATE</literal> e/ou
<literal>INSERT</literal>. Setando ambas para
- <literal>false</literal> você permite uma
associação "derivada" pura cujos valores
- são inicializados de algumas outras propriedades que mapeiam
a mesma coluna ou
- por uma trigger ou outra aplicação.
- </para>
- </callout>
- <callout arearefs="manytoone8">
- <para>
- <literal>property-ref</literal>: (opcional) O
nome da propriedade da classe associada
- que faz a junção desta foreign key. Se não especificada, a
chave primaria da
- classe associada será utilizada.
- </para>
- </callout>
- <callout arearefs="manytoone9">
- <para>
- <literal>access</literal> (opcional - valor
default <literal>property</literal>): A
- estrategia que o Hibernate deve utilizar para acessar o valor
da propriedade.
- </para>
- </callout>
- <callout arearefs="manytoone10">
- <para>
- <literal>unique</literal> (opcional): Habilita a
geração DDL de uma constraint
- unique para a coluna foreign-key. Alem disso, permite ser o
alvo de uma
- <literal>property-ref</literal>. Isso torna a
associação multipla
- efetivamente um para um.
- </para>
- </callout>
- <callout arearefs="manytoone11">
- <para>
- <literal>not-null</literal> (opcional): Habilita
a geração DDL de uma constraint de
- nulidade para as foreign keys.
- </para>
- </callout>
- <callout arearefs="manytoone12">
- <para>
- <literal>optimistic-lock</literal> (opcional -
valor default <literal>true</literal>):
- Especifica se mudanças desta propriedade requerem ou não
travamento otimista.
- Em outras palavras, determina se um incremento de versão deve
ocorrer quando
- esta propriedade está suja.
- </para>
- </callout>
- <callout arearefs="manytoone13">
- <para>
- <literal>lazy</literal>(opcional – valor default
<literal>proxy</literal>):
- Por default, associações de ponto unico são envoltas em um
proxie.
- <literal>lazy="no-proxy"</literal>
especifica que a propriedade deve ser
- trazida de forma tardia quando a instancia da variável é
acessada pela
- primeira vez (requer instrumentação bytecode em tempo de
criação)
- <literal>lazy="false"</literal>
especifica que a associação será
- sempre recuperada fortemente.
- </para>
- </callout>
- <callout arearefs="manytoone14">
- <para>
- <literal>not-found</literal> (opcional - valor
default <literal>exception</literal>):
- Especifica como as foreign keys que referenciam linhas
ausentes serão tratadas:
- <literal>ignore</literal> irá tratar a linha
ausente como ama associaççao de null
- </para>
- </callout>
- <callout arearefs="manytoone15">
- <para>
- <literal>entity-name</literal> (opcional): O nome
da entidade da classe associada.
- </para>
- </callout>
- </calloutlist>
- <callout arearefs="manytoone16">
- <para>
- <literal>formula</literal> (optional): Uma
expressão SQL que define um valor
- para um foreign key
<emphasis>computed</emphasis>.
- </para>
- </callout>
- </programlistingco>
-
- <para>
- Setar o valor do atributo <literal>cascade</literal> para
qualquer valor
- significativo diferente de <literal>none</literal> irá
propagar certas operações
- ao objeto associado. Os valores significativos são os nomes das operações
básicas
- do Hibernate, <literal>persist, merge, delete, save-update, evict,
replicate, lock,
- refresh</literal>, assim como os valores especiais
<literal>delete-orphan</literal>
- e <literal>all</literal> e combinações de nomes de operações
separadas por vírgula,
- como por exemplo,
<literal>cascade="persist,merge,evict"</literal> ou
- <literal>cascade="all,delete-orphan"</literal>.
Veja a seção
- <xref linkend="objectstate-transitive"/> para uma
explicação completa. Note que
- associações valoradas simples (associações muitos-pra-um, e um-pra-um)
não suportam
- orphan delete.
- </para>
-
- <para>
- Uma típica declaração <literal>muitos-pra-um</literal> se
parece com esta:
- </para>
-
- <programlisting><![CDATA[<many-to-one name="product"
class="Product" column="PRODUCT_ID"/>]]></programlisting>
-
- <para>
- O atributo <literal>property-ref</literal> deve apenas ser
usado para mapear dados
- legados onde uma chave estrangeira se referencia a uma chave exclusiva da
tabela
- associada que não seja à chave primária. Este é um modelo relacional
desagradável.
- Por exemplo, suponha que a classe <literal>Product</literal>
tenha um número
- seqüencial exclusivo, que não é a chave primária. (O atributo
<literal>unique</literal>
- controla a geração de DDL do Hibernate com a ferramenta SchemaExport.)
- </para>
-
- <programlisting><![CDATA[<property name="serialNumber"
unique="true" type="string"
column="SERIAL_NUMBER"/>]]></programlisting>
-
- <para>
- Então o mapeamento para <literal>OrderItem</literal> poderia
usar:
- </para>
-
- <programlisting><![CDATA[<many-to-one name="product"
property-ref="serialNumber"
column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
-
- <para>
- Porém, isto obviamente não é indicado, nunca.
- </para>
-
- <para>
- Se a chave exclusiva referenciada engloba múltiplas propriedades da
entidade associada,
- você deve mapear as propriedades referenciadas dentro de um elemento
chamado
- <literal><properties></literal>
-
- </para>
-
- <para>
- Se a chave exclusiva referenciada é a propriedade de um componente, você
pode especificar
- um caminho para a propriedade.
- </para>
-
- <programlisting><![CDATA[<many-to-one name="owner"
property-ref="identity.ssn"
column="OWNER_SSN"/>]]></programlisting>
-
- </sect2>
-
- <sect2 id="mapping-declaration-onetoone" revision="3">
- <title>one-to-one (um-pra-um)</title>
-
- <para>
- Uma associação um-pra-um para outra classe persistente é declarada usando
- um elemento <literal>one-to-one </literal>.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="onetoone1" coords="2 70"/>
- <area id="onetoone2" coords="3 70"/>
- <area id="onetoone3" coords="4 70"/>
- <area id="onetoone4" coords="5 70"/>
- <area id="onetoone5" coords="6 70"/>
- <area id="onetoone6" coords="7 70"/>
- <area id="onetoone7" coords="8 70"/>
- <area id="onetoone8" coords="9 70"/>
- <area id="onetoone9" coords="10 70"/>
- <area id="onetoone10" coords="11 70"/>
- </areaspec>
- <programlisting><![CDATA[<one-to-one
- name="propertyName"
- class="ClassName"
- cascade="cascade_style"
- constrained="true|false"
- fetch="join|select"
- property-ref="propertyNameFromAssociatedClass"
- access="field|property|ClassName"
- formula="any SQL expression"
- lazy="proxy|no-proxy|false"
- entity-name="EntityName"
- node="element-name|@attribute-name|element/(a)attribute|."
- embed-xml="true|false"
- foreign-key="foreign_key_name"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="onetoone1">
- <para>
- <literal>name</literal>: O nome da propriedade.
- </para>
- </callout>
- <callout arearefs="onetoone2">
- <para>
- <literal>class</literal> (opcional – default para
o tipo da propriedade
- definido via reflection): O nome da classe associada.
- </para>
- </callout>
- <callout arearefs="onetoone3">
- <para>
- <literal>cascade</literal> (opcional): Especifica
qual operação deve
- ser cascateada do objeto pai para o objeto associado.
- </para>
- </callout>
- <callout arearefs="onetoone4">
- <para>
- <literal>constrained</literal> (opcional):
Especifica que uma chave estrangeira
- constraint na chave primária da tabela mapeada referencia a
tabela da classe
- associada, Esta opção afeta a ordem em queh
<literal>save()</literal> e
- <literal>delete()</literal> são cascateadas, e
determina se a associação
- pode ser substituída (isto também é usado pela ferramenta
schema export).
- </para>
- </callout>
- <callout arearefs="onetoone5">
- <para>
- <literal>fetch</literal> ((opcional – valor
default <literal>select</literal>):
- Escolhe entre outer-join fetching ou sequential select
fetching.
- </para>
- </callout>
- <callout arearefs="onetoone6">
- <para>
- <literal>property-ref</literal>(opcional): O nome
da propriedade da classe associada
- que é ligada a chave primária desta classe. Se não for
especificada, a chave primária
- da classe associada é utilizada.
- </para>
- </callout>
- <callout arearefs="onetoone7">
- <para>
- <literal>access</literal> (opcional - valor
default padrão <literal>property</literal>):
- A estratégia que o Hibernate pode usar para acessar o valor
da propriedade.
- </para>
- </callout>
- <callout arearefs="onetoone8">
- <para>
- <literal>formula</literal> (opcional): Quase
todas associações um-pra-um mapeiam
- para a chave primária da entidade dona. No caso raro, que não
é o caso, você
- pode especificar uma outra coluna, colunas ou expressões para
juntar utilizando
- uma formula SQL. (Veja
<literal>org.hibernate.test.onetooneformula</literal>
- para exemplo).
- </para>
- </callout>
- <callout arearefs="onetoone9">
- <para>
- <literal>lazy</literal> (opcional – valor default
<literal>proxy</literal>):
- Por default, associações single point são proxied.
<literal>lazy="no-proxy"</literal>
- especifica que a propriedade deve ser fetched lazily quando o
atributo é acessado
- pela primeira vez (requer build-time bytecode
instrumentation).
- <literal>lazy="false"</literal>
especifica que a associação vai sempre ser
- avidamente fetched. <emphasis>Note que se
<literal>constrained="false"</literal>,
- proxing é impossível e o Hibernate vai ávido fetch a
associação!</emphasis>
- </para>
- </callout>
- <callout arearefs="onetoone10">
- <para>
- <literal>entity-name</literal> (opcional): O nome
da entidade da classe associada.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Existem duas variedades de associações um-pra-um:
- </para>
- <itemizedlist>
- <listitem><para>
- associações de chave primária
- </para></listitem>
- <listitem><para>
- associações de chave estrangeira exclusiva
- </para></listitem>
- </itemizedlist>
-
- <para>
- Associações de chave primária não necessitam de uma coluna extra de
tabela; se duas
- linhas são relacionadas pela associação então as duas linhas da tabela
dividem a mesmo
- valor da chave primária. Assim, se você quer que dois objetos sejam
relacionados por
- uma associação de chave primária, você deve ter certeza que eles são
assinados com o
- mesmo valor identificador!
- </para>
-
- <para>
- Para uma associação de chave primária, adicione os seguintes mapeamentos
em
- <literal>Employee</literal> e
<literal>Person</literal>, respectivamente.
- </para>
-
- <programlisting><![CDATA[<one-to-one name="person"
class="Person"/>]]></programlisting>
- <programlisting><![CDATA[<one-to-one name="employee"
class="Employee" constrained="true"/>]]></programlisting>
-
- <para>
- Agora nós 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
<literal>foreign</literal>:
- </para>
-
- <programlisting><![CDATA[<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>]]></programlisting>
-
- <para>
- Uma nova instância de <literal>Person</literal> salva
recentemente é então assinada
- com o mesmo valor da chave primária da instância de
<literal>employee</literal> referenciada
- com a propriedade <literal>employee</literal> daquela
<literal>Person</literal>.
- </para>
-
- <para>
- Alternativamente, uma chave estrangeira com uma unique constraint, de
- <literal>Employee</literal> para
<literal>Person</literal>, pode ser expressa como:
- </para>
-
- <programlisting><![CDATA[<many-to-one name="person"
class="Person" column="PERSON_ID"
unique="true"/>]]></programlisting>
-
- <para>
- E esta associação pode ser feita de forma bi-direcional adicionando o
seguinte
- no mapeamento de <literal>Person</literal>:
- </para>
-
- <programlisting><![CDATA[<one-to-one name="employee"
class="Employee"
property-ref="person"/>]]></programlisting>
-
- </sect2>
-
- <sect2 id="mapping-declaration-naturalid">
- <title>natural-id</title>
-
- <programlisting><![CDATA[<natural-id
mutable="true|false"/>
- <property ... />
- <many-to-one ... />
- ......
-</natural-id>]]></programlisting>
-
- <para>
- Embora nós recomendemos o uso de surrogate keys como chaves primárias,
você deve
- ainda identificar chaves naturais para todas as entidades. Uma chave
natural é
- uma propriedade ou combinação de propriedades que é exclusiva e não nula.
Se não
- pude ser modificada, melhor ainda. Mapeie as propriedades da chave
natural dentro do
- elemento <literal><natural-id></literal>. O
Hibernate irá gerar a chave
- exclusiva necessária e as constraints de nullability , e seu mapeamento
será
- apropriadamente auto documentado.
- </para>
-
- <para>
- Nós recomendamos com enfase que você implemente
<literal>equals()</literal> e
- <literal>hashCode()</literal> para comparar as propriedades
da chave natural da
- entidade.
- </para>
-
- <para>
- Este mapeamento não tem o objetivo de uso com entidades com natural
chaves primárias.
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>mutable</literal> mutable (opcional, valor
default<literal>false</literal>):
- Por default, propriedades naturais identificadoras são
consideradas imutáveis (constante).
- </para>
- </listitem>
- </itemizedlist>
-
- </sect2>
-
- <sect2 id="mapping-declaration-component"
revision="2">
- <title>componente, componente dinâmico</title>
-
- <para>
- O elemento<literal><component></literal> mapeia
propriedades de um
- objeto filho para colunas da tabela de uma classe pai. Componentes podem,
- um após o outro, declarar suas próprias propriedades, componentes ou
coleções.
- Veja "Components" abaixo.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="component1" coords="2 45"/>
- <area id="component2" coords="3 45"/>
- <area id="component3" coords="4 45"/>
- <area id="component4" coords="5 45"/>
- <area id="component5" coords="6 45"/>
- <area id="component6" coords="7 45"/>
- <area id="component7" coords="8 45"/>
- <area id="component8" coords="9 45"/>
- </areaspec>
- <programlisting><![CDATA[<component
- name="propertyName"
- class="className"
- insert="true|false"
- update="true|false"
- access="field|property|ClassName"
- lazy="true|false"
- optimistic-lock="true|false"
- unique="true|false"
- node="element-name|."
->
-
- <property ...../>
- <many-to-one .... />
- ........
-</component>]]></programlisting>
- <calloutlist>
- <callout arearefs="component1">
- <para>
- <literal>name</literal>: O nome da propriedade.
- </para>
- </callout>
- <callout arearefs="component2">
- <para>
- <literal>class</literal> (opcional – valor
default para o tipo de
- propriedade determinada por reflection): O nome da classe
(filha) do
- componente.
- </para>
- </callout>
- <callout arearefs="component3">
- <para>
- <literal>insert</literal>: As colunas mapeadas
aparecem nos
- SQL de <literal>INSERT</literal>s?
- </para>
- </callout>
- <callout arearefs="component4">
- <para>
- <literal>update</literal>: As colunas mapeadas
aparecem nos
- SQL de <literal>UPDATE</literal>s?
- </para>
- </callout>
- <callout arearefs="component5">
- <para>
- <literal>access</literal> (opcional – valor
default <literal>property</literal>):
- A estratégia que o Hibernate pode usar para acessar o valor
da propriedade.
- </para>
- </callout>
- <callout arearefs="component6">
- <para>
- <literal>lazy</literal> (opcional - valor default
<literal>false</literal>):
- Especifica que este componente deve ser fetched lazily quando
o atributo for
- acessado pela primeira vez (requer build-time bytecode
instrumentation).
- </para>
- </callout>
- <callout arearefs="component7">
- <para>
- <literal>optimistic-lock</literal> (opcional
– valor default <literal>true</literal>):
- Especifica que atualizações para este componente requerem
ou não aquisição
- de um lock otimista. Em outras palavras, determina se uma
versão de incremento deve
- ocorrer quando esta propriedade estiver modificada.
- </para>
- </callout>
- <callout arearefs="component8">
- <para>
- <literal>unique</literal> (opcional – valor
default <literal>false</literal>):
- Especifica que existe uma unique constraint em todas as
colunas mapeadas do
- componente.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- A tag filha <literal><property></literal>
acrescenta a propriedade
- de mapeamento da classe filha para colunas de uma tabela.
- </para>
-
- <para>
- O elemento <literal><component></literal>
permite um sub-elemento
- <literal><parent></literal> mapeie uma
propriedade da classe do componente
- como uma referencia de volta para a entidade que o contém.
- </para>
-
- <para>
- O elemento
<literal><dynamic-component></literal> permite que um
- <literal>Map</literal> possa ser mapeado como um componente
onde os nomes das
- propriedades referem-se para as chaves no mapa, veja
- <xref linkend="components-dynamic"/>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-properties"
revision="2">
- <title>propriedades</title>
-
- <para>
- O elemento <literal><properties></literal>
permite a definição de um grupo
- com nome, lógico de propriedades de uma classe. O uso mais importante do
construtor
- é que este permite uma combinação de propriedades para ser o objetivo de
uma
- <literal>property-ref</literal>. É também um modo
conveninente para definir uma
- unique constraint de múltiplas colunas.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="properties1" coords="2 45"/>
- <area id="properties2" coords="3 45"/>
- <area id="properties3" coords="4 45"/>
- <area id="properties4" coords="5 45"/>
- <area id="properties5" coords="6 45"/>
- </areaspec>
- <programlisting><![CDATA[<properties
- name="logicalName"
- insert="true|false"
- update="true|false"
- optimistic-lock="true|false"
- unique="true|false"
->
-
- <property ...../>
- <many-to-one .... />
- ........
-</properties>]]></programlisting>
- <calloutlist>
- <callout arearefs="properties1">
- <para>
- <literal>name</literal>:: O nome lógico do
agrupamento –
- <emphasis>não </emphasis> é o nome atual de
propriedade.
- </para>
- </callout>
- <callout arearefs="properties2">
- <para>
- <literal>insert</literal>: As colunas mapeadas
aparecem nos
- SQL de <literal>INSERT</literal>s?
- </para>
- </callout>
- <callout arearefs="properties3">
- <para>
- <literal>update</literal>: As colunas mapeadas
aparecem nos
- SQL de <literal>UPDATE</literal>s?
- </para>
- </callout>
- <callout arearefs="properties4">
- <para>
- <literal>optimistic-lock</literal> (opcional
– valor default <literal>true</literal>):
- Especifica que atualizações para estes componentes
requerem ou não aquisição de um
- lock otimista. Em outras palavras, determina se uma
versão de incremento deve ocorrer
- quando estas propriedades estiverem modificadas.
- </para>
- </callout>
- <callout arearefs="properties5">
- <para>
- <literal>unique</literal> (opcional – valor
defautl <literal>false</literal>):
- Especifica que uma unique constraint existe em todas as
colunas mapeadas do componente.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Por exemplo, se nós temos o seguinte mapeamento de
<literal><properties></literal>:
- </para>
-
- <programlisting><![CDATA[<class name="Person">
- <id name="personNumber"/>
- ...
- <properties name="name"
- unique="true" update="false">
- <property name="firstName"/>
- <property name="initial"/>
- <property name="lastName"/>
- </properties>
-</class>]]></programlisting>
-
- <para>
- Então nós podemos ter uma associação de dados herdados que referem a
esta chave
- exclusiva da tabela <literal>Person</literal>, ao invés de se
referirem a chave
- primária:
- </para>
-
- <programlisting><![CDATA[<many-to-one name="person"
- class="Person" property-ref="name">
- <column name="firstName"/>
- <column name="initial"/>
- <column name="lastName"/>
-</many-to-one>]]></programlisting>
-
- <para>
- Nós não recomendamos o uso deste tipo de coisa fora do contexto de
mapeamento de
- dados herdados.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-subclass" revision="4">
- <title>subclass (subclasse)</title>
-
- <para>
- Finalmente, a persistência polimórfica requer a declaração de cada
subclasse
- da classe de persistência raiz. Para a estratégia de mapeamento
- table-per-class-hierarchy, a declaração
<literal><subclass></literal>
- deve ser usada.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="subclass1" coords="2 55"/>
- <area id="subclass2" coords="3 55"/>
- <area id="subclass3" coords="4 55"/>
- <area id="subclass4" coords="5 55"/>
- </areaspec>
- <programlisting><![CDATA[<subclass
- name="ClassName"
- discriminator-value="discriminator_value"
- proxy="ProxyInterface"
- lazy="true|false"
- dynamic-update="true|false"
- dynamic-insert="true|false"
- entity-name="EntityName"
- node="element-name"
- extends="SuperclassName">
-
- <property .... />
- .....
-</subclass>]]></programlisting>
- <calloutlist>
- <callout arearefs="subclass1">
- <para>
- <literal>name</literal>: O nome de classe
completamente qualificada da subclasse.
- </para>
- </callout>
- <callout arearefs="subclass2">
- <para>
- <literal>discriminator-value</literal> (opcional
– valor default o nome da classe):
- Um valor que distingue subclasses individuais.
- </para>
- </callout>
- <callout arearefs="subclass3">
- <para>
- <literal>proxy</literal> (opcional): Especifica a
classe ou interface que
- usará os proxies de inicialização atrasada.
- </para>
- </callout>
- <callout arearefs="subclass4">
- <para>
- <literal>lazy</literal> (opcional, valor default
<literal>true</literal>):
- Configurar
<literal>lazy="false"</literal> desabilitará o uso de
- inicialização atrasada.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
- <para>
- Cada subclasse deve declarar suas próprias propriedades persistentes e
subclasses.
- As propriedades <literal><version></literal> e
<literal><id></literal>
- são configuradas para serem herdades da classe raiz. Cada subclasse numa
hierarquia
- deve definir um único <literal>discriminator-value</literal>.
Se nenhum for
- especificado, o nome da classe Java completamente qualificada será
usada.
- </para>
-
- <para>
- Para informações sobre mapeamento de heranças, veja o <xref
linkend="inheritance"/>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-joinedsubclass"
revision="3">
- <title>joined-subclass</title>
-
- <para>
- Alternativamente, cada subclasse pode ser mapeada para sua própria tabela
- (Estratégia de mapeamento table-per-subclass). O estado herdado é
devolvido
- por associação com a tabela da superclasse. Nós usamos o elemento
- <literal><joined-subclass></literal>.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="joinedsubclass1" coords="2 45"/>
- <area id="joinedsubclass2" coords="3 45"/>
- <area id="joinedsubclass3" coords="4 45"/>
- <area id="joinedsubclass4" coords="5 45"/>
- </areaspec>
- <programlisting><![CDATA[<joined-subclass
- name="ClassName"
- table="tablename"
- proxy="ProxyInterface"
- lazy="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>]]></programlisting>
- <calloutlist>
- <callout arearefs="joinedsubclass1">
- <para>
- <literal>name</literal>: O nome da classe
completamente qualificada da
- subclasse.
- </para>
- </callout>
- <callout arearefs="joinedsubclass2">
- <para>
- <literal>table</literal>: O nome da tabela da
subclasse.
- </para>
- </callout>
- <callout arearefs="joinedsubclass3">
- <para>
- <literal>proxy</literal> (opcional): Especifica a
classe ou interface
- para usar os proxies de recuperação atrasada.
- </para>
- </callout>
- <callout arearefs="joinedsubclass4">
- <para>
- <literal>lazy</literal> (opcional, valor default
<literal>true</literal>):
- Fixanr <literal>lazy="false"</literal>
desabilita o uso recuperação
- atrasada.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- A coluna discriminator requerida para esta estratégia de mapeamento.
Porém,
- cada subclasse deve declarar uma coluna de tabela com o identificador do
objeto
- usando o elemento <literal><key></literal>. O
mapeamento no início do
- capítulo poderia ser re-escrito assim:
- </para>
-
- <programlisting><![CDATA[<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD//EN"
- "http://hibernate.sourceforge.net/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>]]></programlisting>
-
- <para>
- Para informações de mapeamentos de herança, veja <xref
linkend="inheritance"/>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-unionsubclass"
revision="2">
- <title>union-subclass</title>
-
- <para>
- Uma terceira opção é mapear para tabelas apenas as classes concretas de
uma
- hierarquia de heranças, (a estratégia table-per-concrete-class) onde cada
tabela
- define todos os estados persistentes da classe, incluindo estados
herdados.
- No Hibernate, não é absolutamente necessário mapear explicitamente como
hierarquia
- de heranças. Você pode simplesmente mapear cada classe com uma declaração
- <literal><class></literal> separada. Porém, se
você deseja usar associações
- polimórficas (por exemplo: uma associação para a superclasse de sua
hierarquia),
- você precisa usar o mapeamento
<literal><union-subclass></literal>.
-
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="unionsubclass1" coords="2 45"/>
- <area id="unionsubclass2" coords="3 45"/>
- <area id="unionsubclass3" coords="4 45"/>
- <area id="unionsubclass4" coords="5 45"/>
- </areaspec>
- <programlisting><![CDATA[<union-subclass
- name="ClassName"
- table="tablename"
- proxy="ProxyInterface"
- lazy="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>]]></programlisting>
- <calloutlist>
- <callout arearefs="unionsubclass1">
- <para>
- <literal>name</literal>: O nome da subclasse
completamente qualificada.
- </para>
- </callout>
- <callout arearefs="unionsubclass2">
- <para>
- <literal>table</literal>: O nome da tabela da
subclasse.
- </para>
- </callout>
- <callout arearefs="unionsubclass3">
- <para>
- <literal>proxy</literal> (optional): Specifies a
class or interface to use
- for lazy initializing proxies.
-
- <literal>proxy</literal> (opcional): Especifica a
classe ou interface para usar
- os proxies de recuperação atrasada.
- </para>
- </callout>
- <callout arearefs="unionsubclass4">
- <para>
- <literal>lazy</literal> (optional, defaults to
<literal>true</literal>): Setting
- <literal>lazy="false"</literal>
disables the use of lazy fetching.
- <literal>lazy</literal> (opcional, valor default
p<literal>true</literal>):
- Fixando <literal>lazy="false"</literal>
desabilita o uso da recuperação atrasada.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- A coluna discriminatõria não é requerida para esta estratégia de
mapeamento.
-
- </para>
-
- <para>
- Para informações sobre mapeamentos de herança, veja <xref
linkend="inheritance"/>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-join" revision="3">
- <title>join</title>
-
- <para>
- Usando o elemento
<literal><join></literal>>, é possível mapear
- propriedades de uma classe para várias tabelas.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="join1" coords="2 50"/>
- <area id="join2" coords="3 50"/>
- <area id="join3" coords="4 50"/>
- <area id="join4" coords="5 50"/>
- <area id="join5" coords="6 50"/>
- <area id="join6" coords="7 50"/>
- </areaspec>
- <programlisting><![CDATA[<join
- table="tablename"
- schema="owner"
- catalog="catalog"
- fetch="join|select"
- inverse="true|false"
- optional="true|false">
-
- <key ... />
-
- <property ... />
- ...
-</join>]]></programlisting>
-
- <calloutlist>
- <callout arearefs="join1">
- <para>
- <literal>table</literal>: O nome da tabela
associada.
- </para>
- </callout>
- <callout arearefs="join2">
- <para>
- <literal>schema</literal> (opcional): Sobrepõe o
nome do esquema
- especificado pelo elemento raiz
<literal><hibernate-mapping></literal>.
- </para>
- </callout>
- <callout arearefs="join3">
- <para>
- <literal>catalog</literal> (opcional): Sobrepõe o
nome do catálogo
- especificado pelo elemento
raiz<literal><hibernate-mapping></literal>.
- </para>
- </callout>
- <callout arearefs="join4">
- <para>
- <literal>fetch</literal>(opcional – valor default
<literal>join</literal>): Se setado
- para <literal>join</literal>, o padrão, o
Hibernate irá usar um inner join para
- restaurar um <literal>join</literal> definido por
uma classe ou suas subclasses e
- uma outer join para um <literal>join</literal>
definido por uma subclasse.
- Se setado para <literal>select</literal>, então o
Hibernate irá usar uma seleção
- seqüencial para um
<literal><join></literal> definida numa subclasse, que irá
- ser emitido apenas se uma linha se concentrar para
representar uma instância
- da subclasse. Inner joins irá ainda ser usado para restaurar
um
- <literal><join></literal> definido
pela classe e suas superclasses.
- </para>
- </callout>
- <callout arearefs="join5">
- <para>
- <literal>inverse</literal> (opcional – valor
default <literal>false</literal>):
- Se habilitado, o Hibernate não irá tentar inserir ou
atualizar as propriedades
- definidas por este join.
- </para>
- </callout>
- <callout arearefs="join6">
- <para>
- <literal>optional</literal> (opcional – valor
default <literal>false</literal>):
- Se habilitado, o Hibernate irá inserir uma linha apenas se as
propriedades definidas
- por esta junção não forem nulas e irá sempre usar uma outer
join para
- recuperar as propriedades.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- 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):
- </para>
-
- <programlisting><![CDATA[<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>
- ...]]></programlisting>
-
- <para>
- Esta característica é útil apenas para modelos de dados legados, nós
recomendamos
- menos tabelas do que classes e um modelo de domínio bem granulado. Porém,
é
- útil para ficar trocando entre estratégias de mapeamento de herança
- numa hierarquia simples, como explicado mais a frente.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-declaration-key">
- <title>key</title>
-
- <para>
- Nós vimos que o elemento
<literal><key></literal> surgiu algumas vezes
- até agora. Ele aparece em qualquer lugar que o elemento pai define uma
junção
- para a nova tabela, e define a chave estrangeira para a tabela associada,
que
- referencia a chave primária da tabela original.
- </para>
-
- <programlistingco>
- <areaspec>
- <area id="key1" coords="2 50"/>
- <area id="key2" coords="3 50"/>
- <area id="key3" coords="4 50"/>
- <area id="key4" coords="5 50"/>
- <area id="key5" coords="6 50"/>
- <area id="key6" coords="7 50"/>
- </areaspec>
- <programlisting><![CDATA[<key
- column="columnname"
- on-delete="noaction|cascade"
- property-ref="propertyName"
- not-null="true|false"
- update="true|false"
- unique="true|false"
-/>]]></programlisting>
-
- <calloutlist>
- <callout arearefs="key1">
- <para>.
- <literal>column</literal> (opcional): O nome da
coluna da chave estrangeira.
- Isto também pode ser especificado por aninhamento de
elemento(s)
- <literal><column></literal>.
- </para>
- </callout>
- <callout arearefs="key2">
- <para>
- <literal>on-delete</literal> (opcional, valor
default <literal>noaction</literal>):
- Especifica se a constraint da chave estrangeira no banco de
dados esta
- habilitada para cascade delete .
- </para>
- </callout>
- <callout arearefs="key3">
- <para>
- <literal>property-ref</literal> (opcional):
Especifica que a chave estrangeira
- se refere a colunas que não são chave primária da tabela
original.
- (Util para base de dados legadas.)
- </para>
- </callout>
- <callout arearefs="key4">
- <para>
- <literal>not-null</literal> (opcional):
Especifica que a coluna da chave
- estrangeira não aceita valores nulos (isto é implícito em
qualquer momento
- que a chave estrangeira também fizer parte da chave
primária).
- </para>
- </callout>
- <callout arearefs="key5">
- <para>
- <literal>update</literal> (optional): Specifies
that the foreign key should never
- be updated (this is implied whenever the foreign key is also
part of the primary
- key).
- <literal>update</literal> (opcional): Especifica
que a chave estrangeira nunca
- deve ser atualizada (isto é implícito em qualquer momento que
a chave estrangeira
- também fizer parte da chave primária).
- </para>
- </callout>
- <callout arearefs="key6">
- <para>
- <literal>unique</literal> (opcional): Especifica
que a chave estrangeira deve ter
- uma constraint unique (sto é implícito em qualquer momento
que a chave estrangeira
- também fizer parte da chave primária).
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- <para>
- Nós recomendamos que para sistemas que a performance de delete seja
importante, todas as
- chaves deve ser definida
<literal>on-delete="cascade"</literal>, e o Hibernate irá usar
- uma constraint a nível de banco de dados <literal>ON CASCADE
DELETE</literal>, ao invés
- de muitas instruções <literal>DELETE</literal>. Esteja ciente
que esta característica é
- um atalho da estratégia usual de optimistic locking do Hibernate para
dados versionados.
- </para>
-
- <para>
- Os atributos <literal>not-null</literal> e
<literal>update</literal> são úteis quando
- estamos mapeamos uma associação unidirecional um para muitos. Se você
mapear uma
- asociação unidirecional um para muitos para uma chave estrangeira
non-nullable, você
- <emphasis>deve</emphasis> declarar a coluna chave usando
- <literal><key
not-null="true"></literal>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-column" revision="4">
- <title>elementos column e formula</title>
- <para>
- Qualquer elemento de mapeamente que aceita um atributo
<literal>column</literal> irá
- aceitar alternativamente um subelemento
<literal><column></literal>. Da mesma forma,
- <literal>formula</literal> é uma alternativa para o atributo
<literal>formula</literal>.
- </para>
-
- <programlisting><![CDATA[<column
- name="column_name"
- length="N"
- precision="N"
- scale="N"
- not-null="true|false"
- unique="true|false"
- unique-key="multicolumn_unique_key_name"
- index="index_name"
- sql-type="sql_type_name"
- check="SQL expression"
- default="SQL expression"/>]]></programlisting>
-
- <programlisting><![CDATA[<formula>SQL
expression</formula>]]></programlisting>
-
- <para>
- O atributo <literal>column</literal> e
<literal>formula</literal> podem até ser combinados
- dentro da mesma propriedade ou associação mapeando para expressar,
- por exemplo, associações exóticas.
- </para>
-
- <programlisting><![CDATA[<many-to-one
name="homeAddress" class="Address"
- insert="false" update="false">
- <column name="person_id" not-null="true"
length="10"/>
- <formula>'MAILING'</formula>
-</many-to-one>]]></programlisting>
-
- </sect2>
-
- <sect2 id="mapping-declaration-import">
- <title>import</title>
-
- <para>
- Suponha que a sua aplicação tem duas classes persistentes com o mesmo
nome, e você não quer
- especificar o nome qualificado (do pacote) nas queries do Hibernate. As
Classes devem
- ser "importadas" explicitamente, de preferência contando com
<literal>auto-import="true"</literal>.
- Você pode até importar classes e interfaces que não estão explicitamente
mapeadas.
- </para>
-
- <programlisting><![CDATA[<import
class="java.lang.Object"
rename="Universe"/>]]></programlisting>
-
- <programlistingco>
- <areaspec>
- <area id="import1" coords="2 40"/>
- <area id="import2" coords="3 40"/>
- </areaspec>
- <programlisting><![CDATA[<import
- class="ClassName"
- rename="ShortName"
-/>]]></programlisting>
- <calloutlist>
- <callout arearefs="import1">
- <para>
- <literal>class</literal>: O nome qualificado (do
pacote) de qualquer classe Java.
- </para>
- </callout>
- <callout arearefs="import2">
- <para>
- <literal>rename</literal> (opcional – valor
default, o nome da classe não
- qualificada): Um nome que pode ser usado numa linguagem de
consulta.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- </sect2>
-
- <sect2 id="mapping-types-anymapping" revision="2">
- <title>any</title>
-
- <para>
- Existe mais um tipo de propriedade de mapeamento. O elemento de
mapeamento
- <literal><any></literal> define uma associação
polimórfica para classes de múltiplas tabelas.
- Este tipo de mapeamento sempre requer mais de uma coluna. A primeira
coluna possui o tipo da entidade
- associada. A outra coluna que ficou possui o identificador. É impossível
especificar uma restrição
- de chave estrangeira para este tipo de associação, assim isto claramente
não é visto
- como um caminho usual para associações (polimórficas) de mapeamento. Você
deve usar este mapeamento
- apenas em casos muito especiais (exemplo: audit logs, dados de sessão do
usuário, etc).
-
- </para>
-
- <para>
- O atributo <literal>meta-type</literal> permite a aplicação
especificar um tipo adaptado
- que mapeia valores de colunas de banco de dados para classes
persistentes que tem propriedades
- identificadoras do tipo especificado através do
<literal>id-type</literal>. Você deve especificar
- o mapeamento de valores do meta-type para nome de classes.
- </para>
-
- <programlisting><![CDATA[<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>]]></programlisting>
-
- <programlistingco>
- <areaspec>
- <area id="any1" coords="2 50"/>
- <area id="any2" coords="3 50"/>
- <area id="any3" coords="4 50"/>
- <area id="any4" coords="5 50"/>
- <area id="any5" coords="6 50"/>
- <area id="any6" coords="7 50"/>
- </areaspec>
- <programlisting><![CDATA[<any
- name="propertyName"
- id-type="idtypename"
- meta-type="metatypename"
- cascade="cascade_style"
- access="field|property|ClassName"
- optimistic-lock="true|false"
->
- <meta-value ... />
- <meta-value ... />
- .....
- <column .... />
- <column .... />
- .....
-</any>]]></programlisting>
- <calloutlist>
- <callout arearefs="any1">
- <para>
- <literal>name</literal>: o nome da propriedade.
- </para>
- </callout>
- <callout arearefs="any2">
- <para>
- <literal>id-type</literal>: o tipo
identificador.
- </para>
- </callout>
- <callout arearefs="any3">
- <para>
- <literal>meta-type</literal> (opcional – valor
default <literal>string</literal>):
- Qualquer tipo que é permitido para um mapeamento
discriminador.
- </para>
- </callout>
- <callout arearefs="any4">
- <para>
- <literal>cascade</literal> (opcional – valor
default <literal>none</literal>):
- o estilo do cascade.
- </para>
- </callout>
- <callout arearefs="any5">
- <para>
- <literal>access</literal> (opcional – valor
default <literal>property</literal>):
- A estratégia que o hibernate deve usar para acessar o valor
da propriedade.
- </para>
- </callout>
- <callout arearefs="any6">
- <para>
- <literal>optimistic-lock</literal> (opcional -
valor default<literal>true</literal>):
- Especifica que as atualizações para esta propriedade requerem
ou não aquisição da
- trava otimista. Em outras palavras, define se uma versão de
incremento deve ocorrer
- se esta propriedade está modificada.
- </para>
- </callout>
- </calloutlist>
- </programlistingco>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="mapping-types">
- <title>Tipos do Hibernate</title>
-
- <sect2 id="mapping-types-entitiesvalues" revision="1">
- <title>Entidades e valores</title>
-
- <para>
- Para entender o comportamento de vários objetos em nível de linguagem de
Java a
- respeito do serviço de persistência, nós precisamos classificá-los em
dois grupos.
- </para>
-
- <para>
- Uma <emphasis>entidade </emphasis> 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 garbage collector.
Entidades
- devem ser explicitamente salvas ou deletada (exceto em operações de
salvamento
- ou deleção que possam ser executada em
<emphasis>cascata</emphasis> de uma entidade
- pai para seus filhos). Isto é diferente do modelo ODMG de persistência do
objeto
- por acessibilidade – e corresponde quase a como objetos de aplicações são
- geralmente usados em grandes sistemas. Entidades suportam referências
circulares
- e comuns. Eles podem ser versionadas.
- </para>
-
- <para>
- Uma entidade em estado persistente consiste de referências para outras
entidades
- e instâncias de tipos de <emphasis>valor</emphasis>. 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)
- <emphasis>são </emphasis> persistidos e apagados por
acessibilidade. Visto que
- objetos value (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.
-
- </para>
-
- <para>
- Até agora, nós estivemos usando o termo "classe persistente"
para referir
- a entidades. Nós iremos continuar a fazer isto. Falando a rigor, porém,
nem todas
- as classes definidas pelo usuário com estados persistentes são entidades.
Um
- <emphasis>componente</emphasis> é uma classe de usuário
definida com valores
- semânticos. Uma propriedade de Java de tipo
<literal>java.lang.String</literal>
- também tem um valor semêntico. Dada esta definição, nós podemos dizer que
- todos os tipos (classes) fornecida pelo JDK tem tipo de valor semântico
em Java,
- enquanto que tipos definidos pelo usuário pode 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 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 valor de tipo.
- </para>
-
- <para>
- Nós iremos rever ambos os conceitos durante toda a documentação.
-
- </para>
-
- <para>
- O desafio pe 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 é fornecido pelo Hibernate: para entidades que usam
- <literal><class></literal>,
<literal><subclass></literal> e assim por diante.
- Para tipos de valores nós usamos
<literal><property></literal>,
- <literal><component></literal>, etc, geralmente
com um atributo
- <literal>type</literal>. O valor deste atributo é o nome de
um <emphasis>tipo de
- mapeamento</emphasis> do Hibernate. O Hibernate fornece muitos
mapeamentos
- (para tipos de valores do JDK padrão) ut of the box. Você pode escrever
os seus
- próprios tipos de mapeamentos e implementar sua estratégia de conversão
adaptada,
- como você verá adiante.
- </para>
-
- <para>
- Todos os tipos internos do hibernate exceto coleções suportam semânticas
nulas.
-
- </para>
-
- </sect2>
-
- <sect2 id="mapping-types-basictypes" revision="3">
- <title>Valores de tipos básicos</title>
-
- <para>
- O tipos internos de mapeamentos básicos podem ser a grosso modo
categorizado como:
- <variablelist>
- <varlistentry>
- <term><literal>integer, long, short, float, double,
character, byte,
- boolean, yes_no, true_false</literal></term>
- <listitem>
- <para>
- Tipos de mapeamentos de classes primitivas ou wrapper
Java especificos
- (vendor-specific) para tipos de coluna SQL. Boolean,
- <literal>boolean, yes_no</literal> são todas
codificações alternativas
- para um <literal>boolean</literal> ou
<literal>java.lang.Boolean</literal>
- do Java.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>string</literal></term>
- <listitem>
- <para>
- Um tipo de mapeamento de
<literal>java.lang.String</literal> para
- <literal>VARCHAR</literal> (ou
<literal>VARCHAR2</literal> no Oracle).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>date, time,
timestamp</literal></term>
- <listitem>
- <para>
- Tipos de mapeamento de
<literal>java.util.Date</literal> e suas
- subclasses para os tipos SQL
<literal>DATE</literal>,
- <literal>TIME</literal> e
<literal>TIMESTAMP</literal>
- (ou equivalente).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>calendar,
calendar_date</literal></term>
- <listitem>
- <para>
- Tipo de mapeamento de
<literal>java.util.Calendar</literal> para
- os tipos SQL <literal>TIMESTAMP</literal> e
- <literal>DATE</literal> (ou equivalente).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>big_decimal,
big_integer</literal></term>
- <listitem>
- <para>
- Tipo de mapeamento de
<literal>java.math.BigDecimal</literal> and
- <literal>java.math.BigInteger</literal> para
<literal>NUMERIC</literal>
- (ou <literal>NUMBER</literal> no Oracle).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>locale, timezone,
currency</literal></term>
- <listitem>
- <para>
- Tipos de mapeamentos de
<literal>java.util.Locale</literal>,
- <literal>java.util.TimeZone</literal> e
<literal>java.util.Currency</literal>
- para <literal>VARCHAR</literal> (ou
<literal>VARCHAR2</literal> no Oracle).
- Instâncias de f <literal>Locale</literal> e
<literal>Currency</literal>
- são mapeados para seus códigos ISO. Instâncias de
<literal>TimeZone</literal>
- são mapeados para seu <literal>ID</literal>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>class</literal></term>
- <listitem>
- <para>
- um tipo de mapeamento de
<literal>java.lang.Class</literal> para
- <literal>VARCHAR</literal> (ou
<literal>VARCHAR2</literal> no
- Oracle). Uma <literal>Class</literal> é
mapeada pelo
- seu nome qualificado (completo).
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>binary</literal></term>
- <listitem>
- <para>
- Mapeia arrays de bytes para um tipo binário de SQL
apropriado.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>text</literal></term>
- <listitem>
- <para>
- Maps long Java strings to a SQL
<literal>CLOB</literal> or
- <literal>TEXT</literal> type.
- Mapeia strings longas de Java para um tipo SQL
- <literal>CLOB</literal> ou
<literal>TEXT</literal>.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
-
<term><literal>serializable</literal></term>
- <listitem>
- <para>
- Mapeia tipos Java serializáveis para um tipo binário SQL
apropriado.
- Você pode também indicar o tipo
<literal>serializable</literal> do
- Hibernate com o nome da classe ou interface Java
serializável que
- não é padrão para um tipo básico.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>clob,
blob</literal></term>
- <listitem>
- <para>
- Tipos de mapeamentos para as classes JDBC
<literal>java.sql.Clob</literal> and
- <literal>java.sql.Blob</literal>. Estes tipos
podem ser inconveniente para
- algumas aplicações, visto que o objeto blob ou clob pode
não ser reusado
- fora de uma transação. (Além disso, o suporte de driver é
imcompleto e
- inconsistente.)
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>
- <literal>imm_date, imm_time, imm_timestamp,
imm_calendar, imm_calendar_date,
- imm_serializable, imm_binary</literal>
- </term>
- <listitem>
- <para>
- Mapeando tipos para o que geralmente são consideradas
tipos mutáveis de
- Java, 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
<literal>Date.setTime()</literal> para
- uma instância mapeada como
<literal>imm_timestamp</literal>. Para mudar
- o valor da propriedade, e ter a mudança feita
persistente, a aplicação
- deve atribuir um novo objeto (nonidentical) à
propriedade.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- </para>
-
- <para>
- Identificadores únicos das entidades e coleções podem ser de qualquer
tipo
- básico exceto <literal>binary</literal>,
<literal>blob</literal> ou
- <literal>clob</literal>. (Identificadores compostos também
são permitidos,
- veja abaixo.)
- </para>
-
- <para>
- Os tipos de valores básicos têm suas constantes
<literal>Type</literal>
- correspondentes definidas em
<literal>org.hibernate.Hibernate</literal>. Por exemplo,
- <literal>Hibernate.STRING</literal> representa o tipo
<literal>string</literal>.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-types-custom" revision="2">
- <title>Tipos de valores personalizados</title>
-
- <para>
- É relativamente fácil para desenvolvedores criar seus próprios tipos de
valor.
- Por exemplo, você pode querer persistir propriedades do tipo
- <literal>java.lang.BigInteger</literal> para colunas
<literal>VARCHAR</literal>. 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ê pôde ter uma propriedade
Java
-
<literal>getName()</literal>/<literal>setName()</literal> do tipo
- <literal>java.lang.String</literal> que é persistido para
colunas
- <literal>FIRST_NAME</literal>,
<literal>INITIAL</literal>, <literal>SURNAME</literal>.
-
- </para>
-
- <para>
- Para implementar um tipo personalizado, implemente
<literal>org.hibernate.UserType</literal>
- or <literal>org.hibernate.CompositeUserType</literal> e
declare propriedades usando o nome
- qualificado da classe do tipo. Veja
<literal>org.hibernate.test.DoubleStringType</literal>
- para ver o tipo das coisas que são possíveis.
- </para>
-
- <programlisting><![CDATA[<property name="twoStrings"
type="org.hibernate.test.DoubleStringType">
- <column name="first_string"/>
- <column name="second_string"/>
-</property>]]></programlisting>
-
- <para>
- Observe o uso da tag
<literal><column></literal> para mapear uma propriedade
- para colunas múltiplas.
- </para>
-
- <para>
- As interfaces <literal>CompositeUserType</literal>,
<literal>EnhancedUserType</literal>,
- <literal>UserCollectionType</literal>, e
<literal>UserVersionType</literal>
- fornecem suporte para usos mais especializados.
- </para>
-
- <para>
- Você pode mesmo fornecer parâmetros a um
<literal>UserType</literal> no arquivo de mapeamento.
- Para isto, seu <literal>UserType</literal> deve implementar a
interface
- <literal>org.hibernate.usertype.ParameterizedType</literal>.
Para fornecer parâmetros a seu
- tipo personalizado, você pode usar o elemento
<literal><type></literal> em seus
- arquivos de mapeamento.
- </para>
-
- <programlisting><![CDATA[<property name="priority">
- <type name="com.mycompany.usertypes.DefaultValueIntegerType">
- <param name="default">0</param>
- </type>
-</property>]]></programlisting>
-
- <para>
- O <literal>UserType</literal> pode agora recuperar o valor
para o parâmetro chamado
- <literal>default</literal> da
<literal>Propriedade</literal> do passado a ele.
- </para>
-
- <para>
- Se você usar freqüentemente um determinado
<literal>UserType</literal>, pode ser útil definir
- um nome mais curto para ele. Você pode fazer isto usando o elemento
- <literal><typedef></literal>. Typedefs atribui
um nome a um tipo personalizado, e pode também
- conter uma lista de valores default de parâmetro se o tipo for
parametrizado.
- </para>
-
- <programlisting><![CDATA[<typedef
class="com.mycompany.usertypes.DefaultValueIntegerType"
name="default_zero">
- <param name="default">0</param>
-</typedef>]]></programlisting>
-
- <programlisting><![CDATA[<property name="priority"
type="default_zero"/>]]></programlisting>
-
- <para>
- It is also possible to override the parameters supplied in a typedef on a
case-by-case basis
- by using type parameters on the property mapping.
- </para>
-
- <para>
- Even though Hibernate's rich range of built-in types and support for
components means you
- will very rarely <emphasis>need</emphasis> to use a custom
type, it is nevertheless
- considered good form to use custom types for (non-entity) classes that
occur frequently
- in your application. For example, a
<literal>MonetaryAmount</literal> class is a good
- candidate for a <literal>CompositeUserType</literal>, even
though it could easily be mapped
- as a component. One motivation for this is abstraction. With a custom
type, your mapping
- documents would be future-proofed against possible changes in your way of
representing
- monetary values.
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="mapping-entityname">
- <title>Mapping a class more than once</title>
- <para>
- It is possible to provide more than one mapping for a particular persistent
class. In this
- case you must specify an <emphasis>entity name</emphasis> do
disambiguate between instances
- of the two mapped entities. (By default, the entity name is the same as the
class name.)
- Hibernate lets you specify the entity name when working with persistent
objects, when writing
- queries, or when mapping associations to the named entity.
- </para>
-
- <programlisting><![CDATA[<class name="Contract"
table="Contracts"
- entity-name="CurrentContract">
- ...
- <set name="history" inverse="true"
- order-by="effectiveEndDate desc">
- <key column="currentContractId"/>
- <one-to-many entity-name="HistoricalContract"/>
- </set>
-</class>
-
-<class name="Contract" table="ContractHistory"
- entity-name="HistoricalContract">
- ...
- <many-to-one name="currentContract"
- column="currentContractId"
- entity-name="CurrentContract"/>
-</class>]]></programlisting>
-
- <para>
- Notice how associations are now specified using
<literal>entity-name</literal> instead of
- <literal>class</literal>.
- </para>
-
- </sect1>
-
- <sect1 id="mapping-quotedidentifiers">
- <title>SQL quoted identifiers</title>
- <para>
- You may force Hibernate to quote an identifier in the generated SQL by
enclosing the table or
- column name in backticks in the mapping document. Hibernate will use the
correct quotation
- style for the SQL <literal>Dialect</literal> (usually double
quotes, but brackets for SQL
- Server and backticks for MySQL).
- </para>
-
- <programlisting><![CDATA[<class name="LineItem"
table="`Line Item`">
- <id name="id" column="`Item Id`"/><generator
class="assigned"/></id>
- <property name="itemNumber" column="`Item #`"/>
- ...
-</class>]]></programlisting>
-
- </sect1>
-
-
- <sect1 id="mapping-alternatives">
- <title>Metadata alternatives</title>
-
- <para>
- XML isn't for everyone, and so there are some alternative ways to define O/R
mapping metadata in Hibernate.
- </para>
-
- <sect2 id="mapping-xdoclet">
- <title>Using XDoclet markup</title>
-
- <para>
- Many Hibernate users prefer to embed mapping information directly in
sourcecode using
- XDoclet <literal>(a)hibernate.tags</literal>. We will not cover
this approach in this
- document, since strictly it is considered part of XDoclet. However, we
include the
- following example of the <literal>Cat</literal> class with
XDoclet mappings.
- </para>
-
- <programlisting><![CDATA[package eg;
-import java.util.Set;
-import java.util.Date;
-
-/**
- * @hibernate.class
- * table="CATS"
- */
-public class Cat {
- private Long id; // identifier
- private Date birthdate;
- private Cat mother;
- private Set kittens
- private Color color;
- private char sex;
- private float weight;
-
- /*
- * @hibernate.id
- * generator-class="native"
- * column="CAT_ID"
- */
- public Long getId() {
- return id;
- }
- private void setId(Long id) {
- this.id=id;
- }
-
- /**
- * @hibernate.many-to-one
- * column="PARENT_ID"
- */
- public Cat getMother() {
- return mother;
- }
- void setMother(Cat mother) {
- this.mother = mother;
- }
-
- /**
- * @hibernate.property
- * column="BIRTH_DATE"
- */
- public Date getBirthdate() {
- return birthdate;
- }
- void setBirthdate(Date date) {
- birthdate = date;
- }
- /**
- * @hibernate.property
- * column="WEIGHT"
- */
- public float getWeight() {
- return weight;
- }
- void setWeight(float weight) {
- this.weight = weight;
- }
-
- /**
- * @hibernate.property
- * column="COLOR"
- * not-null="true"
- */
- public Color getColor() {
- return color;
- }
- void setColor(Color color) {
- this.color = color;
- }
- /**
- * @hibernate.set
- * inverse="true"
- * order-by="BIRTH_DATE"
- * @hibernate.collection-key
- * column="PARENT_ID"
- * @hibernate.collection-one-to-many
- */
- public Set getKittens() {
- return kittens;
- }
- void setKittens(Set kittens) {
- this.kittens = kittens;
- }
- // addKitten not needed by Hibernate
- public void addKitten(Cat kitten) {
- kittens.add(kitten);
- }
-
- /**
- * @hibernate.property
- * column="SEX"
- * not-null="true"
- * update="false"
- */
- public char getSex() {
- return sex;
- }
- void setSex(char sex) {
- this.sex=sex;
- }
-}]]></programlisting>
-
- <para>
- See the Hibernate web site for more examples of XDoclet and Hibernate.
- </para>
-
- </sect2>
-
- <sect2 id="mapping-annotations" revision="2">
- <title>Using JDK 5.0 Annotations</title>
-
- <para>
- JDK 5.0 introduced XDoclet-style annotations at the language level, type-safe
and
- checked at compile time. This mechnism is more powerful than XDoclet
annotations and
- better supported by tools and IDEs. IntelliJ IDEA, for example, supports
auto-completion
- and syntax highlighting of JDK 5.0 annotations. The new revision of the EJB
specification
- (JSR-220) uses JDK 5.0 annotations as the primary metadata mechanism for
entity beans.
- Hibernate3 implements the <literal>EntityManager</literal> of
JSR-220 (the persistence API),
- support for mapping metadata is available via the <emphasis>Hibernate
Annotations</emphasis>
- package, as a separate download. Both EJB3 (JSR-220) and Hibernate3 metadata
is supported.
- </para>
-
- <para>
- This is an example of a POJO class annotated as an EJB entity bean:
- </para>
-
- <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
-public class Customer implements Serializable {
-
- @Id;
- Long id;
-
- String firstName;
- String lastName;
- Date birthday;
-
- @Transient
- Integer age;
-
- @Embedded
- private Address homeAddress;
-
- @OneToMany(cascade=CascadeType.ALL)
- @JoinColumn(name="CUSTOMER_ID")
- Set<Order> orders;
-
- // Getter/setter and business methods
-}]]></programlisting>
-
- <para>
- Note that support for JDK 5.0 Annotations (and JSR-220) is still work in
progress and
- not completed. Please refer to the Hibernate Annotations module for more
details.
- </para>
-
- </sect2>
- </sect1>
-
- <sect1 id="mapping-generated" revision="1">
- <title>Generated Properties</title>
- <para>
- Generated properties are properties which have their values generated by the
- database. Typically, Hibernate applications needed to
<literal>refresh</literal>
- objects which contain any properties for which the database was generating
values.
- Marking properties as generated, however, lets the application delegate this
- responsibility to Hibernate. Essentially, whenever Hibernate issues an SQL
INSERT
- or UPDATE for an entity which has defined generated properties, it
immediately
- issues a select afterwards to retrieve the generated values.
- </para>
- <para>
- Properties marked as generated must additionally be non-insertable and
non-updateable.
- Only <xref
linkend="mapping-declaration-version">versions</xref>,
- <xref
linkend="mapping-declaration-timestamp">timestamps</xref>, and
- <xref linkend="mapping-declaration-property">simple
properties</xref> can be marked as
- generated.
- </para>
- <para>
- <literal>never</literal> (the default) - means that the given property
value
- is not generated within the database.
- </para>
- <para>
- <literal>insert</literal> - states that the given property value is
generated on
- insert, but is not regenerated on subsequent updates. Things like created-date
would
- fall into this category. Note that even thought
- <xref linkend="mapping-declaration-version">version</xref>
and
- <xref
linkend="mapping-declaration-timestamp">timestamp</xref> properties
can
- be marked as generated, this option is not available there...
- </para>
- <para>
- <literal>always</literal> - states that the property value is generated
both
- on insert and on update.
- </para>
- </sect1>
-
- <sect1 id="mapping-database-object">
- <title>Auxiliary Database Objects</title>
- <para>
- Allows CREATE and DROP of arbitrary database objects, in conjunction with
- Hibernate's schema evolution tools, to provide the ability to fully
define
- a user schema within the Hibernate mapping files. Although designed
specifically
- for creating and dropping things like triggers or stored procedures, really
any
- SQL command that can be run via a
<literal>java.sql.Statement.execute()</literal>
- method is valid here (ALTERs, INSERTS, etc). There are essentially two modes
for
- defining auxiliary database objects...
- </para>
- <para>
- The first mode is to explicitly list the CREATE and DROP commands out in the
mapping
- file:
- </para>
- <programlisting><![CDATA[<hibernate-mapping>
- ...
- <database-object>
- <create>CREATE TRIGGER my_trigger ...</create>
- <drop>DROP TRIGGER my_trigger</drop>
- </database-object>
-</hibernate-mapping>]]></programlisting>
- <para>
- The second mode is to supply a custom class which knows how to construct the
- CREATE and DROP commands. This custom class must implement the
- <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal>
interface.
- </para>
- <programlisting><![CDATA[<hibernate-mapping>
- ...
- <database-object>
- <definition class="MyTriggerDefinition"/>
- </database-object>
-</hibernate-mapping>]]></programlisting>
- <para>
- Additionally, these database objects can be optionally scoped such that they
only
- apply when certain dialects are used.
- </para>
- <programlisting><![CDATA[<hibernate-mapping>
- ...
- <database-object>
- <definition class="MyTriggerDefinition"/>
- <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
- <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
- </database-object>
-</hibernate-mapping>]]></programlisting>
- </sect1>
-</chapter>
-
+<chapter id="mapping">
+ <title>Mapeamento O/R Bassico</title>
+
+ <sect1 id="mapping-declaration" revision="1">
+ <title>Declaração de mapeamento</title>
+
+ <para>
+ Object/relational mappings are usually defined in an XML document. The
mapping
+ document is designed to be readable and hand-editable. The mapping language
is
+ Java-centric, meaning that mappings are constructed around persistent class
+ declarations, not table declarations.
+ </para>
+
+ <para>
+ Note that, even though many Hibernate users choose to write the XML by hand,
+ a number of tools exist to generate the mapping document, including XDoclet,
+ Middlegen and AndroMDA.
+ </para>
+
+ <para>
+ Lets kick off with an example mapping:
+ </para>
+
+ <programlisting id="mapping-declaration-ex1"
revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/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>]]></programlisting>
+
+ <para>
+ Discutir agora o conteúdo deste documento de mapeamento. Iremos apenas
descrever
+ os elementos do documento e atributos que são utilizados pelo Hibernate em
tempo
+ de execução. O documento de mapeamento também contém alguns atributos
adicionais
+ e opcionais além de elementos que afetam os esquemas de banco de dados
exportados
+ pela ferramenta de exportação de esquemas. (Por exemplo, o atributo
+ <literal>not-null</literal>).
+ </para>
+
+
+
+ <sect2 id="mapping-declaration-doctype" revision="3">
+ <title>Doctype</title>
+
+ <para>
+ Todos os mapeamentos de XML devem declarar o doctype exibido. O DTD atual
pode
+ ser encontrado na URL abaixo, no diretório
<literal>hibernate-x.x.x/src/org/
+ hibernate </literal> ou no
<literal>hibernate3.jar</literal>. 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
+ </para>
+
+ <sect3 id="mapping-declaration-entity-resolution">
+ <title>EntityResolver</title>
+ <para>
+ As mentioned previously, Hibernate will first attempt to resolve DTDs
in its classpath. The
+ manner in which it does this is by registering a custom
<literal>org.xml.sax.EntityResolver</literal>
+ implementation with the SAXReader it uses to read in the xml files.
This custom
+ <literal>EntityResolver</literal> recognizes two
different systemId namespaces.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ a <literal>hibernate namespace</literal> is
recognized whenever the
+ resolver encounteres a systemId starting with
+
<
literal>http://hibernate.sourceforge.net/</literal>; the resolver
+ attempts to resolve these entities via the classlaoder which
loaded
+ the Hibernate classes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a <literal>user namespace</literal> is recognized
whenever the
+ resolver encounteres a systemId using a
<literal>classpath://</literal>
+ URL protocol; the resolver will attempt to resolve these
entities
+ via (1) the current thread context classloader and (2) the
+ classloader which loaded the Hibernate classes.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ An example of utilizing user namespacing:
+ </para>
+ <programlisting><![CDATA[<?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>]]></programlisting>
+ <para>
+ Where <literal>types.xml</literal> is a resource in the
<literal>your.domain</literal>
+ package and contains a custom <xref
linkend="mapping-types-custom">typedef</xref>.
+ </para>
+ </sect3>
+ </sect2>
+
+ <sect2 id="mapping-declaration-mapping" revision="3">
+ <title>hibernate-mapping</title>
+
+ <para>
+ Este elemento tem diversos atributos opcionais. Os atributos
+ <literal>schema</literal> e
<literal>catalog</literal> especificam que tabelas
+ referenciadas neste mapeamento pertencem ao esquema e/ou ao catalogo
nomeado.
+ Se especificados, os nomes das tabelas irão ser qualificados no schema ou
catalog dado.
+ Se não, os nomes das tabelas não serão qualificados. O atributo
<literal>default-cascade
+ </literal> especifica qual estilo de cascata será assumido pelas
propriedades e
+ coleções que não especificarm um atributo
<literal>cascade</literal>. O atributo
+ <literal>auto-import</literal> nos deixa utilizar nomes de
classes não qualificados
+ na linguagem de consulta, por default.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="hm1" coords="2 55"/>
+ <area id="hm2" coords="3 55"/>
+ <area id="hm3" coords="4 55"/>
+ <area id="hm4" coords="5 55"/>
+ <area id="hm5" coords="6 55"/>
+ <area id="hm6" coords="7 55"/>
+ <area id="hm7" coords="8 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<hibernate-mapping
+ schema="schemaName"
+ catalog="catalogName"
+ default-cascade="cascade_style"
+ default-access="field|property|ClassName"
+ default-lazy="true|false"
+ auto-import="true|false"
+ package="package.name"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="hm1">
+ <para>
+ <literal>schema</literal> (opcional): O nome do
esquema do banco de dados.
+ </para>
+ </callout>
+ <callout arearefs="hm2">
+ <para>
+ <literal>catalog</literal> (opcional): O nome
do catálogo do banco de dados.
+ </para>
+ </callout>
+ <callout arearefs="hm3">
+ <para>
+ <literal>default-cascade</literal> (opcional –
default é <literal>nenhum
+ </literal>): Um estilo cascata default.
+ </para>
+ </callout>
+ <callout arearefs="hm4">
+ <para>
+ <literal>default-access</literal> (opcional –
default é <literal>property</literal>):
+ A estratégia que o Hibernate deve utilizar para acessar
todas as propridades. Pode
+ ser uma implementação própria de
<literal>PropertyAccessor</literal>.
+ </para>
+ </callout>
+ <callout arearefs="hm5">
+ <para>
+ <literal>default-lazy</literal> (opcional -
default é <literal>true</literal>):
+ O valor default para atributos
<literal>lazy</literal> da classe e dos
+ mapeamentos de coleções.
+ </para>
+ </callout>
+ <callout arearefs="hm6">
+ <para>
+ <literal>auto-import</literal> ((opcional -
default é <literal>true</literal>):
+ Especifica se nós podemos usar nomes de classess não
qualificados
+ (das classes deste mapeamento) na linguagem de consulta.
+ </para>
+ </callout>
+ <callout arearefs="hm7">
+ <para>
+ <literal>package</literal> (opcional):
Especifica um prefixo da package para
+ assumir para nomes de classes não qualificadas no documento
de mapeamento.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Se voce tem duas classes persistentes com o mesmo nome (não
qualificadas), você deve
+ setar <literal>auto-import="false"</literal>. O
Hibernate irá gerar uma exceção se
+ você tentar setar duas classes para o mesmo nome "importado".
+ </para>
+
+ <para>
+ Observe que o elemento <literal>hibernate-mapping</literal>
permite a você
+ aninhar diversos mapeamentos de
<literal><class></literal> 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 nomea-la
após
+ a superclasse persistente, por exemplo:
<literal>Cat.hbm.xml</literal>,
+ <literal>Dog.hbm.xml</literal>, ou se estiver usando
herança,
+ <literal>Animal.hbm.xml</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-class" revision="3">
+ <title>class</title>
+
+ <para>
+ Você pode declarar uma classe persistente utilizando o elemento
+ <literal>class</literal>:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="class1" coords="2 55"/>
+ <area id="class2" coords="3 55" />
+ <area id="class3" coords="4 55"/>
+ <area id="class4" coords="5 55" />
+ <area id="class5" coords="6 55"/>
+ <area id="class6" coords="7 55" />
+ <area id="class7" coords="8 55"/>
+ <area id="class8" coords="9 55" />
+ <area id="class9" coords="10 55" />
+ <area id="class10" coords="11 55"/>
+ <area id="class11" coords="12 55"/>
+ <area id="class12" coords="13 55"/>
+ <area id="class13" coords="14 55"/>
+ <area id="class14" coords="15 55"/>
+ <area id="class15" coords="16 55"/>
+ <area id="class16" coords="17 55"/>
+ <area id="class17" coords="18 55"/>
+ <area id="class18" coords="19 55"/>
+ <area id="class19" coords="20 55"/>
+ <area id="class20" coords="21 55"/>
+ <area id="class21" coords="22 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<class
+ name="ClassName"
+ table="tableName"
+ discriminator-value="discriminator_value"
+ mutable="true|false"
+ schema="owner"
+ catalog="catalog"
+ proxy="ProxyInterface"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ select-before-update="true|false"
+ polymorphism="implicit|explicit"
+ where="arbitrary sql where condition"
+ persister="PersisterClass"
+ batch-size="N"
+ optimistic-lock="none|version|dirty|all"
+ lazy="true|false"
+ entity-name="EntityName"
+ check="arbitrary sql check condition"
+ rowid="rowid"
+ subselect="SQL expression"
+ abstract="true|false"
+ node="element-name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="class1">
+ <para>
+ <literal>name</literal> (opcional): O nome da
classe Java inteiramente qualificado
+ da classe persistente (ou interface); Se o atributo é
ausente, assume-se que o
+ mapeamento é para intidades não-POJO.
+ </para>
+ </callout>
+ <callout arearefs="class2">
+ <para>
+ <literal>table</literal> (opcional – default para
nomes de classes não
+ qualificadas) O nome da sua tabela do banco de dados.
+ </para>
+ </callout>
+ <callout arearefs="class3">
+ <para>
+ <literal>discriminator-value</literal> (opcional
– default para o nome da classe):
+ Um valor que distingue subclasses individuais, usadas para o
comportamento polimorfico.
+ Valores aceitos incluem <literal>null</literal> e
<literal>not null</literal>
+ </para>
+ </callout>
+ <callout arearefs="class4">
+ <para>
+ <literal>mutable</literal> (opcional - valor
default <literal>true</literal>):
+ Especifica que instancias da classe são (ou não) mutáveis
+ </para>
+ </callout>
+ <callout arearefs="class5">
+ <para>
+ <literal>schema</literal> (opcional): Sobrepõe o
nome do esquema especificado
+ pelo elemento root
<literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="class6">
+ <para>
+ <literal>catalog</literal> (opcional): Sobrepõe o
nome do catálogo especificado
+ pelo elemento root
<literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="class7">
+ <para>
+ <literal>proxy</literal> (opcional): Especifica
um interface para ser
+ utilizada pelos proxies de inicialização tardia. Você pode
especificar o
+ nome da própria classe.
+ </para>
+ </callout>
+ <callout arearefs="class8">
+ <para>
+ <literal>dynamic-update</literal> (opcional,
valor default <literal>false</literal>):
+ Especifica que o SQL de <literal>UPDATE</literal>
deve ser gerado em tempo de
+ execução e conter apenas aquelas colunas cujos valores foram
alterados.
+ </para>
+ </callout>
+ <callout arearefs="class9">
+ <para>
+ <literal>dynamic-insert</literal> (opcional,
valor default <literal>false</literal>):
+ Especifica que o SQL de
<literal>INSERT</literal> deve ser gerado em tempo de
+ execução e conter apenas aquelas colunas cujos valores não
estão nulos.
+ </para>
+ </callout>
+ <callout arearefs="class10">
+ <para>
+ <literal>select-before-update</literal>
(opcional, valor default <literal>false</literal>):
+ Especifica que o Hibernate
<emphasis>never</emphasis> deve executar um SQL de
+ <literal>UPDATE</literal> a não ser que com
certeza um objeto está atualmente modificado.
+ Em certos casos (atualmente, apenas quando um objeto
transiente foi associado com uma nova
+ sessão utilizando <literal>update()</literal>),
isto significa que o Hibernate ira executar
+ uma instrução SQL de <literal>SELECT</literal>
adicional para determinar se um
+ <literal>UPDATE</literal> é necessário nesse
momento.
+ </para>
+ </callout>
+ <callout arearefs="class11">
+ <para>
+ <literal>polymorphism</literal> (opcional,
default para <literal>implicit</literal>):
+ Determina se deve ser utilizado a query polimorfica implicita
ou explicitamente.
+ </para>
+ </callout>
+ <callout arearefs="class12">
+ <para>
+ <literal>where</literal> (opicional) especifica
um comando SQL <literal>WHERE</literal>
+ arbitrário para ser usado quando da recuperação de objetos
desta classe.
+ </para>
+ </callout>
+ <callout arearefs="class13">
+ <para>
+ <literal>persister</literal> (opcional):
Espeicifca uma <literal>ClassPersister</literal>
+ customizada.
+ </para>
+ </callout>
+ <callout arearefs="class14">
+ <para>
+ <literal>batch-size</literal> (opcional, valor
default <literal>1</literal>) especifica um
+ "tamanho de lote" para a recuperação de instancias
desta classe pelo identificador.
+ </para>
+ </callout>
+ <callout arearefs="class15">
+ <para>
+ <literal>optimistic-lock</literal> (octional,
valor default <literal>version</literal>):
+ Determina a estratégia de bloqueio.
+ </para>
+ </callout>
+ <callout arearefs="class16">
+ <para>
+ <literal>lazy</literal> (opcional): A recuperação
tardia pode ser completamente
+ desabilitada, setando
<literal>lazy="false"</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class17">
+ <para>
+ <literal>entity-name</literal> (opcional, default
para o nome da classe): O
+ Hibernate3 permite uma classe ser mapeada multiplas vezes,
(potencialmente,para
+ diferentes tabelas), e permite mapeamentos de entidades que
são representadas
+ por Maps ou XML no nível Java. Nestes casos, você deve
especificar um nome
+ arbitrário explicitamente para a entidade. Veja <xref
linkend="persistent-classes-dynamicmodels"/>
+ e <xref linkend="xml"/> para maiores
informações.
+ </para>
+ </callout>
+ <callout arearefs="class18">
+ <para>
+ <literal>check</literal> (opcional): Uma
expressão SQL utilizada para gerar uma
+ constraint de <emphasis>verificação</emphasis> de
múltiplas linhas para a geração
+ automática do esquema.
+ </para>
+ </callout>
+ <callout arearefs="class19">
+ <para>
+ <literal>rowid</literal> (opcional): O Hibernate
poder usar as assim 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
<literal>rowid</literal>. Um ROWID é uma implementação
+ que representa de maneira detalhada a localização física de
uma determinada
+ tupla armazenado.
+ </para>
+ </callout>
+ <callout arearefs="class20">
+ <para>
+ <literal>subselect</literal> (optional): Maps an
immutable and read-only entity
+ to a database subselect. Useful if you want to have a view
instead of a base table,
+ but don't. See below for more information.
+ <literal>subselect</literal> (opcional): Mapeia
uma entidade imutavel e somente
+ de leitura para um subconjunto do banco de dados. Útil se
você quiser ter uma
+ view em vez de uma tabela. Veja abaixo para mais
informações.
+ </para>
+ </callout>
+ <callout arearefs="class21">
+ <para>
+ <literal>abstract</literal> (opcional): Utilizada
para marcar superclasses
+ abstratas em hierarquias
<literal><union-subclass></literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ É perfeitamente aceitável para uma classe persitente nomeada ser uma
interface. Você deverá
+ então declarar as classes implementadas desta interface utilizando o
elemento
+ <literal><subclass></literal>. Você pode
persistir qualquer classe de aninhada
+ <emphasis>estatica</emphasis>. Você deverá especificar o nome
da classe usando a forma
+ padrão, por exemplo: <literal>eg.Foo$Bar</literal>.
+ </para>
+
+ <para>
+ Classes imutáveis,
<literal>mutable="false"</literal>, não podem ser modificadas ou
excluídas
+ pela aplicação. Isso permite ao Hibernate fazer alguns aperfeiçoamentos
de performance.
+ </para>
+
+ <para>
+ O atributo opcional <literal>proxy</literal> habilita a
inicialização tardia das
+ instâncias persistentes da classe. O Hibernate irá retornar CGLIB proxies
como implementado
+ na interface nomeada. O objeto persistente atual será carregado quando
um método do proxy
+ for invocado. Veja "Inicializando coleções e proxies" abaixo.
+ </para>
+
+ <para>Polimorfismo <emphasis>implícito</emphasis> significa
que instâncias de uma classe
+ serão retornada por uma query que dá nome a qualquer superclasse ou
interface implementada,
+ ou a classe e as instancias de qualquer subclasse da classe será
retornada por umq query
+ que nomeia a classe por si. Polimorfismo
<emphasis>explícito</emphasis> significa que
+ instancias da classe serão retornadas apenas por queries que
explicitamente nomeiam a
+ classe e que queries que nomeiam as classes irão retornar apenas
instancias de subclasses
+ mapeadas dentro da declaração
<literal><class></literal> como uma
+ <literal><subclass></literal> ou
<literal><joined-subclass></literal>.
+ Para a maioria dos casos, o valor default
<literal>polymorphism="implicit"</literal>,
+ é apropriado. Polimorfismo explicito é útil quando duas classes distintas
estão mapeadas
+ para a mesma tabela (isso permite um classe "peso leve" que
contem um subconjunto
+ de colunas da tabela).
+ </para>
+
+ <para>
+ O atributo <literal>persister</literal> deixa você customizar
a estratégia de persistência
+ utilizada para a classe. Você pode, por exemplo, especificar sua prórpia
subclasse do
+ <literal>org.hibernate.persister.EntityPersister</literal> ou
você pode criar
+ uma implementação completamente nova da interface
+ <literal>org.hibernate.persister.ClassPersister</literal> que
implementa a persistência
+ através de, por exemplo, chamadas a stored procedeures, serialização de
arquivos flat ou
+ LDAP. Veja
<literal>org.hibernate.test.CustomPersister</literal> para um exemplo
+ simples (de "persistencia" para uma
<literal>Hashtable</literal>).
+ </para>
+
+ <para>
+ Observe que as configurações
<literal>dynamic-update</literal> e
+ <literal>dynamic-insert</literal> não sao herdadas pelas
subclasses e assim podem tambem
+ ser especificadas em elementos
<literal><subclass></literal> or
+ <literal><joined-subclass></literal>. Estas
configurações podem incrementar a
+ performance em alguns casos, mas pode realmente diminuir a performance em
outras.
+ Use-as de forma bastante criteriosa.
+ </para>
+
+ <para>
+ O uso de <literal>select-before-update</literal> geralmente
irá diminuir a performance. Ela é
+ muito útil para prevenir que uma trigger de atualização no banco de dados
seja ativada
+ desnecessariamente, se você reconectar um nó de uma instancia
desconectada em uma
+ <literal>Session</literal>.
+ </para>
+
+ <para>
+ Se você ativar <literal>dynamic-update</literal>, você terá
de escolher
+ a estratégia de bloqueio otimista:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>version</literal> verifica a versão e a hora
das colunas
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>all</literal> cverifica todas as colunas
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>dirty</literal> verifica as colunas
modificadas, permitindo
+ alguns updates concorrentes
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>none</literal> não utiliza o bloqueio
otimista
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Nós <emphasis>recomendamos</emphasis> com muita enfase que
você utilize a
+ versão e a hora das colunas para o bloqueio otimista com o Hibernate.
+ Esta é a melhor estratégia com respeito a performance e é a única
estratégia
+ que trata corretamente as modificações efetuadas em instancias
desconectadas
+ (por exemplo, quando <literal>Session.merge()</literal> é
utilizado).
+
+ </para>
+
+ <para>
+ Não ha diferença entre uma view e uma tabela para o mapeamento do
Hibernate, e como
+ esperado isto é transparente no nível do banco de dados (observe que
alguns bancos de
+ dados não suportam views apropriadamente, especialmente com updates).
Algumas vezes,
+ você quer utilizar uma view, ma snão pode cria-la no banco de dados (por
exemplo,
+ com um esquema legado). Neste caso, você pode mapear uma entidade
imutável e de
+ somente leitura, para uma dada expressão SQL, que representa um
subselect:
+ </para>
+
+ <programlisting><![CDATA[<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>]]></programlisting>
+
+ <para>
+ Declare as tabelas para sincronizar com esta entidade, garantindo que o
auto-flush
+ ocorra corretamente, e que as queries para esta entidade derivada não
retornem dados
+ desatualizados. O
<literal><subselect></literal> está disponível tanto como um
+ atributo como um elemento mapeado nested.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-id" revision="4">
+ <title>id</title>
+
+ <para>
+ Classes mapeadas <emphasis>precisam</emphasis> declarar a
coluna de chave primaria da
+ tabela do banco de dados. Muitas classes irão tambem ter uma propriedade
ao estilo
+ Java-Beans declarando o identificador unico de uma instancia. O elemento
+ <literal><id></literal> define o mapeamento
desta propriedade para a chave primária.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="id1" coords="2 70"/>
+ <area id="id2" coords="3 70" />
+ <area id="id3" coords="4 70"/>
+ <area id="id4" coords="5 70" />
+ <area id="id5" coords="6 70" />
+ </areaspec>
+ <programlisting><![CDATA[<id
+ name="propertyName"
+ type="typename"
+ column="column_name"
+ unsaved-value="null|any|none|undefined|id_value"
+ access="field|property|ClassName">
+ node="element-name|@attribute-name|element/(a)attribute|."
+
+ <generator class="generatorClass"/>
+</id>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="id1">
+ <para>
+ <literal>name</literal> (opcional): O nome do
identificador.
+ </para>
+ </callout>
+ <callout arearefs="id2">
+ <para>
+ <literal>type</literal> (opcional): Um nome que
indica o tipo no Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="id3">
+ <para>
+ <literal>column</literal> (opcional – default
para o a propridade name): O
+ nome coluna chave primaria.
+ </para>
+ </callout>
+ <callout arearefs="id4">
+ <para>
+ <literal>unsaved-value</literal> (opcional -
default para um valor "sensível"):
+ Uma propriedade de identificação que indica que a instancia
foi novamente
+ instanciada (unsaved), diferenciando de instancias
desconectadas que foram
+ salvas ou carregadas em uma sessão anterior.
+ </para>
+ </callout>
+ <callout arearefs="id5">
+ <para>
+ <literal>access</literal> (opcional - valor
default <literal>property</literal>): A
+ estratégia que o Hiberante deve utilizar para acessar o valor
da propriedade
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Se o atributo <literal>name</literal> não for declarado,
assume-se que a classe não tem
+ a propriedade de identificação.
+ </para>
+
+ <para>
+ O atributo <literal>unsaved-value</literal> não é mais
necessário no Hibernate 3.
+ </para>
+
+ <para>
+ Há declaração alternativa
<literal><composite-id></literal> permite o acesso a
+ dados legados com chaves compostas. Nós desencorajamos fortemente o seu
uso por
+ qualquer pessoa.
+ </para>
+
+ <sect3 id="mapping-declaration-id-generator"
revision="2">
+ <title>Generator</title>
+
+ <para>
+ O elemento filho opcional
<literal><generator></literal> nomeia uma classe Java
+ usada para gerar identificadores unicos para instancias de uma classe
persistente.
+ Se algum parâmetro é requerido para configurar ou inicializar a
instancia geradora,
+ eles são passados utilizando o elemento
<literal><param></literal>.
+ </para>
+
+ <programlisting><![CDATA[<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>]]></programlisting>
+
+ <para>
+ Todos os generators implementam a interface
<literal>org.hibernate.id.IdentifierGenerator</literal>.
+ Esta é uma interface bem simples; algumas aplicações podem prover sua
própria implementação
+ esepecializada. Entretanto, o Hibernate disponibiliza um conjunto de
implementações internamente.
+ Há nomes de atalhos para estes generators próprios:
+ <variablelist>
+ <varlistentry>
+
<term><literal>increment</literal></term>
+ <listitem>
+ <para>
+ gera identificadores dos tipos
<literal>long</literal>, <literal>short</literal> ou
+ <literal>int</literal> que são unicos apenas
quando nenhum outro processo está
+ inserindo dados na mesma tabela. <emphasis>Não
utilize em ambientes
+ de cluster.</emphasis>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>identity</literal></term>
+ <listitem>
+ <para>
+ suporta colunas de identidade em DB2, MySQL, MS SQL
Server, Sybase e
+ HypersonicSQL. O identificador retornado é do tipo
<literal>long</literal>,
+ <literal>short</literal> ou
<literal>int</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>sequence</literal></term>
+ <listitem>
+ <para>
+ utiliza uma sequence em DB2, PostgreSQL, Oracle, SAP DB,
McKoi ou um
+ generator no Interbase. O identificador de retorno é do
tipo <literal>
+ long</literal>,
<literal>short</literal> ou <literal>int</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hilo</literal></term>
+ <listitem>
+ <para
id="mapping-declaration-id-hilodescription" revision="1">
+ utiliza um algoritmo hi/lo para gerar de forma eficiente
identificadores do tipo
+ <literal>long</literal>,
<literal>short</literal> ou <literal>int</literal>,
+ a partir de uma tabela e coluna fornecida (por default
+ <literal>hibernate_unique_key</literal> e
<literal>next_hi</literal>)
+ como fonte para os valores hi. O algoritmo hi/lo gera
identificadores que são
+ únicos apenas para um banco de dados particular.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>seqhilo</literal></term>
+ <listitem>
+ <para>
+ utiliza um algoritmo hi/lo para gerar de forma eficinete
identificadores do tipo
+ <literal>long</literal>,
<literal>short</literal> ou <literal>int</literal>,
+ a partir de uma sequence de banco de dados fornecida.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>uuid</literal></term>
+ <listitem>
+ <para>
+ utiliza um algortimo UUID de 128-bits para gerar
identificadores do
+ tipo string, unicos em uma rede(o endereço IP é
utilizado). O UUID é
+ codificado como um string de digitos hexadecimais de
tamanho 32.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>guid</literal></term>
+ <listitem>
+ <para>
+ utiliza um string GUID gerado pelo banco de dados no MS
SQL Server
+ e MySQL.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>native</literal></term>
+ <listitem>
+ <para>
+ seleciona entre <literal>identity</literal>,
<literal>sequence</literal>
+ ou <literal>hilo</literal> dependendo das
capacidades do banco de dados
+ utilizado.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>assigned</literal></term>
+ <listitem>
+ <para>
+ deixa a aplicação definir um identificador para o objeto
antes que o
+ <literal>save()</literal> seja chamado. Esta
é a estratégia default
+ se nenhum elemento
<literal><generator></literal> é especificado.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>select</literal></term>
+ <listitem>
+ <para>
+ retorna a chave primaria recuperada por uma trigger do
banco de
+ dados, selecionado uma linha pela chave única e
recuperando o valor
+ da chave primária.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>foreign</literal></term>
+ <listitem>
+ <para>
+ utiliza o identificador de um outro objeto associado.
Normalmente utilizado
+ em conjunto com uma associaçõa de chave primária do tipo
+
<literal><one-to-one></literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><literal>sequence-identity</literal></term>
+ <listitem>
+ <para>
+ a specialized sequence generation strategy which utilizes
a
+ database sequence for the actual value generation, but
combines
+ this with JDBC3 getGeneratedKeys to actually return the
generated
+ identifier value as part of the insert statement
execution. This
+ strategy is only known to be supported on Oracle 10g
drivers
+ targetted for JDK 1.4. Note comments on these insert
statements
+ are disabled due to a bug in the Oracle drivers.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-hilo"
revision="1">
+ <title>Algoritmo Hi/lo</title>
+ <para>
+ Os geradores <literal>hilo</literal> e
<literal>seqhilo</literal> fornecem duas
+ implementações alternativas do algoritmo hi/lo, uma solução
preferencial para a geração
+ de identificadores. A primeira implementação requer uma tabela
especial do banco de
+ dados para manter o proximo valor "hi" disponível. A
segunda utiliza uma seqüência
+ do estilo Oracle (quando suportado).
+ </para>
+
+ <programlisting><![CDATA[<id name="id"
type="long" column="cat_id">
+ <generator class="hilo">
+ <param name="table">hi_value</param>
+ <param name="column">next_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+
+ <programlisting><![CDATA[<id name="id"
type="long" column="cat_id">
+ <generator class="seqhilo">
+ <param name="sequence">hi_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ Infelizemente, voce não pode utilizar
<literal>hilo</literal> quando estiver
+ fornecendo sia propria <literal>Connection</literal>
para o Hibernate. Quando o
+ Hibernate está usando um datasource do servidor de aplicações para
obter conexões
+ suportadas com JTA, você precisa configurar adequadamente o
+
<literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-uuid">
+ <title>UUID algorithm</title>
+ <para>
+ O UUID contem: o endereço IP, hora de inicio da JVM (com precisão de
um quarto
+ de segundo), a hora do sistema e um valor contador (unico dentro da
JVM).
+ Não é possivel obter o endereço MAC ou um endereço de memória do
código Java,
+ assim este é o melhor que pode ser feito sem utilizar JNI.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-sequences">
+ <title>Colunas de identidade e sequencias</title>
+ <para>
+ Para bancos de dados que suportam colunas de identidade (DB2, MySQL,
Sybase,
+ MS SQL), você pode utilizar uma geração de chave
<literal>identity</literal>.
+ Para bancos de dados que suportam sequencias (DB2, Oracle,
PostgreSQL, Interbase,
+ McKoi, SAP DB) voce pode utilizar a geração de chaves no estilo
+ <literal>sequence</literal>. As duas estratégias requerem
duas consultas SQL
+ para inserir um novo objeto.
+ </para>
+
+ <programlisting><![CDATA[<id name="id"
type="long" column="person_id">
+ <generator class="sequence">
+ <param name="sequence">person_id_sequence</param>
+ </generator>
+</id>]]></programlisting>
+
+ <programlisting><![CDATA[<id name="id"
type="long" column="person_id" unsaved-value="0">
+ <generator class="identity"/>
+</id>]]></programlisting>
+
+ <para>
+ Para desenvolvimento multi-plataforma, a estratégia
<literal>native</literal>
+ irá escolher entre as estratégias i
<literal>identity</literal>,
+ <literal>sequence</literal> e
<literal>hilo</literal>, dependendo das
+ capacidades do banco de dados utilizado.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-assigned">
+ <title>Identificadores especificados</title>
+ <para>
+ Se você quer que a aplicação especifique os identificadores
+ (em vez do Hibernate gerá-los) você deve utilizar o gerador
+ <literal>assigned</literal>. Este gerador especial irá
utilizar o valor
+ do identificador especificado para a propriedade de identificação do
objeto.
+ Este gerador é usado quando a chave primaria é a chave natural em vez
de uma
+ surrogate key. Este é o comportamento padrão se você não especificar
+ um elemento
<literal><generator></literal>.
+ </para>
+
+ <para>
+ Escolher o gerador <literal>assigned</literal> faz com
que o Hibernate
+ utilize
<literal>unsaved-value="undefined"</literal>, forçando o Hibernate
+ ir até o banco de dados para determinar se uma instância está
transiente ou
+ desasociada, a menos que haja uma versão ou uma propriedade
timestamp,
+ ou você pode definir
<literal>Interceptor.isUnsaved()</literal>.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-select">
+ <title>Chaves primárias geradas por triggers</title>
+ <para>
+ Apenas para sistemas legados (o Hibernate nao gera DDL com
triggers).
+ </para>
+
+ <programlisting><![CDATA[<id name="id"
type="long" column="person_id">
+ <generator class="select">
+ <param name="key">socialSecurityNumber</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ No exemplo acima, há uma única propriedade com valor nomeada
+ <literal>socialSecurityNumber</literal> definida pela
classe,
+ uma chave natural, e uma surrogate key nomeada
+ <literal>person_id</literal> cujo valor é gerado pro uma
trigger.
+ </para>
+
+ </sect3>
+
+ </sect2>
+ <sect2 id="mapping-declaration-id-enhanced">
+ <title>Enhanced identifier generators</title>
+
+ <para>
+ Starting with release 3.2.3, there are 2 new generators which represent a re-thinking
of 2 different
+ aspects of identifier generation. The first aspect is database portability; the
second is optimization
+ (not having to query the database for every request for a new identifier value).
These two new
+ generators are intended to take the place of some of the named generators described
above (starting
+ in 3.3.x); however, they are included in the current releases and can be referenced by
FQN.
+ </para>
+
+ <para>
+ The first of these new generators is
<literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
+ which is intended firstly as a replacement for the
<literal>sequence</literal> generator and secondly as
+ a better portability generator than <literal>native</literal> (because
<literal>native</literal>
+ (generally) chooses between <literal>identity</literal> and
<literal>sequence</literal> which have
+ largely different semantics which can cause subtle isssues in applications eyeing
portability).
+ <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
however achieves portability in
+ a different manner. It chooses between using a table or a sequence in the database to
store its
+ incrementing values depending on the capabilities of the dialect being used. The
difference between this
+ and <literal>native</literal> is that table-based and sequence-based
storage have the same exact
+ semantic (in fact sequences are exactly what Hibernate tries to emmulate with its
table-based
+ generators). This generator has a number of configuration parameters:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>sequence_name</literal> (optional, defaults to
<literal>hibernate_sequence</literal>):
+ The name of the sequence (or table) to be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (optional, defaults to
<literal>1</literal>): The initial
+ value to be retrieved from the sequence/table. In sequence creation terms, this is
analogous
+ to the clause typical named "STARTS WITH".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (optional, defaults to
<literal>1</literal>): The value by
+ which subsequent calls to the sequence/table should differ. In sequence creation
terms, this
+ is analogous to the clause typical named "INCREMENT BY".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>force_table_use</literal> (optional, defaults to
<literal>false</literal>): Should
+ we force the use of a table as the backing structure even though the dialect might
support
+ sequence?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column</literal> (optional, defaults to
<literal>next_val</literal>): Only
+ relevant for table structures! The name of the column on the table which is used
to
+ hold the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (optional, defaults to
<literal>none</literal>):
+ See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The second of these new generators is
<literal>org.hibernate.id.enhanced.TableGenerator</literal> which
+ is intended firstly as a replacement for the <literal>table</literal>
generator (although it actually
+ functions much more like
<literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>) and
secondly
+ as a re-implementation of
<literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal> utilizing
the
+ notion of pluggable optimiziers. Essentially this generator defines a table capable
of holding
+ a number of different increment values simultaneously by using multiple distinctly
keyed rows. This
+ generator has a number of configuration parameters:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>table_name</literal> (optional, defaults to
<literal>hibernate_sequences</literal>):
+ The name of the table to be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column_name</literal> (optional, defaults to
<literal>next_val</literal>):
+ The name of the column on the table which is used to hold the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_column_name</literal> (optional, defaults to
<literal>sequence_name</literal>):
+ The name of the column on the table which is used to hold the "segement
key". This is the
+ value which distinctly identifies which increment value to use.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value</literal> (optional, defaults to
<literal>default</literal>):
+ The "segment key" value for the segment from which we want to pull
increment values for
+ this generator.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value_length</literal> (optional, defaults to
<literal>255</literal>):
+ Used for schema generation; the column size to create this segment key column.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (optional, defaults to
<literal>1</literal>):
+ The initial value to be retrieved from the table.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (optional, defaults to
<literal>1</literal>):
+ The value by which subsequent calls to the table should differ.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (optional, defaults to
<literal></literal>):
+ See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-id-enhanced-optimizers">
+ <title>Identifier generator optimization</title>
+ <para>
+ For identifier generators which 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'd ideally want to
+ 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
+ (<xref linkend="mapping-declaration-id-enhanced"/> support this
notion.
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>none</literal> (generally this is the default if no optimizer
was specified): This
+ says to not perform any optimizations, and hit the database each and every
request.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hilo</literal>: applies a hi/lo algorithm around the database
retrieved values. The
+ values from the database for this optimizer are expected to be sequential. The
values
+ retrieved from the database structure for this optimizer indicates the "group
number"; the
+ <literal>increment_size</literal> is multiplied by that value in memory
to define a group
+ "hi value".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>pooled</literal>: like was discussed for
<literal>hilo</literal>, this optimizers
+ attempts to minimize the number of hits to the database. Here, however, we simply
store
+ the starting value for the "next group" into the database structure
rather than a sequential
+ value in combination with an in-memory grouping algorithm.
<literal>increment_size</literal>
+ here refers to the values coming from the database.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+
+ <sect2 id="mapping-declaration-compositeid"
revision="3">
+ <title>composite-id</title>
+
+ <programlisting><![CDATA[<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>]]></programlisting>
+
+ <para>
+ Para tabelas com uma chave composta, você pode mapear múltiplas
propriedades
+ da classe como propriedades de identificação. O elemento
+ <literal><composite-id></literal> aceita o
mapeamento da propriedade
+ <literal><key-property></literal> e mapeamentos
+ <literal><key-many-to-one></literal>como
elements filhos.
+ </para>
+
+ <programlisting><![CDATA[<composite-id>
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+ <para>
+ Sua classe persistente <emphasis>precisa</emphasis> sobre
escrever
+ <literal>equals()</literal> e
<literal>hashCode()</literal> para implementar
+ identificadores compostos igualmente. E precisa também implementar
+ <literal>Serializable</literal>.
+ </para>
+
+ <para>
+ Infelizmente, esta solução para um identificador composto significa que
um objeto
+ persistente é seu próprio identificador. Não há outro "handle"
que o próprio objeto.
+ Você mesmo precisa instanciar uma instância de outra classe persistente e
preencher
+ suas propriedades de identificação antes que você possa dar um
<literal>load()</literal>
+ para o estado persistente associado com uma chave composta. Nos chamamos
esta
+ solução de identificador composto
<emphasis>embedded</emphasis> e não aconselhamos
+ para aplicações sérias.
+ </para>
+
+ <para>
+ Uma segunda solução é o que podemos chamar de identificador composto
+ <emphasis>mapped</emphasis> quando a propriedades de
identificação nomeadas dentro do
+ elemento <literal><composite-id></literal>
estão duplicadas tando na classe
+ persistente como em uma classe de identificação separada.
+ </para>
+
+ <programlisting><![CDATA[<composite-id
class="MedicareId" mapped="true">
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+ <para>
+ No exemplo, ambas as classes de identificação compostas,
<literal>MedicareId</literal>,
+ e a própria classe entidade tem propriedades nomeadas
<literal>medicareNumber</literal>
+ e <literal>dependent</literal>. A classe identificadora
precisa sobrepor
+ <literal>equals()</literal> e
<literal>hashCode()</literal> e implementar
+ <literal>Serializable</literal>. A desvantagem desta solução
é obvia –
+ duplicação de código.
+ </para>
+
+ <para>
+ Os seguintes atributos ão utilizados para especificar o mapeamento de
+ um identificador composto:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mapped</literal> mapped (opcional, valor
default <literal>false
+ </literal>): indica que um identificar composto mapeado é
usado, e que as
+ propriedades de mapeamento contidas refere-se tanto a classe
entidade e
+ a classe de identificação composta.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (opcional, mas requerida
para um identificar composto
+ mapeado): A classe usada como um identificador composto.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Nós iremos descrever uma terceira e as vezes mais conveniente solução,
onde o
+ identificador composto é implementado como uma classe componente na
+ <xref linkend="components-compositeid"/>. Os atributos
descritos abaixo aplicam-se
+ apenas para esta solução:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>name</literal> (opcional, requerida para
esta solução): Uma
+ propriedade do tipo componente que armazena o identificador
composto
+ (veja capítulo 9)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>access</literal> (opcional - valor default
<literal>property</literal>):
+ A estartégia Hibernate que deve ser utilizada para acessar o
valor da propriedade.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (opcional - valor default
para o tipo de propriedade
+ determiando por reflexão) : A classe componente utilizada como um
identificador
+ composto (veja a próxima sessão).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Esta terceira solução, um <emphasis>componente de
identificação</emphasis>, é o que nós
+ recomendamos para a maioria das aplicações.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-discriminator"
revision="3">
+ <title>discriminator</title>
+
+ <para>
+ O elemento <literal><discriminator></literal>
é necessário para persistência
+ polimórfica utilizando a estratégia de mapeamento
table-per-class-hierarchy e declara
+ uma coluna discriminadora da tabela. A coluna discriminadora contem
valores de marcação
+ que dizem a camada de persistência qual subclasse instanciar para uma
linha particular.
+ Um restrito conjunto de tipos que podem ser utilizados:
<literal>string</literal>,
+ <literal>character</literal>,
<literal>integer</literal>, <literal>byte</literal>,
+ <literal>short</literal>,
<literal>boolean</literal>,
+ <literal>yes_no</literal>,
<literal>true_false</literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="discriminator1" coords="2 60"/>
+ <area id="discriminator2" coords="3 60" />
+ <area id="discriminator3" coords="4 60" />
+ <area id="discriminator4" coords="5 60" />
+ <area id="discriminator5" coords="6 60" />
+ </areaspec>
+ <programlisting><![CDATA[<discriminator
+ column="discriminator_column"
+ type="discriminator_type"
+ force="true|false"
+ insert="true|false"
+ formula="arbitrary sql expression"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="discriminator1">
+ <para>
+ <literal>column</literal> (opcional - valor
default <literal>class</literal>)
+ o nome da coluna discriminadora
+ </para>
+ </callout>
+ <callout arearefs="discriminator2">
+ <para>
+ <literal>type</literal> (opcional - valor default
<literal>string</literal>)
+ o nome que indica o tipo Hibernate
+ </para>
+ </callout>
+ <callout arearefs="discriminator3">
+ <para>
+ <literal>force</literal> (opcional - valor
default <literal>false</literal>)
+ "força" o Hibernate a especificar valores
discriminadores permitidos mesmo
+ quando recuperando todas as instancias da classe root.
+ </para>
+ </callout>
+ <callout arearefs="discriminator4">
+ <para>
+ <literal>insert</literal> (opcional - valor
default para <literal>true</literal>)
+ sete isto para <literal>false</literal> se sua
coluna discriminadora é também
+ parte do identificador composto mapeado. (Diz ao Hibernate
para não incluir a
+ coluna em comandos SQL
<literal>INSERT</literal>s).
+ </para>
+ </callout>
+ <callout arearefs="discriminator5">
+ <para>
+ <literal>formula</literal> (opcional) uma
expressão SQL arbitraria que é e
+ xecutada quando um tipo tem que ser avaliado. Permite
discriminação baseada
+ em conteúdo.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Valores atuais de uma coluna discriminada são especificados pelo atributo
+ <literal>discriminator-value</literal> da
<literal><class></literal>
+ e elementos da <literal><subclass></literal>.
+ </para>
+
+ <para>
+ O atributo <literal>force</literal> é util (apenas) em
tabelas contendo linhas com
+ valores discriminadores "extras" que não estão mapeados para
uma classe persistente.
+ Este não é geralmente o caso.
+ </para>
+
+ <para>
+ Usando o atributo <literal>formula</literal> voce pode
declarar uma expressão SQL
+ arbitrária que sera utilizada para avaliar o tipo de uma linha :
+ </para>
+
+ <programlisting><![CDATA[<discriminator
+ formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0
else 1 end"
+ type="integer"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-version" revision="4">
+ <title>version (optional)</title>
+
+ <para>
+ O elemento <literal><version></literal> é
opcional e indica que a tabela
+ possui dados versionados. Isto é particularmente útil se você planeja
utilizar
+ <emphasis>transações longas</emphasis> (veja abaixo):
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="version1" coords="2 70"/>
+ <area id="version2" coords="3 70"/>
+ <area id="version3" coords="4 70"/>
+ <area id="version4" coords="5 70"/>
+ <area id="version5" coords="6 70"/>
+ <area id="version6" coords="7 70"/>
+ <area id="version7" coords="8 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<version
+ column="version_column"
+ name="propertyName"
+ type="typename"
+ access="field|property|ClassName"
+ unsaved-value="null|negative|undefined"
+ generated="never|always"
+ insert="true|false"
+ node="element-name|@attribute-name|element/(a)attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="version1">
+ <para>
+ <literal>column</literal> (opcional - default a a
propriedade name): O nome da
+ coluna mantendo o numero da versão
+ </para>
+ </callout>
+ <callout arearefs="version2">
+ <para>
+ <literal>name</literal>: O nome da propriedade da
classe persistente.
+ </para>
+ </callout>
+ <callout arearefs="version3">
+ <para>
+ <literal>type</literal> (opcional - valor default
para <literal>integer</literal>):
+ O tipo do numero da versão
+ </para>
+ </callout>
+ <callout arearefs="version4">
+ <para>
+ <literal>access</literal> (opcional - valor
default <literal>property</literal>):
+ A estratégia Hibernate que deve ser usada para acessar o
valor da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="version5">
+ <para>
+ <literal>unsaved-value</literal> (opcional –
valor default para <literal>undefined
+ </literal>): Um valor para a propriedade versão que
indica que uma instancia é
+ uma nova instanciada (unsaved), distinguindo de instancias
desconectadas que foram
+ salvas ou carregadas em sessões anteriores.
((<literal>undefined</literal> especifica
+ que o valor da propriedade de identificação deve ser
utilizado).
+ </para>
+ </callout>
+ <callout arearefs="version6">
+ <para>
+ <literal>generated</literal> (optional - defaults
to <literal>never</literal>):
+ Specifies that this version property value is actually
generated by the database.
+ See the discussion of <xref
linkend="mapping-generated">generated properties</xref>.
+ <literal>generated</literal> (opcional - valor
default <literal>never</literal>):
+ Especifica que valor para a propriedade versão é na verdade
gerado pelo banco de
+ dados. Veja a discussão da Seção
+ <xref linkend="mapping-generated">generated
properties</xref>.
+ </para>
+ </callout>
+ <callout arearefs="version7">
+ <para>
+ <literal>insert</literal> (opcional - valor
default para <literal>true</literal>):
+ Especifica se a coluna de versão deve ser incluída no comando
SQL de insert.
+ Pode ser configurado como
<literal>false</literal> se a coluna do banco de dados
+ está definida com um valor default de
<literal>0</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Números de versão podem ser dos tipos Hibernate
<literal>long</literal>,
+ <literal>integer</literal>,
<literal>short</literal>, <literal>timestamp</literal> ou
+ <literal>calendar</literal>.
+ </para>
+
+ <para>
+ A versão de uma propriedade timestamp nunca deve ser nula para uma
instancia
+ desconectada, assim o Hibernate irá identificar qualquer instância com
uma versão
+ nula ou timestamp como transiente, não importando qual estratégia para
foi
+ especificada para <literal>unsaved-value</literal>.
<emphasis>Declarando 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 assinaldados ou chaves compostas!</emphasis>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-timestamp" revision="4"
>
+ <title>timestamp (optional)</title>
+
+ <para>
+ O elemento opcional
<literal><timestamp></literal> indica que uma tabela contém
+ dados timestamped. Isso tem por objetivo dar uma alternativa para
versionamento. Timestamps
+ são por natureza uma implementação menos segura do locking otimista.
Entretanto, algumas
+ vezes a aplicação pode usar timestamps em outros caminhos.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="timestamp1" coords="2 70"/>
+ <area id="timestamp2" coords="3 70" />
+ <area id="timestamp3" coords="4 70" />
+ <area id="timestamp4" coords="5 70" />
+ <area id="timestamp5" coords="6 70" />
+ <area id="timestamp6" coords="7 70" />
+ </areaspec>
+ <programlisting><![CDATA[<timestamp
+ column="timestamp_column"
+ name="propertyName"
+ access="field|property|ClassName"
+ unsaved-value="null|undefined"
+ source="vm|db"
+ generated="never|always"
+ node="element-name|@attribute-name|element/(a)attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="timestamp1">
+ <para>
+ <literal>column</literal> (opcional - valor
default para a propriedade name):
+ O nome da coluna que mantem o timestamp.
+ </para>
+ </callout>
+ <callout arearefs="timestamp2">
+ <para>
+ <literal>name</literal>: O nome da propriedade no
estilo JavaBeans do
+ tipo <literal>Date</literal> ou
<literal>Timestamp</literal> da classe
+ persistente Java.
+ </para>
+ </callout>
+ <callout arearefs="timestamp3">
+ <para>
+ <literal>access</literal> (opcional - valor
default para <literal>property</literal>):
+ A estretagia Hibernate que deve ser utilizada para acessar o
valor da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="timestamp4">
+ <para>
+ <literal>unsaved-value</literal> (opcional -
valor default <literal>null</literal>):
+ Uma propriedade para a versão de que indica que uma instância
é uma nova instanciada
+ (unsaved), distinguindo-a de instancias desconectadas que
foram salvas ou carregadas
+ em sessões previas. (<literal>undefined</literal>
especifica que um valor de
+ propriedade de identificação deve ser utilizado)
+ </para>
+ </callout>
+ <callout arearefs="timestamp5">
+ <para>
+ <literal>source</literal> (opcional - valor
default para <literal>vm</literal>):
+ De onde o Hibernate deve recuperar o valor timestamp? Do
banco de dados ou da JVM
+ corrente? 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
+ <literal>Dialect</literal>s suportam a
recuperação do timestamp corrente do banco
+ de dados, enquando outros podem não ser seguros para
utilização em bloqueios
+ pela falta de precisão (Oracle 8 por exemplo)
+ </para>
+ </callout>
+ <callout arearefs="timestamp6">
+ <para>
+ <literal>generated</literal> (opcional - valor
default <literal>never</literal>):
+ Especifica que o valor da propriedade timestamp é gerado pelo
banco de dados.
+ Veja a discussão <xref
linkend="mapping-generated">generated properties</xref>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Observe que <literal><timestamp></literal> é
equivalente a
+ <literal><version
type="timestamp"></literal>. E
+ <literal><timestamp
source="db"></literal> é equivalente a
+ <literal><version
type="dbtimestamp"></literal>.
+ </para>
+ </sect2>
+
+
+ <sect2 id="mapping-declaration-property" revision="4">
+ <title>property</title>
+
+ <para>
+ O elemento <literal><property></literal>
declara uma propriedade
+ persistente de uma classe, no estilo JavaBean.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="property1" coords="2 70"/>
+ <area id="property2" coords="3 70"/>
+ <area id="property3" coords="4 70"/>
+ <areaset id="property4-5" coords="">
+ <area id="property4" coords='5 70'/>
+ <area id="property5" coords='6 70'/>
+ </areaset>
+ <area id="property6" coords="7 70"/>
+ <area id="property7" coords="8 70"/>
+ <area id="property8" coords="9 70"/>
+ <area id="property9" coords="10 70"/>
+ <area id="property10" coords="11 70"/>
+ <area id="property11" coords="12 70"/>
+ <area id="property12" coords="13 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<property
+ name="propertyName"
+ column="column_name"
+ type="typename"
+ update="true|false"
+ insert="true|false"
+ formula="arbitrary SQL expression"
+ access="field|property|ClassName"
+ lazy="true|false"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ generated="never|insert|always"
+ node="element-name|@attribute-name|element/(a)attribute|."
+ index="index_name"
+ unique_key="unique_key_id"
+ length="L"
+ precision="P"
+ scale="S"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="property1">
+ <para>
+ <literal>name</literal>: o nome da propriedade,
iniciando com letra minúscula.
+ </para>
+ </callout>
+ <callout arearefs="property2">
+ <para>
+ <literal>column</literal> (opcional - default
para a propriedade name): o nome
+ da coluna mapeada do banco de dados, Isto pode também ser
especificado pelo(s)
+ elemento(s)
<literal><column></literal> aninhados.
+
+ </para>
+ </callout>
+ <callout arearefs="property3">
+ <para>
+ <literal>type</literal> (opcional): um nome que
indica o tipo Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="property4-5">
+ <para>
+ <literal>update, insert</literal> (opcional -
valor default <literal>true</literal>):
+ especifica que as colunas mapeadas devem ser incluidas nas
instruções SQL de
+ <literal>UPDATE</literal> e/ou
<literal>INSERT</literal> . Setar ambas para to
+ <literal>false</literal> permite uma propridade
"derivada" pura cujo valor é
+ inicializado de outra propriedade que mapeie a mesma
coluna(s) ou por uma trigger
+ ou outra aplicação.
+ </para>
+ </callout>
+ <callout arearefs="property6">
+ <para>
+ <literal>formula</literal> (opcional): uma
expressão SQL que definie o valor para
+ uma propriedade <emphasis>calculada</emphasis>.
Propriedades calculadas nao tem
+ uma coluna de mapeamento para elas.
+ </para>
+ </callout>
+ <callout arearefs="property7">
+ <para>
+ <literal>access</literal> (opcional – valor
default <literal>property</literal>):
+ A estratégia que o Hibernate deve utilizar para acessar o
valor da propriedade
+ </para>
+ </callout>
+ <callout arearefs="property8">
+ <para>
+ <literal>lazy</literal> (opcional - valor default
para <literal>false</literal>):
+ Especifica que esta propriedade deve ser trazida de forma
"lazy" quando a
+ instancia da variável é acessada pela primeira vez (requer
instrumentação
+ bytecode em tempo de criação).
+ </para>
+ </callout>
+ <callout arearefs="property9">
+ <para>
+ <literal>unique</literal> (opcional): Habilita a
geração de DDL de uma
+ unica constraint para as colunas. Assim, permite que isto
seja o
+ alvo de uma <literal>property-ref</literal>.
+ </para>
+ </callout>
+ <callout arearefs="property10">
+ <para>
+ <literal>not-null</literal> (opcional): Habilita
a geração de DDL de uma
+ constraint de nulidade para as colunas.
+ </para>
+ </callout>
+ <callout arearefs="property11">
+ <para>
+ <literal>optimistic-lock</literal> (opcional -
valor default <literal>true</literal>):
+ 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.
+ </para>
+ </callout>
+ <callout arearefs="property12">
+ <para>
+ <literal>generated</literal> (opcional - valor
default <literal>never</literal>):
+ Especifica que o valor da propriedade é na verdade gerado
pelo banco de dados.
+ Veja a discussão da seção
+ <xref linkend="mapping-generated">generated
properties</xref>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ <emphasis>typename</emphasis> pode ser:
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ The name of a Hibernate basic type (eg. <literal>integer,
string, character,
+ date, timestamp, float, binary, serializable, object,
blob</literal>).
+ O nome do tipo basico do Hibernate (ex., <literal>integer,
string, character,
+ date, timestamp, float, binary, serializable, object,
blob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ O nome da classe Java com um tipo básico default (ex.
<literal>int, float,
+ char, java.lang.String, java.util.Date, java.lang.Integer,
java.sql.Clob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ O nome da classe Java serializable
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ O nome da classe de um tipo customizado (ex.
<literal>com.illflow.type.MyCustomType</literal>).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ Se você não especificar um tipo, o Hibernate ira utilizar reflexão sobre
a
+ propriedade nomeada para ter uma idéia do tipo Hibernate correto. O
Hibernate ira
+ tentar interpretar o nome da classe retornada, usando as regras 2, 3 e 4
nesta ordem.
+ Entretanto, isto não é sempre suficiente Em certos casos, você ainda irá
necessitar
+ do atributo <literal>type</literal>. (Por exemplo, para
distinguir entre
+ <literal>Hibernate.DATE</literal> ou
<literal>Hibernate.TIMESTAMP</literal>,
+ ou para espcificar uma tipo ciustomizado.)
+ </para>
+
+ <para>
+ O atributo <literal>access</literal> permite voce controlar
como o Hibernate irá
+ acessar a propriedade em tempo de execução. Por default, o Hibernate irá
chamar os
+ métodos get/set da propriedades. Se voce especificar
<literal>access="field"</literal>,
+ o Hibernate ira bipassar os metodos get/set, acessnado o campo
diretamente,
+ usando reflexão. Voc epode especificar sua própria estratégia para acesso
da
+ propriedade criando uma classe que implemente a interface
+ <literal>org.hibernate.property.PropertyAccessor</literal>.
+ </para>
+
+ <para>
+ Um recurso especialmente poderoso é o de propriedades derivadas. Estas
propriedades
+ são por definição read-only, e o valor da propriedade é calculado em
tempo de execução.
+ Você declara este calculo como uma expressão SQL, que traduz para
clausula
+ <literal>SELECT</literal> de uma subquery daquery SQL que
carrega a instancia:
+ </para>
+
+ <programlisting><![CDATA[
+<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
)"/>]]></programlisting>
+
+ <para>
+ 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 (
+ <literal>customerId</literal> no exemplo dado). Observe
tambem que voce pode usar o
+ mapeamento de elemento aninhado
<literal><formula></literal>, se você não
+ gostar de usar o atributo.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-manytoone"
revision="5">
+ <title>many-to-one</title>
+
+ <para>
+ Uma associação ordinária para outra classe persistente é declarada usando
o
+ elemento <literal>many-to-one</literal>. O modelo relacional
é uma
+ associação many-to-one: a uma chave estrangeira de uma tabela
referenciando
+ a chave primaria da tabela destino.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="manytoone1" coords="2 70"/>
+ <area id="manytoone2" coords="3 70"/>
+ <area id="manytoone3" coords="4 70"/>
+ <area id="manytoone4" coords="5 70"/>
+ <area id="manytoone5" coords="6 70"/>
+ <areaset id="manytoone6-7" coords="">
+ <area id="manytoone6" coords='7 70'/>
+ <area id="manytoone7" coords='8 70'/>
+ </areaset>
+ <area id="manytoone8" coords="9 70"/>
+ <area id="manytoone9" coords="10 70"/>
+ <area id="manytoone10" coords="11 70"/>
+ <area id="manytoone11" coords="12 70"/>
+ <area id="manytoone12" coords="13 70"/>
+ <area id="manytoone13" coords="14 70"/>
+ <area id="manytoone14" coords="15 70"/>
+ <area id="manytoone15" coords="16 70"/>
+ <area id="manytoone16" coords="17 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-one
+ name="propertyName"
+ column="column_name"
+ class="ClassName"
+ cascade="cascade_style"
+ fetch="join|select"
+ update="true|false"
+ insert="true|false"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ lazy="proxy|no-proxy|false"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ formula="arbitrary SQL expression"
+ node="element-name|@attribute-name|element/(a)attribute|."
+ embed-xml="true|false"
+ index="index_name"
+ unique_key="unique_key_id"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytoone1">
+ <para>
+ <literal>name</literal>: O nome da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="manytoone2">
+ <para>
+ <literal>column</literal> (opcional): O nome da
coluna foreign key. Isto
+ pode também ser especificado através de elementos aninhados
+ <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="manytoone3">
+ <para>
+ <literal>class</literal> (opcional – default para
o tipo de propriedade
+ determinado pela reflexão). O nome da classe associada.
+ </para>
+ </callout>
+ <callout arearefs="manytoone4">
+ <para>
+ <literal>cascade</literal> (opcional): Especifica
quais operações dever
+ ser em cascata do objeto pai para o objeto associado.
+ </para>
+ </callout>
+ <callout arearefs="manytoone5">
+ <para>
+ <literal>fetch</literal> (opcional - default para
<literal>select</literal>):
+ Escolhe entre recuperação outer-join ou recuperação
seqüencial.
+ </para>
+ </callout>
+ <callout arearefs="manytoone6-7">
+ <para>
+ <literal>update, insert</literal> (opcional -
valor default <literal>true</literal>):
+ especifica que as colunas mapeadas dever ser incluidas em
instruções SQL de
+ <literal>UPDATE</literal> e/ou
<literal>INSERT</literal>. Setando ambas para
+ <literal>false</literal> você permite uma
associação "derivada" pura cujos valores
+ são inicializados de algumas outras propriedades que mapeiam
a mesma coluna ou
+ por uma trigger ou outra aplicação.
+ </para>
+ </callout>
+ <callout arearefs="manytoone8">
+ <para>
+ <literal>property-ref</literal>: (opcional) O
nome da propriedade da classe associada
+ que faz a junção desta foreign key. Se não especificada, a
chave primaria da
+ classe associada será utilizada.
+ </para>
+ </callout>
+ <callout arearefs="manytoone9">
+ <para>
+ <literal>access</literal> (opcional - valor
default <literal>property</literal>): A
+ estrategia que o Hibernate deve utilizar para acessar o valor
da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="manytoone10">
+ <para>
+ <literal>unique</literal> (opcional): Habilita a
geração DDL de uma constraint
+ unique para a coluna foreign-key. Alem disso, permite ser o
alvo de uma
+ <literal>property-ref</literal>. Isso torna a
associação multipla
+ efetivamente um para um.
+ </para>
+ </callout>
+ <callout arearefs="manytoone11">
+ <para>
+ <literal>not-null</literal> (opcional): Habilita
a geração DDL de uma constraint de
+ nulidade para as foreign keys.
+ </para>
+ </callout>
+ <callout arearefs="manytoone12">
+ <para>
+ <literal>optimistic-lock</literal> (opcional -
valor default <literal>true</literal>):
+ Especifica se mudanças desta propriedade requerem ou não
travamento otimista.
+ Em outras palavras, determina se um incremento de versão deve
ocorrer quando
+ esta propriedade está suja.
+ </para>
+ </callout>
+ <callout arearefs="manytoone13">
+ <para>
+ <literal>lazy</literal>(opcional – valor default
<literal>proxy</literal>):
+ Por default, associações de ponto unico são envoltas em um
proxie.
+ <literal>lazy="no-proxy"</literal>
especifica que a propriedade deve ser
+ trazida de forma tardia quando a instancia da variável é
acessada pela
+ primeira vez (requer instrumentação bytecode em tempo de
criação)
+ <literal>lazy="false"</literal>
especifica que a associação será
+ sempre recuperada fortemente.
+ </para>
+ </callout>
+ <callout arearefs="manytoone14">
+ <para>
+ <literal>not-found</literal> (opcional - valor
default <literal>exception</literal>):
+ Especifica como as foreign keys que referenciam linhas
ausentes serão tratadas:
+ <literal>ignore</literal> irá tratar a linha
ausente como ama associaççao de null
+ </para>
+ </callout>
+ <callout arearefs="manytoone15">
+ <para>
+ <literal>entity-name</literal> (opcional): O nome
da entidade da classe associada.
+ </para>
+ </callout>
+ </calloutlist>
+ <callout arearefs="manytoone16">
+ <para>
+ <literal>formula</literal> (optional): Uma
expressão SQL que define um valor
+ para um foreign key
<emphasis>computed</emphasis>.
+ </para>
+ </callout>
+ </programlistingco>
+
+ <para>
+ Setar o valor do atributo <literal>cascade</literal> para
qualquer valor
+ significativo diferente de <literal>none</literal> irá
propagar certas operações
+ ao objeto associado. Os valores significativos são os nomes das operações
básicas
+ do Hibernate, <literal>persist, merge, delete, save-update, evict,
replicate, lock,
+ refresh</literal>, assim como os valores especiais
<literal>delete-orphan</literal>
+ e <literal>all</literal> e combinações de nomes de operações
separadas por vírgula,
+ como por exemplo,
<literal>cascade="persist,merge,evict"</literal> ou
+ <literal>cascade="all,delete-orphan"</literal>.
Veja a seção
+ <xref linkend="objectstate-transitive"/> para uma
explicação completa. Note que
+ associações valoradas simples (associações muitos-pra-um, e um-pra-um)
não suportam
+ orphan delete.
+ </para>
+
+ <para>
+ Uma típica declaração <literal>muitos-pra-um</literal> se
parece com esta:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="product"
class="Product" column="PRODUCT_ID"/>]]></programlisting>
+
+ <para>
+ O atributo <literal>property-ref</literal> deve apenas ser
usado para mapear dados
+ legados onde uma chave estrangeira se referencia a uma chave exclusiva da
tabela
+ associada que não seja à chave primária. Este é um modelo relacional
desagradável.
+ Por exemplo, suponha que a classe <literal>Product</literal>
tenha um número
+ seqüencial exclusivo, que não é a chave primária. (O atributo
<literal>unique</literal>
+ controla a geração de DDL do Hibernate com a ferramenta SchemaExport.)
+ </para>
+
+ <programlisting><![CDATA[<property name="serialNumber"
unique="true" type="string"
column="SERIAL_NUMBER"/>]]></programlisting>
+
+ <para>
+ Então o mapeamento para <literal>OrderItem</literal> poderia
usar:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="product"
property-ref="serialNumber"
column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+
+ <para>
+ Porém, isto obviamente não é indicado, nunca.
+ </para>
+
+ <para>
+ Se a chave exclusiva referenciada engloba múltiplas propriedades da
entidade associada,
+ você deve mapear as propriedades referenciadas dentro de um elemento
chamado
+ <literal><properties></literal>
+
+ </para>
+
+ <para>
+ Se a chave exclusiva referenciada é a propriedade de um componente, você
pode especificar
+ um caminho para a propriedade.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="owner"
property-ref="identity.ssn"
column="OWNER_SSN"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-onetoone" revision="3">
+ <title>one-to-one (um-pra-um)</title>
+
+ <para>
+ Uma associação um-pra-um para outra classe persistente é declarada usando
+ um elemento <literal>one-to-one </literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="onetoone1" coords="2 70"/>
+ <area id="onetoone2" coords="3 70"/>
+ <area id="onetoone3" coords="4 70"/>
+ <area id="onetoone4" coords="5 70"/>
+ <area id="onetoone5" coords="6 70"/>
+ <area id="onetoone6" coords="7 70"/>
+ <area id="onetoone7" coords="8 70"/>
+ <area id="onetoone8" coords="9 70"/>
+ <area id="onetoone9" coords="10 70"/>
+ <area id="onetoone10" coords="11 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-one
+ name="propertyName"
+ class="ClassName"
+ cascade="cascade_style"
+ constrained="true|false"
+ fetch="join|select"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ formula="any SQL expression"
+ lazy="proxy|no-proxy|false"
+ entity-name="EntityName"
+ node="element-name|@attribute-name|element/(a)attribute|."
+ embed-xml="true|false"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetoone1">
+ <para>
+ <literal>name</literal>: O nome da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="onetoone2">
+ <para>
+ <literal>class</literal> (opcional – default para
o tipo da propriedade
+ definido via reflection): O nome da classe associada.
+ </para>
+ </callout>
+ <callout arearefs="onetoone3">
+ <para>
+ <literal>cascade</literal> (opcional): Especifica
qual operação deve
+ ser cascateada do objeto pai para o objeto associado.
+ </para>
+ </callout>
+ <callout arearefs="onetoone4">
+ <para>
+ <literal>constrained</literal> (opcional):
Especifica que uma chave estrangeira
+ constraint na chave primária da tabela mapeada referencia a
tabela da classe
+ associada, Esta opção afeta a ordem em queh
<literal>save()</literal> e
+ <literal>delete()</literal> são cascateadas, e
determina se a associação
+ pode ser substituída (isto também é usado pela ferramenta
schema export).
+ </para>
+ </callout>
+ <callout arearefs="onetoone5">
+ <para>
+ <literal>fetch</literal> ((opcional – valor
default <literal>select</literal>):
+ Escolhe entre outer-join fetching ou sequential select
fetching.
+ </para>
+ </callout>
+ <callout arearefs="onetoone6">
+ <para>
+ <literal>property-ref</literal>(opcional): O nome
da propriedade da classe associada
+ que é ligada a chave primária desta classe. Se não for
especificada, a chave primária
+ da classe associada é utilizada.
+ </para>
+ </callout>
+ <callout arearefs="onetoone7">
+ <para>
+ <literal>access</literal> (opcional - valor
default padrão <literal>property</literal>):
+ A estratégia que o Hibernate pode usar para acessar o valor
da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="onetoone8">
+ <para>
+ <literal>formula</literal> (opcional): Quase
todas associações um-pra-um mapeiam
+ para a chave primária da entidade dona. No caso raro, que não
é o caso, você
+ pode especificar uma outra coluna, colunas ou expressões para
juntar utilizando
+ uma formula SQL. (Veja
<literal>org.hibernate.test.onetooneformula</literal>
+ para exemplo).
+ </para>
+ </callout>
+ <callout arearefs="onetoone9">
+ <para>
+ <literal>lazy</literal> (opcional – valor default
<literal>proxy</literal>):
+ Por default, associações single point são proxied.
<literal>lazy="no-proxy"</literal>
+ especifica que a propriedade deve ser fetched lazily quando o
atributo é acessado
+ pela primeira vez (requer build-time bytecode
instrumentation).
+ <literal>lazy="false"</literal>
especifica que a associação vai sempre ser
+ avidamente fetched. <emphasis>Note que se
<literal>constrained="false"</literal>,
+ proxing é impossível e o Hibernate vai ávido fetch a
associação!</emphasis>
+ </para>
+ </callout>
+ <callout arearefs="onetoone10">
+ <para>
+ <literal>entity-name</literal> (opcional): O nome
da entidade da classe associada.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Existem duas variedades de associações um-pra-um:
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ associações de chave primária
+ </para></listitem>
+ <listitem><para>
+ associações de chave estrangeira exclusiva
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ Associações de chave primária não necessitam de uma coluna extra de
tabela; se duas
+ linhas são relacionadas pela associação então as duas linhas da tabela
dividem a mesmo
+ valor da chave primária. Assim, se você quer que dois objetos sejam
relacionados por
+ uma associação de chave primária, você deve ter certeza que eles são
assinados com o
+ mesmo valor identificador!
+ </para>
+
+ <para>
+ Para uma associação de chave primária, adicione os seguintes mapeamentos
em
+ <literal>Employee</literal> e
<literal>Person</literal>, respectivamente.
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person"
class="Person"/>]]></programlisting>
+ <programlisting><![CDATA[<one-to-one name="employee"
class="Employee" constrained="true"/>]]></programlisting>
+
+ <para>
+ Agora nós 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
<literal>foreign</literal>:
+ </para>
+
+ <programlisting><![CDATA[<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>]]></programlisting>
+
+ <para>
+ Uma nova instância de <literal>Person</literal> salva
recentemente é então assinada
+ com o mesmo valor da chave primária da instância de
<literal>employee</literal> referenciada
+ com a propriedade <literal>employee</literal> daquela
<literal>Person</literal>.
+ </para>
+
+ <para>
+ Alternativamente, uma chave estrangeira com uma unique constraint, de
+ <literal>Employee</literal> para
<literal>Person</literal>, pode ser expressa como:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="person"
class="Person" column="PERSON_ID"
unique="true"/>]]></programlisting>
+
+ <para>
+ E esta associação pode ser feita de forma bi-direcional adicionando o
seguinte
+ no mapeamento de <literal>Person</literal>:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="employee"
class="Employee"
property-ref="person"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-naturalid">
+ <title>natural-id</title>
+
+ <programlisting><![CDATA[<natural-id
mutable="true|false"/>
+ <property ... />
+ <many-to-one ... />
+ ......
+</natural-id>]]></programlisting>
+
+ <para>
+ Embora nós recomendemos o uso de surrogate keys como chaves primárias,
você deve
+ ainda identificar chaves naturais para todas as entidades. Uma chave
natural é
+ uma propriedade ou combinação de propriedades que é exclusiva e não nula.
Se não
+ pude ser modificada, melhor ainda. Mapeie as propriedades da chave
natural dentro do
+ elemento <literal><natural-id></literal>. O
Hibernate irá gerar a chave
+ exclusiva necessária e as constraints de nullability , e seu mapeamento
será
+ apropriadamente auto documentado.
+ </para>
+
+ <para>
+ Nós recomendamos com enfase que você implemente
<literal>equals()</literal> e
+ <literal>hashCode()</literal> para comparar as propriedades
da chave natural da
+ entidade.
+ </para>
+
+ <para>
+ Este mapeamento não tem o objetivo de uso com entidades com natural
chaves primárias.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mutable</literal> mutable (opcional, valor
default<literal>false</literal>):
+ Por default, propriedades naturais identificadoras são
consideradas imutáveis (constante).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-component"
revision="2">
+ <title>componente, componente dinâmico</title>
+
+ <para>
+ O elemento<literal><component></literal> mapeia
propriedades de um
+ objeto filho para colunas da tabela de uma classe pai. Componentes podem,
+ um após o outro, declarar suas próprias propriedades, componentes ou
coleções.
+ Veja "Components" abaixo.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="component1" coords="2 45"/>
+ <area id="component2" coords="3 45"/>
+ <area id="component3" coords="4 45"/>
+ <area id="component4" coords="5 45"/>
+ <area id="component5" coords="6 45"/>
+ <area id="component6" coords="7 45"/>
+ <area id="component7" coords="8 45"/>
+ <area id="component8" coords="9 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<component
+ name="propertyName"
+ class="className"
+ insert="true|false"
+ update="true|false"
+ access="field|property|ClassName"
+ lazy="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+ node="element-name|."
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</component>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="component1">
+ <para>
+ <literal>name</literal>: O nome da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="component2">
+ <para>
+ <literal>class</literal> (opcional – valor
default para o tipo de
+ propriedade determinada por reflection): O nome da classe
(filha) do
+ componente.
+ </para>
+ </callout>
+ <callout arearefs="component3">
+ <para>
+ <literal>insert</literal>: As colunas mapeadas
aparecem nos
+ SQL de <literal>INSERT</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="component4">
+ <para>
+ <literal>update</literal>: As colunas mapeadas
aparecem nos
+ SQL de <literal>UPDATE</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="component5">
+ <para>
+ <literal>access</literal> (opcional – valor
default <literal>property</literal>):
+ A estratégia que o Hibernate pode usar para acessar o valor
da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="component6">
+ <para>
+ <literal>lazy</literal> (opcional - valor default
<literal>false</literal>):
+ Especifica que este componente deve ser fetched lazily quando
o atributo for
+ acessado pela primeira vez (requer build-time bytecode
instrumentation).
+ </para>
+ </callout>
+ <callout arearefs="component7">
+ <para>
+ <literal>optimistic-lock</literal> (opcional
– valor default <literal>true</literal>):
+ Especifica que atualizações para este componente requerem
ou não aquisição
+ de um lock otimista. Em outras palavras, determina se uma
versão de incremento deve
+ ocorrer quando esta propriedade estiver modificada.
+ </para>
+ </callout>
+ <callout arearefs="component8">
+ <para>
+ <literal>unique</literal> (opcional – valor
default <literal>false</literal>):
+ Especifica que existe uma unique constraint em todas as
colunas mapeadas do
+ componente.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ A tag filha <literal><property></literal>
acrescenta a propriedade
+ de mapeamento da classe filha para colunas de uma tabela.
+ </para>
+
+ <para>
+ O elemento <literal><component></literal>
permite um sub-elemento
+ <literal><parent></literal> mapeie uma
propriedade da classe do componente
+ como uma referencia de volta para a entidade que o contém.
+ </para>
+
+ <para>
+ O elemento
<literal><dynamic-component></literal> permite que um
+ <literal>Map</literal> possa ser mapeado como um componente
onde os nomes das
+ propriedades referem-se para as chaves no mapa, veja
+ <xref linkend="components-dynamic"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-properties"
revision="2">
+ <title>propriedades</title>
+
+ <para>
+ O elemento <literal><properties></literal>
permite a definição de um grupo
+ com nome, lógico de propriedades de uma classe. O uso mais importante do
construtor
+ é que este permite uma combinação de propriedades para ser o objetivo de
uma
+ <literal>property-ref</literal>. É também um modo
conveninente para definir uma
+ unique constraint de múltiplas colunas.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="properties1" coords="2 45"/>
+ <area id="properties2" coords="3 45"/>
+ <area id="properties3" coords="4 45"/>
+ <area id="properties4" coords="5 45"/>
+ <area id="properties5" coords="6 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<properties
+ name="logicalName"
+ insert="true|false"
+ update="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</properties>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="properties1">
+ <para>
+ <literal>name</literal>:: O nome lógico do
agrupamento –
+ <emphasis>não </emphasis> é o nome atual de
propriedade.
+ </para>
+ </callout>
+ <callout arearefs="properties2">
+ <para>
+ <literal>insert</literal>: As colunas mapeadas
aparecem nos
+ SQL de <literal>INSERT</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="properties3">
+ <para>
+ <literal>update</literal>: As colunas mapeadas
aparecem nos
+ SQL de <literal>UPDATE</literal>s?
+ </para>
+ </callout>
+ <callout arearefs="properties4">
+ <para>
+ <literal>optimistic-lock</literal> (opcional
– valor default <literal>true</literal>):
+ Especifica que atualizações para estes componentes
requerem ou não aquisição de um
+ lock otimista. Em outras palavras, determina se uma
versão de incremento deve ocorrer
+ quando estas propriedades estiverem modificadas.
+ </para>
+ </callout>
+ <callout arearefs="properties5">
+ <para>
+ <literal>unique</literal> (opcional – valor
defautl <literal>false</literal>):
+ Especifica que uma unique constraint existe em todas as
colunas mapeadas do componente.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Por exemplo, se nós temos o seguinte mapeamento de
<literal><properties></literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="personNumber"/>
+ ...
+ <properties name="name"
+ unique="true" update="false">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </properties>
+</class>]]></programlisting>
+
+ <para>
+ Então nós podemos ter uma associação de dados herdados que referem a
esta chave
+ exclusiva da tabela <literal>Person</literal>, ao invés de se
referirem a chave
+ primária:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="person"
+ class="Person" property-ref="name">
+ <column name="firstName"/>
+ <column name="initial"/>
+ <column name="lastName"/>
+</many-to-one>]]></programlisting>
+
+ <para>
+ Nós não recomendamos o uso deste tipo de coisa fora do contexto de
mapeamento de
+ dados herdados.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-subclass" revision="4">
+ <title>subclass (subclasse)</title>
+
+ <para>
+ Finalmente, a persistência polimórfica requer a declaração de cada
subclasse
+ da classe de persistência raiz. Para a estratégia de mapeamento
+ table-per-class-hierarchy, a declaração
<literal><subclass></literal>
+ deve ser usada.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="subclass1" coords="2 55"/>
+ <area id="subclass2" coords="3 55"/>
+ <area id="subclass3" coords="4 55"/>
+ <area id="subclass4" coords="5 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<subclass
+ name="ClassName"
+ discriminator-value="discriminator_value"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ entity-name="EntityName"
+ node="element-name"
+ extends="SuperclassName">
+
+ <property .... />
+ .....
+</subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="subclass1">
+ <para>
+ <literal>name</literal>: O nome de classe
completamente qualificada da subclasse.
+ </para>
+ </callout>
+ <callout arearefs="subclass2">
+ <para>
+ <literal>discriminator-value</literal> (opcional
– valor default o nome da classe):
+ Um valor que distingue subclasses individuais.
+ </para>
+ </callout>
+ <callout arearefs="subclass3">
+ <para>
+ <literal>proxy</literal> (opcional): Especifica a
classe ou interface que
+ usará os proxies de inicialização atrasada.
+ </para>
+ </callout>
+ <callout arearefs="subclass4">
+ <para>
+ <literal>lazy</literal> (opcional, valor default
<literal>true</literal>):
+ Configurar
<literal>lazy="false"</literal> desabilitará o uso de
+ inicialização atrasada.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+ <para>
+ Cada subclasse deve declarar suas próprias propriedades persistentes e
subclasses.
+ As propriedades <literal><version></literal> e
<literal><id></literal>
+ são configuradas para serem herdades da classe raiz. Cada subclasse numa
hierarquia
+ deve definir um único <literal>discriminator-value</literal>.
Se nenhum for
+ especificado, o nome da classe Java completamente qualificada será
usada.
+ </para>
+
+ <para>
+ Para informações sobre mapeamento de heranças, veja o <xref
linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-joinedsubclass"
revision="3">
+ <title>joined-subclass</title>
+
+ <para>
+ Alternativamente, cada subclasse pode ser mapeada para sua própria tabela
+ (Estratégia de mapeamento table-per-subclass). O estado herdado é
devolvido
+ por associação com a tabela da superclasse. Nós usamos o elemento
+ <literal><joined-subclass></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="joinedsubclass1" coords="2 45"/>
+ <area id="joinedsubclass2" coords="3 45"/>
+ <area id="joinedsubclass3" coords="4 45"/>
+ <area id="joinedsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<joined-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="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>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="joinedsubclass1">
+ <para>
+ <literal>name</literal>: O nome da classe
completamente qualificada da
+ subclasse.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass2">
+ <para>
+ <literal>table</literal>: O nome da tabela da
subclasse.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass3">
+ <para>
+ <literal>proxy</literal> (opcional): Especifica a
classe ou interface
+ para usar os proxies de recuperação atrasada.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass4">
+ <para>
+ <literal>lazy</literal> (opcional, valor default
<literal>true</literal>):
+ Fixanr <literal>lazy="false"</literal>
desabilita o uso recuperação
+ atrasada.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ A coluna discriminator requerida para esta estratégia de mapeamento.
Porém,
+ cada subclasse deve declarar uma coluna de tabela com o identificador do
objeto
+ usando o elemento <literal><key></literal>. O
mapeamento no início do
+ capítulo poderia ser re-escrito assim:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD//EN"
+ "http://hibernate.sourceforge.net/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>]]></programlisting>
+
+ <para>
+ Para informações de mapeamentos de herança, veja <xref
linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-unionsubclass"
revision="2">
+ <title>union-subclass</title>
+
+ <para>
+ Uma terceira opção é mapear para tabelas apenas as classes concretas de
uma
+ hierarquia de heranças, (a estratégia table-per-concrete-class) onde cada
tabela
+ define todos os estados persistentes da classe, incluindo estados
herdados.
+ No Hibernate, não é absolutamente necessário mapear explicitamente como
hierarquia
+ de heranças. Você pode simplesmente mapear cada classe com uma declaração
+ <literal><class></literal> separada. Porém, se
você deseja usar associações
+ polimórficas (por exemplo: uma associação para a superclasse de sua
hierarquia),
+ você precisa usar o mapeamento
<literal><union-subclass></literal>.
+
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="unionsubclass1" coords="2 45"/>
+ <area id="unionsubclass2" coords="3 45"/>
+ <area id="unionsubclass3" coords="4 45"/>
+ <area id="unionsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<union-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="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>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="unionsubclass1">
+ <para>
+ <literal>name</literal>: O nome da subclasse
completamente qualificada.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass2">
+ <para>
+ <literal>table</literal>: O nome da tabela da
subclasse.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass3">
+ <para>
+ <literal>proxy</literal> (optional): Specifies a
class or interface to use
+ for lazy initializing proxies.
+
+ <literal>proxy</literal> (opcional): Especifica a
classe ou interface para usar
+ os proxies de recuperação atrasada.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass4">
+ <para>
+ <literal>lazy</literal> (optional, defaults to
<literal>true</literal>): Setting
+ <literal>lazy="false"</literal>
disables the use of lazy fetching.
+ <literal>lazy</literal> (opcional, valor default
p<literal>true</literal>):
+ Fixando <literal>lazy="false"</literal>
desabilita o uso da recuperação atrasada.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ A coluna discriminatõria não é requerida para esta estratégia de
mapeamento.
+
+ </para>
+
+ <para>
+ Para informações sobre mapeamentos de herança, veja <xref
linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-join" revision="3">
+ <title>join</title>
+
+ <para>
+ Usando o elemento
<literal><join></literal>>, é possível mapear
+ propriedades de uma classe para várias tabelas.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="join1" coords="2 50"/>
+ <area id="join2" coords="3 50"/>
+ <area id="join3" coords="4 50"/>
+ <area id="join4" coords="5 50"/>
+ <area id="join5" coords="6 50"/>
+ <area id="join6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<join
+ table="tablename"
+ schema="owner"
+ catalog="catalog"
+ fetch="join|select"
+ inverse="true|false"
+ optional="true|false">
+
+ <key ... />
+
+ <property ... />
+ ...
+</join>]]></programlisting>
+
+ <calloutlist>
+ <callout arearefs="join1">
+ <para>
+ <literal>table</literal>: O nome da tabela
associada.
+ </para>
+ </callout>
+ <callout arearefs="join2">
+ <para>
+ <literal>schema</literal> (opcional): Sobrepõe o
nome do esquema
+ especificado pelo elemento raiz
<literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="join3">
+ <para>
+ <literal>catalog</literal> (opcional): Sobrepõe o
nome do catálogo
+ especificado pelo elemento
raiz<literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="join4">
+ <para>
+ <literal>fetch</literal>(opcional – valor default
<literal>join</literal>): Se setado
+ para <literal>join</literal>, o padrão, o
Hibernate irá usar um inner join para
+ restaurar um <literal>join</literal> definido por
uma classe ou suas subclasses e
+ uma outer join para um <literal>join</literal>
definido por uma subclasse.
+ Se setado para <literal>select</literal>, então o
Hibernate irá usar uma seleção
+ seqüencial para um
<literal><join></literal> definida numa subclasse, que irá
+ ser emitido apenas se uma linha se concentrar para
representar uma instância
+ da subclasse. Inner joins irá ainda ser usado para restaurar
um
+ <literal><join></literal> definido
pela classe e suas superclasses.
+ </para>
+ </callout>
+ <callout arearefs="join5">
+ <para>
+ <literal>inverse</literal> (opcional – valor
default <literal>false</literal>):
+ Se habilitado, o Hibernate não irá tentar inserir ou
atualizar as propriedades
+ definidas por este join.
+ </para>
+ </callout>
+ <callout arearefs="join6">
+ <para>
+ <literal>optional</literal> (opcional – valor
default <literal>false</literal>):
+ Se habilitado, o Hibernate irá inserir uma linha apenas se as
propriedades definidas
+ por esta junção não forem nulas e irá sempre usar uma outer
join para
+ recuperar as propriedades.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ 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):
+ </para>
+
+ <programlisting><![CDATA[<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>
+ ...]]></programlisting>
+
+ <para>
+ Esta característica é útil apenas para modelos de dados legados, nós
recomendamos
+ menos tabelas do que classes e um modelo de domínio bem granulado. Porém,
é
+ útil para ficar trocando entre estratégias de mapeamento de herança
+ numa hierarquia simples, como explicado mais a frente.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-key">
+ <title>key</title>
+
+ <para>
+ Nós vimos que o elemento
<literal><key></literal> surgiu algumas vezes
+ até agora. Ele aparece em qualquer lugar que o elemento pai define uma
junção
+ para a nova tabela, e define a chave estrangeira para a tabela associada,
que
+ referencia a chave primária da tabela original.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="key1" coords="2 50"/>
+ <area id="key2" coords="3 50"/>
+ <area id="key3" coords="4 50"/>
+ <area id="key4" coords="5 50"/>
+ <area id="key5" coords="6 50"/>
+ <area id="key6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<key
+ column="columnname"
+ on-delete="noaction|cascade"
+ property-ref="propertyName"
+ not-null="true|false"
+ update="true|false"
+ unique="true|false"
+/>]]></programlisting>
+
+ <calloutlist>
+ <callout arearefs="key1">
+ <para>.
+ <literal>column</literal> (opcional): O nome da
coluna da chave estrangeira.
+ Isto também pode ser especificado por aninhamento de
elemento(s)
+ <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="key2">
+ <para>
+ <literal>on-delete</literal> (opcional, valor
default <literal>noaction</literal>):
+ Especifica se a constraint da chave estrangeira no banco de
dados esta
+ habilitada para cascade delete .
+ </para>
+ </callout>
+ <callout arearefs="key3">
+ <para>
+ <literal>property-ref</literal> (opcional):
Especifica que a chave estrangeira
+ se refere a colunas que não são chave primária da tabela
original.
+ (Util para base de dados legadas.)
+ </para>
+ </callout>
+ <callout arearefs="key4">
+ <para>
+ <literal>not-null</literal> (opcional):
Especifica que a coluna da chave
+ estrangeira não aceita valores nulos (isto é implícito em
qualquer momento
+ que a chave estrangeira também fizer parte da chave
primária).
+ </para>
+ </callout>
+ <callout arearefs="key5">
+ <para>
+ <literal>update</literal> (optional): Specifies
that the foreign key should never
+ be updated (this is implied whenever the foreign key is also
part of the primary
+ key).
+ <literal>update</literal> (opcional): Especifica
que a chave estrangeira nunca
+ deve ser atualizada (isto é implícito em qualquer momento que
a chave estrangeira
+ também fizer parte da chave primária).
+ </para>
+ </callout>
+ <callout arearefs="key6">
+ <para>
+ <literal>unique</literal> (opcional): Especifica
que a chave estrangeira deve ter
+ uma constraint unique (sto é implícito em qualquer momento
que a chave estrangeira
+ também fizer parte da chave primária).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Nós recomendamos que para sistemas que a performance de delete seja
importante, todas as
+ chaves deve ser definida
<literal>on-delete="cascade"</literal>, e o Hibernate irá usar
+ uma constraint a nível de banco de dados <literal>ON CASCADE
DELETE</literal>, ao invés
+ de muitas instruções <literal>DELETE</literal>. Esteja ciente
que esta característica é
+ um atalho da estratégia usual de optimistic locking do Hibernate para
dados versionados.
+ </para>
+
+ <para>
+ Os atributos <literal>not-null</literal> e
<literal>update</literal> são úteis quando
+ estamos mapeamos uma associação unidirecional um para muitos. Se você
mapear uma
+ asociação unidirecional um para muitos para uma chave estrangeira
non-nullable, você
+ <emphasis>deve</emphasis> declarar a coluna chave usando
+ <literal><key
not-null="true"></literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-column" revision="4">
+ <title>elementos column e formula</title>
+ <para>
+ Qualquer elemento de mapeamente que aceita um atributo
<literal>column</literal> irá
+ aceitar alternativamente um subelemento
<literal><column></literal>. Da mesma forma,
+ <literal>formula</literal> é uma alternativa para o atributo
<literal>formula</literal>.
+ </para>
+
+ <programlisting><![CDATA[<column
+ name="column_name"
+ length="N"
+ precision="N"
+ scale="N"
+ not-null="true|false"
+ unique="true|false"
+ unique-key="multicolumn_unique_key_name"
+ index="index_name"
+ sql-type="sql_type_name"
+ check="SQL expression"
+ default="SQL expression"/>]]></programlisting>
+
+ <programlisting><![CDATA[<formula>SQL
expression</formula>]]></programlisting>
+
+ <para>
+ O atributo <literal>column</literal> e
<literal>formula</literal> podem até ser combinados
+ dentro da mesma propriedade ou associação mapeando para expressar,
+ por exemplo, associações exóticas.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one
name="homeAddress" class="Address"
+ insert="false" update="false">
+ <column name="person_id" not-null="true"
length="10"/>
+ <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-import">
+ <title>import</title>
+
+ <para>
+ Suponha que a sua aplicação tem duas classes persistentes com o mesmo
nome, e você não quer
+ especificar o nome qualificado (do pacote) nas queries do Hibernate. As
Classes devem
+ ser "importadas" explicitamente, de preferência contando com
<literal>auto-import="true"</literal>.
+ Você pode até importar classes e interfaces que não estão explicitamente
mapeadas.
+ </para>
+
+ <programlisting><![CDATA[<import
class="java.lang.Object"
rename="Universe"/>]]></programlisting>
+
+ <programlistingco>
+ <areaspec>
+ <area id="import1" coords="2 40"/>
+ <area id="import2" coords="3 40"/>
+ </areaspec>
+ <programlisting><![CDATA[<import
+ class="ClassName"
+ rename="ShortName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="import1">
+ <para>
+ <literal>class</literal>: O nome qualificado (do
pacote) de qualquer classe Java.
+ </para>
+ </callout>
+ <callout arearefs="import2">
+ <para>
+ <literal>rename</literal> (opcional – valor
default, o nome da classe não
+ qualificada): Um nome que pode ser usado numa linguagem de
consulta.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ </sect2>
+
+ <sect2 id="mapping-types-anymapping" revision="2">
+ <title>any</title>
+
+ <para>
+ Existe mais um tipo de propriedade de mapeamento. O elemento de
mapeamento
+ <literal><any></literal> define uma associação
polimórfica para classes de múltiplas tabelas.
+ Este tipo de mapeamento sempre requer mais de uma coluna. A primeira
coluna possui o tipo da entidade
+ associada. A outra coluna que ficou possui o identificador. É impossível
especificar uma restrição
+ de chave estrangeira para este tipo de associação, assim isto claramente
não é visto
+ como um caminho usual para associações (polimórficas) de mapeamento. Você
deve usar este mapeamento
+ apenas em casos muito especiais (exemplo: audit logs, dados de sessão do
usuário, etc).
+
+ </para>
+
+ <para>
+ O atributo <literal>meta-type</literal> permite a aplicação
especificar um tipo adaptado
+ que mapeia valores de colunas de banco de dados para classes
persistentes que tem propriedades
+ identificadoras do tipo especificado através do
<literal>id-type</literal>. Você deve especificar
+ o mapeamento de valores do meta-type para nome de classes.
+ </para>
+
+ <programlisting><![CDATA[<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>]]></programlisting>
+
+ <programlistingco>
+ <areaspec>
+ <area id="any1" coords="2 50"/>
+ <area id="any2" coords="3 50"/>
+ <area id="any3" coords="4 50"/>
+ <area id="any4" coords="5 50"/>
+ <area id="any5" coords="6 50"/>
+ <area id="any6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<any
+ name="propertyName"
+ id-type="idtypename"
+ meta-type="metatypename"
+ cascade="cascade_style"
+ access="field|property|ClassName"
+ optimistic-lock="true|false"
+>
+ <meta-value ... />
+ <meta-value ... />
+ .....
+ <column .... />
+ <column .... />
+ .....
+</any>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="any1">
+ <para>
+ <literal>name</literal>: o nome da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="any2">
+ <para>
+ <literal>id-type</literal>: o tipo
identificador.
+ </para>
+ </callout>
+ <callout arearefs="any3">
+ <para>
+ <literal>meta-type</literal> (opcional – valor
default <literal>string</literal>):
+ Qualquer tipo que é permitido para um mapeamento
discriminador.
+ </para>
+ </callout>
+ <callout arearefs="any4">
+ <para>
+ <literal>cascade</literal> (opcional – valor
default <literal>none</literal>):
+ o estilo do cascade.
+ </para>
+ </callout>
+ <callout arearefs="any5">
+ <para>
+ <literal>access</literal> (opcional – valor
default <literal>property</literal>):
+ A estratégia que o hibernate deve usar para acessar o valor
da propriedade.
+ </para>
+ </callout>
+ <callout arearefs="any6">
+ <para>
+ <literal>optimistic-lock</literal> (opcional -
valor default<literal>true</literal>):
+ Especifica que as atualizações para esta propriedade requerem
ou não aquisição da
+ trava otimista. Em outras palavras, define se uma versão de
incremento deve ocorrer
+ se esta propriedade está modificada.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="mapping-types">
+ <title>Tipos do Hibernate</title>
+
+ <sect2 id="mapping-types-entitiesvalues" revision="1">
+ <title>Entidades e valores</title>
+
+ <para>
+ Para entender o comportamento de vários objetos em nível de linguagem de
Java a
+ respeito do serviço de persistência, nós precisamos classificá-los em
dois grupos.
+ </para>
+
+ <para>
+ Uma <emphasis>entidade </emphasis> 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 garbage collector.
Entidades
+ devem ser explicitamente salvas ou deletada (exceto em operações de
salvamento
+ ou deleção que possam ser executada em
<emphasis>cascata</emphasis> de uma entidade
+ pai para seus filhos). Isto é diferente do modelo ODMG de persistência do
objeto
+ por acessibilidade – e corresponde quase a como objetos de aplicações são
+ geralmente usados em grandes sistemas. Entidades suportam referências
circulares
+ e comuns. Eles podem ser versionadas.
+ </para>
+
+ <para>
+ Uma entidade em estado persistente consiste de referências para outras
entidades
+ e instâncias de tipos de <emphasis>valor</emphasis>. 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)
+ <emphasis>são </emphasis> persistidos e apagados por
acessibilidade. Visto que
+ objetos value (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.
+
+ </para>
+
+ <para>
+ Até agora, nós estivemos usando o termo "classe persistente"
para referir
+ a entidades. Nós iremos continuar a fazer isto. Falando a rigor, porém,
nem todas
+ as classes definidas pelo usuário com estados persistentes são entidades.
Um
+ <emphasis>componente</emphasis> é uma classe de usuário
definida com valores
+ semânticos. Uma propriedade de Java de tipo
<literal>java.lang.String</literal>
+ também tem um valor semêntico. Dada esta definição, nós podemos dizer que
+ todos os tipos (classes) fornecida pelo JDK tem tipo de valor semântico
em Java,
+ enquanto que tipos definidos pelo usuário pode 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 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 valor de tipo.
+ </para>
+
+ <para>
+ Nós iremos rever ambos os conceitos durante toda a documentação.
+
+ </para>
+
+ <para>
+ O desafio pe 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 é fornecido pelo Hibernate: para entidades que usam
+ <literal><class></literal>,
<literal><subclass></literal> e assim por diante.
+ Para tipos de valores nós usamos
<literal><property></literal>,
+ <literal><component></literal>, etc, geralmente
com um atributo
+ <literal>type</literal>. O valor deste atributo é o nome de
um <emphasis>tipo de
+ mapeamento</emphasis> do Hibernate. O Hibernate fornece muitos
mapeamentos
+ (para tipos de valores do JDK padrão) ut of the box. Você pode escrever
os seus
+ próprios tipos de mapeamentos e implementar sua estratégia de conversão
adaptada,
+ como você verá adiante.
+ </para>
+
+ <para>
+ Todos os tipos internos do hibernate exceto coleções suportam semânticas
nulas.
+
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-types-basictypes" revision="3">
+ <title>Valores de tipos básicos</title>
+
+ <para>
+ O tipos internos de mapeamentos básicos podem ser a grosso modo
categorizado como:
+ <variablelist>
+ <varlistentry>
+ <term><literal>integer, long, short, float, double,
character, byte,
+ boolean, yes_no, true_false</literal></term>
+ <listitem>
+ <para>
+ Tipos de mapeamentos de classes primitivas ou wrapper
Java especificos
+ (vendor-specific) para tipos de coluna SQL. Boolean,
+ <literal>boolean, yes_no</literal> são todas
codificações alternativas
+ para um <literal>boolean</literal> ou
<literal>java.lang.Boolean</literal>
+ do Java.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>string</literal></term>
+ <listitem>
+ <para>
+ Um tipo de mapeamento de
<literal>java.lang.String</literal> para
+ <literal>VARCHAR</literal> (ou
<literal>VARCHAR2</literal> no Oracle).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>date, time,
timestamp</literal></term>
+ <listitem>
+ <para>
+ Tipos de mapeamento de
<literal>java.util.Date</literal> e suas
+ subclasses para os tipos SQL
<literal>DATE</literal>,
+ <literal>TIME</literal> e
<literal>TIMESTAMP</literal>
+ (ou equivalente).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>calendar,
calendar_date</literal></term>
+ <listitem>
+ <para>
+ Tipo de mapeamento de
<literal>java.util.Calendar</literal> para
+ os tipos SQL <literal>TIMESTAMP</literal> e
+ <literal>DATE</literal> (ou equivalente).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>big_decimal,
big_integer</literal></term>
+ <listitem>
+ <para>
+ Tipo de mapeamento de
<literal>java.math.BigDecimal</literal> and
+ <literal>java.math.BigInteger</literal> para
<literal>NUMERIC</literal>
+ (ou <literal>NUMBER</literal> no Oracle).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>locale, timezone,
currency</literal></term>
+ <listitem>
+ <para>
+ Tipos de mapeamentos de
<literal>java.util.Locale</literal>,
+ <literal>java.util.TimeZone</literal> e
<literal>java.util.Currency</literal>
+ para <literal>VARCHAR</literal> (ou
<literal>VARCHAR2</literal> no Oracle).
+ Instâncias de f <literal>Locale</literal> e
<literal>Currency</literal>
+ são mapeados para seus códigos ISO. Instâncias de
<literal>TimeZone</literal>
+ são mapeados para seu <literal>ID</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>class</literal></term>
+ <listitem>
+ <para>
+ um tipo de mapeamento de
<literal>java.lang.Class</literal> para
+ <literal>VARCHAR</literal> (ou
<literal>VARCHAR2</literal> no
+ Oracle). Uma <literal>Class</literal> é
mapeada pelo
+ seu nome qualificado (completo).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>binary</literal></term>
+ <listitem>
+ <para>
+ Mapeia arrays de bytes para um tipo binário de SQL
apropriado.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>text</literal></term>
+ <listitem>
+ <para>
+ Maps long Java strings to a SQL
<literal>CLOB</literal> or
+ <literal>TEXT</literal> type.
+ Mapeia strings longas de Java para um tipo SQL
+ <literal>CLOB</literal> ou
<literal>TEXT</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><literal>serializable</literal></term>
+ <listitem>
+ <para>
+ Mapeia tipos Java serializáveis para um tipo binário SQL
apropriado.
+ Você pode também indicar o tipo
<literal>serializable</literal> do
+ Hibernate com o nome da classe ou interface Java
serializável que
+ não é padrão para um tipo básico.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>clob,
blob</literal></term>
+ <listitem>
+ <para>
+ Tipos de mapeamentos para as classes JDBC
<literal>java.sql.Clob</literal> and
+ <literal>java.sql.Blob</literal>. Estes tipos
podem ser inconveniente para
+ algumas aplicações, visto que o objeto blob ou clob pode
não ser reusado
+ fora de uma transação. (Além disso, o suporte de driver é
imcompleto e
+ inconsistente.)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <literal>imm_date, imm_time, imm_timestamp,
imm_calendar, imm_calendar_date,
+ imm_serializable, imm_binary</literal>
+ </term>
+ <listitem>
+ <para>
+ Mapeando tipos para o que geralmente são consideradas
tipos mutáveis de
+ Java, 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
<literal>Date.setTime()</literal> para
+ uma instância mapeada como
<literal>imm_timestamp</literal>. Para mudar
+ o valor da propriedade, e ter a mudança feita
persistente, a aplicação
+ deve atribuir um novo objeto (nonidentical) à
propriedade.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+
+ <para>
+ Identificadores únicos das entidades e coleções podem ser de qualquer
tipo
+ básico exceto <literal>binary</literal>,
<literal>blob</literal> ou
+ <literal>clob</literal>. (Identificadores compostos também
são permitidos,
+ veja abaixo.)
+ </para>
+
+ <para>
+ Os tipos de valores básicos têm suas constantes
<literal>Type</literal>
+ correspondentes definidas em
<literal>org.hibernate.Hibernate</literal>. Por exemplo,
+ <literal>Hibernate.STRING</literal> representa o tipo
<literal>string</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-types-custom" revision="2">
+ <title>Tipos de valores personalizados</title>
+
+ <para>
+ É relativamente fácil para desenvolvedores criar seus próprios tipos de
valor.
+ Por exemplo, você pode querer persistir propriedades do tipo
+ <literal>java.lang.BigInteger</literal> para colunas
<literal>VARCHAR</literal>. 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ê pôde ter uma propriedade
Java
+
<literal>getName()</literal>/<literal>setName()</literal> do tipo
+ <literal>java.lang.String</literal> que é persistido para
colunas
+ <literal>FIRST_NAME</literal>,
<literal>INITIAL</literal>, <literal>SURNAME</literal>.
+
+ </para>
+
+ <para>
+ Para implementar um tipo personalizado, implemente
<literal>org.hibernate.UserType</literal>
+ or <literal>org.hibernate.CompositeUserType</literal> e
declare propriedades usando o nome
+ qualificado da classe do tipo. Veja
<literal>org.hibernate.test.DoubleStringType</literal>
+ para ver o tipo das coisas que são possíveis.
+ </para>
+
+ <programlisting><![CDATA[<property name="twoStrings"
type="org.hibernate.test.DoubleStringType">
+ <column name="first_string"/>
+ <column name="second_string"/>
+</property>]]></programlisting>
+
+ <para>
+ Observe o uso da tag
<literal><column></literal> para mapear uma propriedade
+ para colunas múltiplas.
+ </para>
+
+ <para>
+ As interfaces <literal>CompositeUserType</literal>,
<literal>EnhancedUserType</literal>,
+ <literal>UserCollectionType</literal>, e
<literal>UserVersionType</literal>
+ fornecem suporte para usos mais especializados.
+ </para>
+
+ <para>
+ Você pode mesmo fornecer parâmetros a um
<literal>UserType</literal> no arquivo de mapeamento.
+ Para isto, seu <literal>UserType</literal> deve implementar a
interface
+ <literal>org.hibernate.usertype.ParameterizedType</literal>.
Para fornecer parâmetros a seu
+ tipo personalizado, você pode usar o elemento
<literal><type></literal> em seus
+ arquivos de mapeamento.
+ </para>
+
+ <programlisting><![CDATA[<property name="priority">
+ <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+ <param name="default">0</param>
+ </type>
+</property>]]></programlisting>
+
+ <para>
+ O <literal>UserType</literal> pode agora recuperar o valor
para o parâmetro chamado
+ <literal>default</literal> da
<literal>Propriedade</literal> do passado a ele.
+ </para>
+
+ <para>
+ Se você usar freqüentemente um determinado
<literal>UserType</literal>, pode ser útil definir
+ um nome mais curto para ele. Você pode fazer isto usando o elemento
+ <literal><typedef></literal>. Typedefs atribui
um nome a um tipo personalizado, e pode também
+ conter uma lista de valores default de parâmetro se o tipo for
parametrizado.
+ </para>
+
+ <programlisting><![CDATA[<typedef
class="com.mycompany.usertypes.DefaultValueIntegerType"
name="default_zero">
+ <param name="default">0</param>
+</typedef>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="priority"
type="default_zero"/>]]></programlisting>
+
+ <para>
+ It is also possible to override the parameters supplied in a typedef on a
case-by-case basis
+ by using type parameters on the property mapping.
+ </para>
+
+ <para>
+ Even though Hibernate's rich range of built-in types and support for
components means you
+ will very rarely <emphasis>need</emphasis> to use a custom
type, it is nevertheless
+ considered good form to use custom types for (non-entity) classes that
occur frequently
+ in your application. For example, a
<literal>MonetaryAmount</literal> class is a good
+ candidate for a <literal>CompositeUserType</literal>, even
though it could easily be mapped
+ as a component. One motivation for this is abstraction. With a custom
type, your mapping
+ documents would be future-proofed against possible changes in your way of
representing
+ monetary values.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="mapping-entityname">
+ <title>Mapping a class more than once</title>
+ <para>
+ It is possible to provide more than one mapping for a particular persistent
class. In this
+ case you must specify an <emphasis>entity name</emphasis> do
disambiguate between instances
+ of the two mapped entities. (By default, the entity name is the same as the
class name.)
+ Hibernate lets you specify the entity name when working with persistent
objects, when writing
+ queries, or when mapping associations to the named entity.
+ </para>
+
+ <programlisting><![CDATA[<class name="Contract"
table="Contracts"
+ entity-name="CurrentContract">
+ ...
+ <set name="history" inverse="true"
+ order-by="effectiveEndDate desc">
+ <key column="currentContractId"/>
+ <one-to-many entity-name="HistoricalContract"/>
+ </set>
+</class>
+
+<class name="Contract" table="ContractHistory"
+ entity-name="HistoricalContract">
+ ...
+ <many-to-one name="currentContract"
+ column="currentContractId"
+ entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+ <para>
+ Notice how associations are now specified using
<literal>entity-name</literal> instead of
+ <literal>class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="mapping-quotedidentifiers">
+ <title>SQL quoted identifiers</title>
+ <para>
+ You may force Hibernate to quote an identifier in the generated SQL by
enclosing the table or
+ column name in backticks in the mapping document. Hibernate will use the
correct quotation
+ style for the SQL <literal>Dialect</literal> (usually double
quotes, but brackets for SQL
+ Server and backticks for MySQL).
+ </para>
+
+ <programlisting><![CDATA[<class name="LineItem"
table="`Line Item`">
+ <id name="id" column="`Item Id`"/><generator
class="assigned"/></id>
+ <property name="itemNumber" column="`Item #`"/>
+ ...
+</class>]]></programlisting>
+
+ </sect1>
+
+
+ <sect1 id="mapping-alternatives">
+ <title>Metadata alternatives</title>
+
+ <para>
+ XML isn't for everyone, and so there are some alternative ways to define O/R
mapping metadata in Hibernate.
+ </para>
+
+ <sect2 id="mapping-xdoclet">
+ <title>Using XDoclet markup</title>
+
+ <para>
+ Many Hibernate users prefer to embed mapping information directly in
sourcecode using
+ XDoclet <literal>(a)hibernate.tags</literal>. We will not cover
this approach in this
+ document, since strictly it is considered part of XDoclet. However, we
include the
+ following example of the <literal>Cat</literal> class with
XDoclet mappings.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ * table="CATS"
+ */
+public class Cat {
+ private Long id; // identifier
+ private Date birthdate;
+ private Cat mother;
+ private Set kittens
+ private Color color;
+ private char sex;
+ private float weight;
+
+ /*
+ * @hibernate.id
+ * generator-class="native"
+ * column="CAT_ID"
+ */
+ public Long getId() {
+ return id;
+ }
+ private void setId(Long id) {
+ this.id=id;
+ }
+
+ /**
+ * @hibernate.many-to-one
+ * column="PARENT_ID"
+ */
+ public Cat getMother() {
+ return mother;
+ }
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+
+ /**
+ * @hibernate.property
+ * column="BIRTH_DATE"
+ */
+ public Date getBirthdate() {
+ return birthdate;
+ }
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ /**
+ * @hibernate.property
+ * column="WEIGHT"
+ */
+ public float getWeight() {
+ return weight;
+ }
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+
+ /**
+ * @hibernate.property
+ * column="COLOR"
+ * not-null="true"
+ */
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+ /**
+ * @hibernate.set
+ * inverse="true"
+ * order-by="BIRTH_DATE"
+ * @hibernate.collection-key
+ * column="PARENT_ID"
+ * @hibernate.collection-one-to-many
+ */
+ public Set getKittens() {
+ return kittens;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kittens.add(kitten);
+ }
+
+ /**
+ * @hibernate.property
+ * column="SEX"
+ * not-null="true"
+ * update="false"
+ */
+ public char getSex() {
+ return sex;
+ }
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+}]]></programlisting>
+
+ <para>
+ See the Hibernate web site for more examples of XDoclet and Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-annotations" revision="2">
+ <title>Using JDK 5.0 Annotations</title>
+
+ <para>
+ JDK 5.0 introduced XDoclet-style annotations at the language level, type-safe
and
+ checked at compile time. This mechnism is more powerful than XDoclet
annotations and
+ better supported by tools and IDEs. IntelliJ IDEA, for example, supports
auto-completion
+ and syntax highlighting of JDK 5.0 annotations. The new revision of the EJB
specification
+ (JSR-220) uses JDK 5.0 annotations as the primary metadata mechanism for
entity beans.
+ Hibernate3 implements the <literal>EntityManager</literal> of
JSR-220 (the persistence API),
+ support for mapping metadata is available via the <emphasis>Hibernate
Annotations</emphasis>
+ package, as a separate download. Both EJB3 (JSR-220) and Hibernate3 metadata
is supported.
+ </para>
+
+ <para>
+ This is an example of a POJO class annotated as an EJB entity bean:
+ </para>
+
+ <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+ @Id;
+ Long id;
+
+ String firstName;
+ String lastName;
+ Date birthday;
+
+ @Transient
+ Integer age;
+
+ @Embedded
+ private Address homeAddress;
+
+ @OneToMany(cascade=CascadeType.ALL)
+ @JoinColumn(name="CUSTOMER_ID")
+ Set<Order> orders;
+
+ // Getter/setter and business methods
+}]]></programlisting>
+
+ <para>
+ Note that support for JDK 5.0 Annotations (and JSR-220) is still work in
progress and
+ not completed. Please refer to the Hibernate Annotations module for more
details.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="mapping-generated" revision="1">
+ <title>Generated Properties</title>
+ <para>
+ Generated properties are properties which have their values generated by the
+ database. Typically, Hibernate applications needed to
<literal>refresh</literal>
+ objects which contain any properties for which the database was generating
values.
+ Marking properties as generated, however, lets the application delegate this
+ responsibility to Hibernate. Essentially, whenever Hibernate issues an SQL
INSERT
+ or UPDATE for an entity which has defined generated properties, it
immediately
+ issues a select afterwards to retrieve the generated values.
+ </para>
+ <para>
+ Properties marked as generated must additionally be non-insertable and
non-updateable.
+ Only <xref
linkend="mapping-declaration-version">versions</xref>,
+ <xref
linkend="mapping-declaration-timestamp">timestamps</xref>, and
+ <xref linkend="mapping-declaration-property">simple
properties</xref> can be marked as
+ generated.
+ </para>
+ <para>
+ <literal>never</literal> (the default) - means that the given property
value
+ is not generated within the database.
+ </para>
+ <para>
+ <literal>insert</literal> - states that the given property value is
generated on
+ insert, but is not regenerated on subsequent updates. Things like created-date
would
+ fall into this category. Note that even thought
+ <xref linkend="mapping-declaration-version">version</xref>
and
+ <xref
linkend="mapping-declaration-timestamp">timestamp</xref> properties
can
+ be marked as generated, this option is not available there...
+ </para>
+ <para>
+ <literal>always</literal> - states that the property value is generated
both
+ on insert and on update.
+ </para>
+ </sect1>
+
+ <sect1 id="mapping-database-object">
+ <title>Auxiliary Database Objects</title>
+ <para>
+ Allows CREATE and DROP of arbitrary database objects, in conjunction with
+ Hibernate's schema evolution tools, to provide the ability to fully
define
+ a user schema within the Hibernate mapping files. Although designed
specifically
+ for creating and dropping things like triggers or stored procedures, really
any
+ SQL command that can be run via a
<literal>java.sql.Statement.execute()</literal>
+ method is valid here (ALTERs, INSERTS, etc). There are essentially two modes
for
+ defining auxiliary database objects...
+ </para>
+ <para>
+ The first mode is to explicitly list the CREATE and DROP commands out in the
mapping
+ file:
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <create>CREATE TRIGGER my_trigger ...</create>
+ <drop>DROP TRIGGER my_trigger</drop>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ The second mode is to supply a custom class which knows how to construct the
+ CREATE and DROP commands. This custom class must implement the
+ <literal>org.hibernate.mapping.AuxiliaryDatabaseObject</literal>
interface.
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <definition class="MyTriggerDefinition"/>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ <para>
+ Additionally, these database objects can be optionally scoped such that they
only
+ apply when certain dialects are used.
+ </para>
+ <programlisting><![CDATA[<hibernate-mapping>
+ ...
+ <database-object>
+ <definition class="MyTriggerDefinition"/>
+ <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/>
+ <dialect-scope name="org.hibernate.dialect.OracleDialect"/>
+ </database-object>
+</hibernate-mapping>]]></programlisting>
+ </sect1>
+</chapter>
+
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/batch.xml
===================================================================
--- core/trunk/documentation/manual/pt-BR/src/main/docbook/content/batch.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++ core/trunk/documentation/manual/pt-BR/src/main/docbook/content/batch.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,360 +1,364 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="batch">
- <title>Processamento de lotes</title>
-
- <para>
- Uma alternativa para inserir 100.000 linhas no banco de dados usando o Hibernate
- pode ser a seguinte:
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-for ( int i=0; i<100000; i++ ) {
- Customer customer = new Customer(.....);
- session.save(customer);
-}
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- Isto irá falhar em algum lugar próximo a linha 50.000, lançando uma
- <literal>OutOfMemoryException</literal>. Isso ocorre devido ao fato
do Hibernate
- fazer cache de todas as instâncias de <literal>Customer</literal>
inseridas num
- cachê em nível de sessão.
- </para>
-
- <para>
- Neste capítulo veremos como contornar esse problema. Entretanto, se você vai
realizar
- processamento de lotes, é muito importante que você habilite o uso de lotes JDBC,
se
- você pretende obter um desempenho razoável. Defina o tamanho do lote JDBC em um
- valor razoável (algo entre 10-50):
- </para>
-
-<programlisting><![CDATA[hibernate.jdbc.batch_size
20]]></programlisting>
-
- <para>
- Você também pode querer rodar esse tipo de processamento de lotes com o cache
- secundário completamente desabilitado:
- </para>
-
-<programlisting><![CDATA[hibernate.cache.use_second_level_cache
false]]></programlisting>
-
- <para>
- Mas isto não é absolutamente necessário, desde que nós possamos ajustar o
- <literal>CacheMode</literal> para desabilitar a interação com o
cache secundário.
- </para>
-
- <sect1 id="batch-inserts">
- <title>Inserção de lotes</title>
-
- <para>
- Quando você estiver inserindo novos objetos persistentes, vocês deve executar
- os métodos <literal>flush()</literal> e
<literal>clear()</literal> regularmente
- na sessão, para controlar o tamanho do cache primário.
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-for ( int i=0; i<100000; i++ ) {
- Customer customer = new Customer(.....);
- session.save(customer);
- if ( i % 20 == 0 ) { //20, same as the JDBC batch size
- //flush a batch of inserts and release memory:
- session.flush();
- session.clear();
- }
-}
-
-tx.commit();
-session.close();]]></programlisting>
-
- </sect1>
-
- <sect1 id="batch-update" >
- <title>Batch updates</title>
-
- <para>
- Para recuperar e atualizar informações a mesma idéia é válida.
Adicionalmente,
- pode precisar usar o <literal>scroll()</literal> para usar
recursos no lado
- do servidor em queries que retornam muita informação.
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-ScrollableResults customers = session.getNamedQuery("GetCustomers")
- .setCacheMode(CacheMode.IGNORE)
- .scroll(ScrollMode.FORWARD_ONLY);
-int count=0;
-while ( customers.next() ) {
- Customer customer = (Customer) customers.get(0);
- customer.updateStuff(...);
- if ( ++count % 20 == 0 ) {
- //flush a batch of updates and release memory:
- session.flush();
- session.clear();
- }
-}
-
-tx.commit();
-session.close();]]></programlisting>
-
- </sect1>
-
- <sect1 id="batch-statelesssession">
- <title>A interface StatelessSession</title>
- <para>
- Alternativamente, o Hibernate provê uma API orientada à comandos, usada para
- transmitir um fluxo de dados de e para o banco de dados na forma de objetos
soltos.
- Uma <literal>StatelessSession</literal> não tem um contexto
persistente associado e
- não fornece muito das semânticas de alto nível para controle do ciclo de
vida.
- Em especial, uma StatelessSession não implemente o cache primário e nem
interage
- com o cache secundário ou query cache. Ele não implementa salvamento
transacional
- automatico ou checagem automática de mudanças. Operação realizadas usando uma
- StatelessSession não fazem nenhum tipo de cascade com as instancias
associadas.
- As coleções são ignoradas por uma StatelessSession. Operações realizadas com
um
- StatelessSession ignoram a arquitetura de eventos e os interceptadores.
- StatelessSession são vulneráveis aos efeitos do aliasing dos dados, devido a
- falta do cache primário. Uma StatelessSession é uma abstração de baixo nível,
- muito mais próxima do JDBC.
- </para>
-
-<programlisting><![CDATA[StatelessSession session =
sessionFactory.openStatelessSession();
-Transaction tx = session.beginTransaction();
-
-ScrollableResults customers = session.getNamedQuery("GetCustomers")
- .scroll(ScrollMode.FORWARD_ONLY);
-while ( customers.next() ) {
- Customer customer = (Customer) customers.get(0);
- customer.updateStuff(...);
- session.update(customer);
-}
-
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- Veja neste exempo, as instancias de <literal>Customer</literal>
retornadas pela query
- são imediatamente desvinculadas. Elas nunca serão assossiadas à um contexto
persistente.
- </para>
-
- <para>
- As operações <literal>insert(), update()</literal> e
<literal>delete()</literal>
- definidos pela interface <literal>StatelessSession</literal> são
considerados
- operações diretas no banco de dados (row-level operations), isso resulta em
uma
- execução imediata de comandos SQL <literal>INSERT,
UPDATE</literal> ou
- <literal>DELETE</literal> respectivamente. Devido a isso, eles
possuem uma
- semântica bem diferente das operações <literal>save(),
saveOrUpdate()</literal>
- ou <literal>delete()</literal> definidas na interface
<literal>Session</literal>.
- </para>
-
- </sect1>
-
- <sect1 id="batch-direct" revision="3">
- <title>Operações no estilo DML</title>
-
- <para>
- Como já discutido, mapeamento objeto/relacional automático e transparente é
conseguido
- com a gerência do estado do objeto. Com isto o estado daquele objeto fica
disponível na
- memória, manipulando(usando as expressões SQL <literal>Data
Manipulation Language</literal>
- (SQL-style DML): <literal>INSERT</literal>,
<literal>UPDATE</literal>, <literal>DELETE</literal>)
- os dados diretamente no banco de dados não irá afetar o estado registrado em
memória.
- Entretanto, o Hibernate provê métodos para executar queries SQL-style DML,
que são
- totalmente executas com HQL (Hibernate Query Language)
- (<xref linkend="queryhql">HQL</xref>).
- </para>
-
- <para>
- A pseudo-sintaxe para expressões <literal>UPDATE</literal> e
<literal>DELETE</literal> é:
- <literal>( UPDATE | DELETE ) FROM? NomeEntidade (WHERE
condições_where)?</literal>.
- Algumas observações:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Na clausula from, a palavra chave FROM é opcional;
- </para>
- </listitem>
- <listitem>
- <para>
- Somente uma entidade pode ser chamada na clausula from; opcionalmente
pode ter
- um alias. Se o nome da entidade for possuir um alias, então qualquer
propriedade
- referenciada deve usar esse alias qualificado; se o nome da entidade
não possuir
- um alias, então nenhuma das propriedade precisa usar o acesso
qualificado.
- </para>
- </listitem>
- <listitem>
- <para>
- Na <xref linkend="queryhql-joins-forms">joins</xref>
(ambas implícita ou explicita)
- pode ser especificada em um bulk HQL query. Sub-queries podem ser usadas na
clausula
- where; as subqueries podem conter joins.
- </para>
- </listitem>
- <listitem>
- <para>
- A clausula where também é opcional.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Como exemplo para executar um HQL <literal>UPDATE</literal>, use
o
- método <literal>Query.executeUpdate()</literal>(o método ganhou o
nome
- devido a sua familiaridade com o do JDBC
- <literal>PreparedStatement.executeUpdate()</literal>):
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-String hqlUpdate = "update Customer c set c.name = :newName where c.name =
:oldName";
-// or String hqlUpdate = "update Customer set name = :newName where name =
:oldName";
-int updatedEntities = s.createQuery( hqlUpdate )
- .setString( "newName", newName )
- .setString( "oldName", oldName )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- HQL <literal>UPDATE</literal> statements, by default do not
effect the
- <xref
linkend="mapping-declaration-version">version</xref>
- or the <xref
linkend="mapping-declaration-timestamp">timestamp</xref> property
values
- for the affected entities; this is in keeping with the EJB3 specification.
However,
- you can force Hibernate to properly reset the
<literal>version</literal> or
- <literal>timestamp</literal> property values through the use of a
<literal>versioned update</literal>.
- This is achieved by adding the <literal>VERSIONED</literal>
keyword after the <literal>UPDATE</literal>
- keyword.
-
- </para>
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-String hqlVersionedUpdate = "update versioned Customer set name = :newName where
name = :oldName";
-int updatedEntities = s.createQuery( hqlUpdate )
- .setString( "newName", newName )
- .setString( "oldName", oldName )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- Note that custom version types
(<literal>org.hibernate.usertype.UserVersionType</literal>)
- are not allowed in conjunction with a <literal>update
versioned</literal> statement.
- </para>
-
- <para>
-
- Para executar um HQL <literal>DELETE</literal>, use o mesmo
método
- <literal>Query.executeUpdate()</literal>:
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-String hqlDelete = "delete Customer c where c.name = :oldName";
-// or String hqlDelete = "delete Customer where name = :oldName";
-int deletedEntities = s.createQuery( hqlDelete )
- .setString( "oldName", oldName )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- <para>
- O valor <literal>int</literal> retornado pelo método
<literal>Query.executeUpdate()</literal>
- indica o numero de entidade afetadas pela operação. Lembre-se que isso pode
estar ou não
- relacionado ao número de linhas alteradas no banco de dados. Uma operação
bulk HQL pode resultar
- em várias expressões SQL reais a serem executadas, por exemplo, no caso de
joined-subclass.
- O número retornado indica a quantidade real de entidades afetadas pela
expressão. Voltando
- ao exemplo da joined-subclass, a exclusão de uma das subclasses pode resultar
numa
- exclusão em outra tabelas, não apenas na tabela para qual a subclasses está
mapeada, mas
- também tabela "root" e possivelmente nas tabelas joined-subclass
num nível hierárquico
- imediatamente abaixo.
- </para>
-
- <para>
-
- A pseudo-sintaxe para o comando <literal>INSERT</literal> é:
- <literal>INSERT INTO EntityName properties_list
select_statement</literal>. Alguns
- pontos a observar:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Apenas a forma INSERT INTO ... SELECT ... é suportada; INSERT INTO
... VALUES ...
- não é suportada.
- </para>
- <para>
- A lista de propriedade é análoga à <literal>especificação da
coluna</literal>
- do comando SQL <literal>INSERT</literal>. Para entidades
envolvidas em mapeamentos,
- apenas a propriedades definidas diretamente a nível da classe podem
ser usandas na
- properties_list. Propriedades da superclass não são permitidas; e as
propriedades
- da subclasse não faz sentido. Em outras palavras, os comandos
- <literal>INSERT</literal> não são polimorficos.
- </para>
- </listitem>
- <listitem>
- <para>
- O camando select pode ser qualquer query HQL válida, que tenha um
retorno compatível
- com o tipo com o esperado pela inclusão. Atualmente, isto é
verificado durante a compilação
- da query, isto é melhor do que permitir que a verificação chegue ao
banco de dados.
- Entretanto perceba que isso pode causar problemas entre os
<literal>Tipo</literal> do Hibernate
- que são <emphasis>equivalentes</emphasis> em oposição a
<emphasis>equal</emphasis>.
- Isso pode causar problemas nas combinações entre a propriedade
definida como
- <literal>org.hibernate.type.DateType</literal>e um
propriedade definida como
- <literal>org.hibernate.type.TimestampType</literal>,
embora o banco de dados não possa
- fazer uma distinção ou possa ser capaz de manusear a conversão.
- </para>
- </listitem>
- <listitem>
- <para>
- Para a propriedade id, a expressão insert oferece duas opções. Você
pode especificar
- qualquer propriedade id explicitamente no properties_list (em alguns
casos esse valor
- é obtido diretamente da expressão select) ou pode omitir do
properties_list (nesse caso,
- um valor gerado é usado). Essa ultima opção só é válida quando são
usados geradores de ids
- que operam no banco de dados; a tentativa de usar essa opção com
geradores do tipo
- "em memória" vai causar um exceção durante a etapa de
parser. Veja a finalidades desta
- discussão, os seguintes geradores operam com o banco de dados
- <literal>org.hibernate.id.SequenceGenerator</literal> (e
suas subclasses)
- e qualquer implementação de
<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
- Aqui, a exceção mais notável é o
<literal>org.hibernate.id.TableHiLoGenerator</literal>, que
- não pode ser usado porque ele não dispõe de mecanismos para recuperar
o seu valor.
- </para>
- </listitem>
- <listitem>
- <para>
- For properties mapped as either
<literal>version</literal> or <literal>timestamp</literal>,
- the insert statement gives you two options. You can either specify
the property in the
- properties_list (in which case its value is taken from the
corresponding select expressions)
- or omit it from the properties_list (in which case the
<literal>seed value</literal> defined
- by the <literal>org.hibernate.type.VersionType</literal>
is used).
-
- Para propriedades mapeadas como
<literal>version</literal> ou <literal>timestamp</literal>,
- a expressão insert oferece a você duas opções. Você pode especificar
a propriedade na
- properties_list (nesse caso o seu valor é obtido a partir da
expressão select correspondente)
- ou ele pode ser omitido da properties_list (neste caso o usa o
<literal>valor semente</literal>
- definido pela classe
<literal>org.hibernate.type.VersionType</literal>).
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Exemplo da execução de um HQL <literal>INSERT</literal>:
- </para>
-
-<programlisting><![CDATA[Session session = sessionFactory.openSession();
-Transaction tx = session.beginTransaction();
-
-String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name
from Customer c where ...";
-int createdEntities = s.createQuery( hqlInsert )
- .executeUpdate();
-tx.commit();
-session.close();]]></programlisting>
-
- </sect1>
-
-</chapter>
+<chapter id="batch">
+ <title>Processamento de lotes</title>
+
+ <para>
+ Uma alternativa para inserir 100.000 linhas no banco de dados usando o Hibernate
+ pode ser a seguinte:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Isto irá falhar em algum lugar próximo a linha 50.000, lançando uma
+ <literal>OutOfMemoryException</literal>. Isso ocorre devido ao fato
do Hibernate
+ fazer cache de todas as instâncias de <literal>Customer</literal>
inseridas num
+ cachê em nível de sessão.
+ </para>
+
+ <para>
+ Neste capítulo veremos como contornar esse problema. Entretanto, se você vai
realizar
+ processamento de lotes, é muito importante que você habilite o uso de lotes JDBC,
se
+ você pretende obter um desempenho razoável. Defina o tamanho do lote JDBC em um
+ valor razoável (algo entre 10-50):
+ </para>
+
+<programlisting><![CDATA[hibernate.jdbc.batch_size
20]]></programlisting>
+
+ <para>
+ Você também pode querer rodar esse tipo de processamento de lotes com o cache
+ secundário completamente desabilitado:
+ </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache
false]]></programlisting>
+<para id="disablebatching" revision="1">
+ Note that Hibernate disables insert batching at the JDBC level transparently if you
+ use an <literal>identiy</literal> identifier generator.
+</para>
+
+ <para>
+ Mas isto não é absolutamente necessário, desde que nós possamos ajustar o
+ <literal>CacheMode</literal> para desabilitar a interação com o
cache secundário.
+ </para>
+
+ <sect1 id="batch-inserts">
+ <title>Inserção de lotes</title>
+
+ <para>
+ Quando você estiver inserindo novos objetos persistentes, vocês deve executar
+ os métodos <literal>flush()</literal> e
<literal>clear()</literal> regularmente
+ na sessão, para controlar o tamanho do cache primário.
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+ if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+ //flush a batch of inserts and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-update" >
+ <title>Batch updates</title>
+
+ <para>
+ Para recuperar e atualizar informações a mesma idéia é válida.
Adicionalmente,
+ pode precisar usar o <literal>scroll()</literal> para usar
recursos no lado
+ do servidor em queries que retornam muita informação.
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .setCacheMode(CacheMode.IGNORE)
+ .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ if ( ++count % 20 == 0 ) {
+ //flush a batch of updates and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-statelesssession">
+ <title>A interface StatelessSession</title>
+ <para>
+ Alternativamente, o Hibernate provê uma API orientada à comandos, usada para
+ transmitir um fluxo de dados de e para o banco de dados na forma de objetos
soltos.
+ Uma <literal>StatelessSession</literal> não tem um contexto
persistente associado e
+ não fornece muito das semânticas de alto nível para controle do ciclo de
vida.
+ Em especial, uma StatelessSession não implemente o cache primário e nem
interage
+ com o cache secundário ou query cache. Ele não implementa salvamento
transacional
+ automatico ou checagem automática de mudanças. Operação realizadas usando uma
+ StatelessSession não fazem nenhum tipo de cascade com as instancias
associadas.
+ As coleções são ignoradas por uma StatelessSession. Operações realizadas com
um
+ StatelessSession ignoram a arquitetura de eventos e os interceptadores.
+ StatelessSession são vulneráveis aos efeitos do aliasing dos dados, devido a
+ falta do cache primário. Uma StatelessSession é uma abstração de baixo nível,
+ muito mais próxima do JDBC.
+ </para>
+
+<programlisting><![CDATA[StatelessSession session =
sessionFactory.openStatelessSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .scroll(ScrollMode.FORWARD_ONLY);
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ session.update(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Veja neste exempo, as instancias de <literal>Customer</literal>
retornadas pela query
+ são imediatamente desvinculadas. Elas nunca serão assossiadas à um contexto
persistente.
+ </para>
+
+ <para>
+ As operações <literal>insert(), update()</literal> e
<literal>delete()</literal>
+ definidos pela interface <literal>StatelessSession</literal> são
considerados
+ operações diretas no banco de dados (row-level operations), isso resulta em
uma
+ execução imediata de comandos SQL <literal>INSERT,
UPDATE</literal> ou
+ <literal>DELETE</literal> respectivamente. Devido a isso, eles
possuem uma
+ semântica bem diferente das operações <literal>save(),
saveOrUpdate()</literal>
+ ou <literal>delete()</literal> definidas na interface
<literal>Session</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="batch-direct" revision="3">
+ <title>Operações no estilo DML</title>
+
+ <para>
+ Como já discutido, mapeamento objeto/relacional automático e transparente é
conseguido
+ com a gerência do estado do objeto. Com isto o estado daquele objeto fica
disponível na
+ memória, manipulando(usando as expressões SQL <literal>Data
Manipulation Language</literal>
+ (SQL-style DML): <literal>INSERT</literal>,
<literal>UPDATE</literal>, <literal>DELETE</literal>)
+ os dados diretamente no banco de dados não irá afetar o estado registrado em
memória.
+ Entretanto, o Hibernate provê métodos para executar queries SQL-style DML,
que são
+ totalmente executas com HQL (Hibernate Query Language)
+ (<xref linkend="queryhql">HQL</xref>).
+ </para>
+
+ <para>
+ A pseudo-sintaxe para expressões <literal>UPDATE</literal> e
<literal>DELETE</literal> é:
+ <literal>( UPDATE | DELETE ) FROM? NomeEntidade (WHERE
condições_where)?</literal>.
+ Algumas observações:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Na clausula from, a palavra chave FROM é opcional;
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Somente uma entidade pode ser chamada na clausula from; opcionalmente
pode ter
+ um alias. Se o nome da entidade for possuir um alias, então qualquer
propriedade
+ referenciada deve usar esse alias qualificado; se o nome da entidade
não possuir
+ um alias, então nenhuma das propriedade precisa usar o acesso
qualificado.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Na <xref linkend="queryhql-joins-forms">joins</xref>
(ambas implícita ou explicita)
+ pode ser especificada em um bulk HQL query. Sub-queries podem ser usadas na
clausula
+ where; as subqueries podem conter joins.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A clausula where também é opcional.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Como exemplo para executar um HQL <literal>UPDATE</literal>, use
o
+ método <literal>Query.executeUpdate()</literal>(o método ganhou o
nome
+ devido a sua familiaridade com o do JDBC
+ <literal>PreparedStatement.executeUpdate()</literal>):
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlUpdate = "update Customer c set c.name = :newName where c.name =
:oldName";
+// or String hqlUpdate = "update Customer set name = :newName where name =
:oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ HQL <literal>UPDATE</literal> statements, by default do not
effect the
+ <xref
linkend="mapping-declaration-version">version</xref>
+ or the <xref
linkend="mapping-declaration-timestamp">timestamp</xref> property
values
+ for the affected entities; this is in keeping with the EJB3 specification.
However,
+ you can force Hibernate to properly reset the
<literal>version</literal> or
+ <literal>timestamp</literal> property values through the use of a
<literal>versioned update</literal>.
+ This is achieved by adding the <literal>VERSIONED</literal>
keyword after the <literal>UPDATE</literal>
+ keyword.
+
+ </para>
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+String hqlVersionedUpdate = "update versioned Customer set name = :newName where
name = :oldName";
+int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Note that custom version types
(<literal>org.hibernate.usertype.UserVersionType</literal>)
+ are not allowed in conjunction with a <literal>update
versioned</literal> statement.
+ </para>
+
+ <para>
+
+ Para executar um HQL <literal>DELETE</literal>, use o mesmo
método
+ <literal>Query.executeUpdate()</literal>:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlDelete = "delete Customer c where c.name = :oldName";
+// or String hqlDelete = "delete Customer where name = :oldName";
+int deletedEntities = s.createQuery( hqlDelete )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ O valor <literal>int</literal> retornado pelo método
<literal>Query.executeUpdate()</literal>
+ indica o numero de entidade afetadas pela operação. Lembre-se que isso pode
estar ou não
+ relacionado ao número de linhas alteradas no banco de dados. Uma operação
bulk HQL pode resultar
+ em várias expressões SQL reais a serem executadas, por exemplo, no caso de
joined-subclass.
+ O número retornado indica a quantidade real de entidades afetadas pela
expressão. Voltando
+ ao exemplo da joined-subclass, a exclusão de uma das subclasses pode resultar
numa
+ exclusão em outra tabelas, não apenas na tabela para qual a subclasses está
mapeada, mas
+ também tabela "root" e possivelmente nas tabelas joined-subclass
num nível hierárquico
+ imediatamente abaixo.
+ </para>
+
+ <para>
+
+ A pseudo-sintaxe para o comando <literal>INSERT</literal> é:
+ <literal>INSERT INTO EntityName properties_list
select_statement</literal>. Alguns
+ pontos a observar:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Apenas a forma INSERT INTO ... SELECT ... é suportada; INSERT INTO
... VALUES ...
+ não é suportada.
+ </para>
+ <para>
+ A lista de propriedade é análoga à <literal>especificação da
coluna</literal>
+ do comando SQL <literal>INSERT</literal>. Para entidades
envolvidas em mapeamentos,
+ apenas a propriedades definidas diretamente a nível da classe podem
ser usandas na
+ properties_list. Propriedades da superclass não são permitidas; e as
propriedades
+ da subclasse não faz sentido. Em outras palavras, os comandos
+ <literal>INSERT</literal> não são polimorficos.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ O camando select pode ser qualquer query HQL válida, que tenha um
retorno compatível
+ com o tipo com o esperado pela inclusão. Atualmente, isto é
verificado durante a compilação
+ da query, isto é melhor do que permitir que a verificação chegue ao
banco de dados.
+ Entretanto perceba que isso pode causar problemas entre os
<literal>Tipo</literal> do Hibernate
+ que são <emphasis>equivalentes</emphasis> em oposição a
<emphasis>equal</emphasis>.
+ Isso pode causar problemas nas combinações entre a propriedade
definida como
+ <literal>org.hibernate.type.DateType</literal>e um
propriedade definida como
+ <literal>org.hibernate.type.TimestampType</literal>,
embora o banco de dados não possa
+ fazer uma distinção ou possa ser capaz de manusear a conversão.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Para a propriedade id, a expressão insert oferece duas opções. Você
pode especificar
+ qualquer propriedade id explicitamente no properties_list (em alguns
casos esse valor
+ é obtido diretamente da expressão select) ou pode omitir do
properties_list (nesse caso,
+ um valor gerado é usado). Essa ultima opção só é válida quando são
usados geradores de ids
+ que operam no banco de dados; a tentativa de usar essa opção com
geradores do tipo
+ "em memória" vai causar um exceção durante a etapa de
parser. Veja a finalidades desta
+ discussão, os seguintes geradores operam com o banco de dados
+ <literal>org.hibernate.id.SequenceGenerator</literal> (e
suas subclasses)
+ e qualquer implementação de
<literal>org.hibernate.id.PostInsertIdentifierGenerator</literal>.
+ Aqui, a exceção mais notável é o
<literal>org.hibernate.id.TableHiLoGenerator</literal>, que
+ não pode ser usado porque ele não dispõe de mecanismos para recuperar
o seu valor.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ For properties mapped as either
<literal>version</literal> or <literal>timestamp</literal>,
+ the insert statement gives you two options. You can either specify
the property in the
+ properties_list (in which case its value is taken from the
corresponding select expressions)
+ or omit it from the properties_list (in which case the
<literal>seed value</literal> defined
+ by the <literal>org.hibernate.type.VersionType</literal>
is used).
+
+ Para propriedades mapeadas como
<literal>version</literal> ou <literal>timestamp</literal>,
+ a expressão insert oferece a você duas opções. Você pode especificar
a propriedade na
+ properties_list (nesse caso o seu valor é obtido a partir da
expressão select correspondente)
+ ou ele pode ser omitido da properties_list (neste caso o usa o
<literal>valor semente</literal>
+ definido pela classe
<literal>org.hibernate.type.VersionType</literal>).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Exemplo da execução de um HQL <literal>INSERT</literal>:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name
from Customer c where ...";
+int createdEntities = s.createQuery( hqlInsert )
+ .executeUpdate();
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/best_practices.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/best_practices.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/best_practices.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="best-practices" revision="3">
+<chapter id="best-practices" revision="3">
<title>Boas práticas</title>
<variablelist spacing="compact">
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/collection_mapping.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/collection_mapping.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/collection_mapping.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="collections">
+<chapter id="collections">
<title>Mapeamento de Coleções</title>
<sect1 id="collections-persistent" revision="3">
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/component_mapping.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/component_mapping.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/component_mapping.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="components">
+<chapter id="components">
<title>Mapeamento de Componentes</title>
<para>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/configuration.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/configuration.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/configuration.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,1792 +1,1789 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="session-configuration" revision="1">
-
- <title>Configuração</title>
-
- <para>
- Devido ao fato de o Hibernate ser projetado para operar em vários ambientes
diferentes,
- há um grande número de parâmetros de configuração. Felizmente, a maioria tem
valores default
- lógicos e o Hibernate é distribuído com um arquivo
<literal>hibernate.properties</literal>
- de exemplo no <literal>etc/</literal> que mostra várias opções.
Apenas coloque o arquivo
- de exemplo no seu classpath e personalize-o.
- </para>
-
- <sect1 id="configuration-programmatic" revision="1">
- <title>1.11 Configuração programática</title>
-
- <para>
- Uma instância de
<literal>org.hibernate.cfg.Configuration</literal>
- representa um conjunto inteiro de mapeamentos de tipos Java da aplicação para
- um banco de dados SQL. O <literal>Configuration</literal> é usado
para construir
- uma <literal>SessionFactory</literal> (imutável). Os mapeamentos
são compilados
- a partir de arquivos de mapeamento XML.
-
- </para>
-
- <para>
- Você pode obter uma instância <literal>Configuration</literal>
intanciando-
- o diretamente e especificando documentos de mapeamento XML. Se o arquivo
- de mapeamento estão no classpath, use use
<literal>addResource()</literal>:
- </para>
-
- <programlisting><![CDATA[Configuration cfg = new Configuration()
- .addResource("Item.hbm.xml")
- .addResource("Bid.hbm.xml");]]></programlisting>
-
- <para>
- Uma alternativa (às vezes melhor) é especificar a classe mapeada,
- e permitir que o Hibernate encontre o documento de mapeamento para você:
- </para>
-
- <programlisting><![CDATA[Configuration cfg = new Configuration()
- .addClass(org.hibernate.auction.Item.class)
- .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
-
- <para>
- Então o Hibernate procurará pelos arquivos de mapeamento chamados
- <literal>/org/hibernate/auction/Item.hbm.xml</literal> e
- <literal>/org/hibernate/auction/Bid.hbm.xml</literal> no
classpath.
- Esta abordagem elimina qualquer nome de arquivo de difícil compreensão.
- </para>
-
- <para>
- Uma <literal>Configuration</literal> também permite você
especificar
- propriedades de configuração:
- </para>
-
- <programlisting><![CDATA[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");]]></programlisting>
-
- <para>
- Este não é o único caminho para passar as propriedades de configuração
- para o Hibernate. As várias opções incluem:
- </para>
-
- <orderedlist spacing="compact">
- <listitem>
- <para>
- Passar uma instância de
<literal>java.util.Properties</literal>
- para <literal>Configuration.setProperties()</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Colocar <literal>hibernate.properties</literal> no
diretório
- raiz do classpath.
- </para>
- </listitem>
- <listitem>
- <para>
- Determinar as propriedades do <literal>System</literal>
- usando <literal>java -Dproperty=value</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Include <literal><property></literal>
elements in
- <literal>hibernate.cfg.xml</literal> (discussed later).
- Incluir elementos
<literal><property></literal> no
- <literal>hibernate.cfg.xml</literal> (discutido mais
tarde).
- </para>
- </listitem>
- </orderedlist>
-
- <para>
- <literal>hibernate.properties</literal> é o caminho mais facil
- se você quer começar mais rápido.
- </para>
-
- <para>
- O <literal>Configuration</literal> é entendido como um objeto
startup-time,
- é descartado uma vez que a <literal>SessionFactory</literal> é
criada.
- </para>
-
- </sect1>
-
- <sect1 id="configuration-sessionfactory">
- <title>Obtendo uma SessionFactory</title>
-
- <para>
- Quando todos os mapeamentos têm sido analisados pelo
<literal>Configuration</literal>,
- a aplicação deve obter uma factory para as instâncias da
<literal>Session</literal>.
- O objetivo desta factory é ser compartilhado por todas as threads da
aplicação:
- </para>
-
- <programlisting><![CDATA[SessionFactory sessions =
cfg.buildSessionFactory();]]></programlisting>
-
- <para>
- Hibernate permite sua aplicação instanciar mais do que uma
- <literal>SessionFactory</literal>. Isto é útil se você está
usando mais
- do que um banco de dados.
- </para>
-
- </sect1>
-
- <sect1 id="configuration-hibernatejdbc" revision="1">
- <title>Conexões JDBC</title>
-
- <para>
- Normalmente, você quer mandar criar a
<literal>SessionFactory</literal> criar um
- pool de conexões JDBC para você. Se você seguir essa abordagem, a abertura de
uma
- <literal>Session</literal> é tão simples quanto:
-
- </para>
-
- <programlisting><![CDATA[Session session = sessions.openSession(); //
open a new Session]]></programlisting>
-
- <para>
- Assim que você fizer algo que requer o acesso ao banco de dados, uma
- conexão JDBC será obtida do pool.
- </para>
-
- <para>
- Para esse trabalho, nós necessitamos passar algumas propriedades da conexão
JDBC
- para o Hibernate. Todos os nomes de propriedades Hibernate e semânticas são
definidas
- <literal>org.hibernate.cfg.Environment</literal>. Nós iremos
descrever agora
- o mais importantes configurações de conexão JDBC.
- </para>
-
- <para>
- O Hibernate obterá conexões( e pool) usando
<literal>java.sql.DriverManager</literal>
- se você determinar as seguintes propriedades:
- </para>
-
- <table frame="topbot">
- <title>Propriedades JDBC Hibernate</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <literal>hibernate.connection.driver_class</literal>
- </entry>
- <entry>
- <emphasis>Classe driver jdbc</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.url</literal>
- </entry>
- <entry>
- <emphasis>URL jdbc</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.username</literal>
- </entry>
- <entry>
- <emphasis>Usuário do banco de dados</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.password</literal>
- </entry>
- <entry>
- <emphasis>Senha do usuário do banco de dados</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.pool_size</literal>
- </entry>
- <entry>
- <emphasis>Número máximo de connecxões no pool</emphasis>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- O algoritmo de pool de conexões do próprio Hibernate entretanto é
completamente
- rudimentar. A intenção dele e ajudar a iniciar e <emphasis>não para
usar em um
- sistema de produção</emphasis> ou até para testar desempenho. Você
deveria usar
- uma ferramente de pool de terceiros para conseguir melhor desempenho e
estabilidade.
- Apenas especifique a propriedade
<literal>hibernate.connection.pool_size</literal>
- com a definição do pool de conexões. Isto irá desligar o pool interno do
Hibernate.
- Por exemplo, você pode gostar de usar C3P0.
- </para>
-
- <para>
- O C3P0 é um pool conexão JDBC de código aberto distribuído junto com
- Hibernate no diretório <literal>lib</literal>. O Hibernate
usará o
- <literal>C3P0ConnectionProvider</literal> para o pool de conexão
se
- você configurar a propriedade
<literal>hibernate.c3p0.*</literal>. Se você
- gostar de usar Proxool consulte ao pacote
<literal>hibernate.properties</literal>
- e o web site do Hibernate para mais informações.
- </para>
-
- <para>
- Aqui é um exemplo de arquivo
<literal>hibernate.properties</literal> para C3P0:
- </para>
-
- <programlisting id="c3p0-configuration"
revision="1"><![CDATA[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]]></programlisting>
-
- <para>
- Para usar dentro de um servidor de aplicação, você deve configurar
- o Hibernate para obter conexões de um application server
- <literal>Datasource</literal> registrado no JNDI. Você
necessitará
- determinar pelo menos uma das seguintes propriedades:
- </para>
-
- <table frame="topbot">
- <title>Propriedades do Datasource do Hibernate</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <literal>hibernate.connection.datasource</literal>
- </entry>
- <entry>
- <emphasis>Nome datasource JNDI</emphasis>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.jndi.url</literal>
- </entry>
- <entry>
- <emphasis>URL do fornecedor JNDI</emphasis> (opcional)
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.jndi.class</literal>
- </entry>
- <entry>
- <emphasis>Classe do JNDI
<literal>InitialContextFactory</literal></emphasis> (opcional)
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.username</literal>
- </entry>
- <entry>
- <emphasis>Usuário do banco de dados</emphasis>
(opcional)
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.password</literal>
- </entry>
- <entry>
- <emphasis>Senha do usuário do banco de dados</emphasis>
(opcional)
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- Eis um exemplo de arquivo <literal>hibernate.properties</literal>
para
- um servidor de aplicação fornecedor de datasources JNDI:
- </para>
-
- <programlisting><![CDATA[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]]></programlisting>
-
- <para>
- Conexões JDBC obtidas de um datasource JNDI irão automaticamente irão
participar
- das transações gerenciadas pelo container no servidor de aplicação.
- </para>
-
- <para>
- Arbitrariamente as propriedades de conexão podem ser acrescentandas ao
- "<literal>hibernate.connnection</literal>" ao nome da
propriedade. Por exemplo,
- você deve especificar o <literal>charSet</literal> usando
<literal>hibernate.connection.charSet</literal>.t.
- </para>
-
- <para>
- Você pode definir sua própria estratégia de plugin para obter conexões JDBC
implementando
- a interface
<literal>org.hibernate.connection.ConnectionProvider</literal>. Você pode
- escolher uma implementação customizada setando
<literal>hibernate.connection.provider_class</literal>.
- </para>
-
- </sect1>
-
- <sect1 id="configuration-optional" revision="1">
- <title>Propriedades opcionais de configuração</title>
-
- <para>
- Há um grande número de outras propriedades que controlam o comportamento do
Hibernate
- em tempo de execução. Todos são opcionais e tem valores default lógicos.
- </para>
-
- <para>
- <emphasis>Aviso: algumas destas propriedades são somente a "nível
de sistema".</emphasis>
- Propriedades nível de sistema podem ser determinados somente via
<literal>java -Dproperty=value</literal>
- ou <literal>hibernate.properties</literal>. Elas
<emphasis>não</emphasis>podem ser
- configuradas por outras técnicas descritas abaixo.
- </para>
-
- <table frame="topbot"
id="configuration-optional-properties" revision="8">
- <title>Hibernate Configuration Properties</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <literal>hibernate.dialect</literal>
- </entry>
- <entry>
- O nome da classe de um <literal>Dialeto</literal>
- que permite o Hibernate gerar SQL otimizado para um banco de
- dados relacional em particular.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>full.classname.of.Dialect</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.show_sql</literal>
- </entry>
- <entry>
- Escreve todas as instruções SQL no console. Esta é uma
alternativa
- a configurar a categoria de log
<literal>org.hibernate.SQL</literal>
- para <literal>debug</literal>.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.format_sql</literal>
- </entry>
- <entry>
- Imprime o SQL formatado no log e console.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.default_schema</literal>
- </entry>
- <entry>
- Qualifica no sql gerado, os nome das tabelas sem qualificar
- com schena/tablespace dado
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>SCHEMA_NAME</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.default_catalog</literal>
- </entry>
- <entry>
- Qualifica no sql gerado, os nome das tabelas sem qualificar
- com catálogo dado
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>CATALOG_NAME</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.session_factory_name</literal>
- </entry>
- <entry>
- O <literal>SessionFactory</literal> irá
automaticamente
- se ligar a este nome no JNDI depois de ter sido criado.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>jndi/composite/name</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.max_fetch_depth</literal>
- </entry>
- <entry>
- Estabelece a "profundidade" máxima para árvore
outer join fetch
- para associações finais únicas(one-to-one,many-to-one).
- Um <literal>0</literal> desativa por default a
busca outer join.
- <para>
- <emphasis
role="strong">eg.</emphasis>
- Valores recomendados
entre<literal>0</literal> e <literal>3</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.default_batch_fetch_size</literal>
- </entry>
- <entry>
- Determina um tamanho default para busca de associações em
lotes do Hibernate
- <para>
- <emphasis
role="strong">eg.</emphasis>
- Valores recomendados <literal>4</literal>,
<literal>8</literal>,
- <literal>16</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.default_entity_mode</literal>
- </entry>
- <entry>
- Determina um modo default para representação de entidades
- para todas as sessões abertas desta
<literal>SessionFactory</literal>
- <para>
- <literal>dynamic-map</literal>,
<literal>dom4j</literal>,
- <literal>pojo</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.order_updates</literal>
- </entry>
- <entry>
- Força o Hibernate a ordenar os updates SQL pelo valor da
chave
- primária dos itens a serem atualizados. Isto resultará em
menos
- deadlocks nas transações em sistemas altamente concorrente.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.generate_statistics</literal>
- </entry>
- <entry>
- If enabled, Hibernate will collect statistics useful for
- performance tuning.
- Se habilitado, o Hibernate coletará estatísticas úties
- para performance tuning dos bancos.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.use_identifer_rollback</literal>
- </entry>
- <entry>
- Se habilitado, propriedades identificadoras geradas
- serão zeradas para os valores default quando os
- objetos forem apagados.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.use_sql_comments</literal>
- </entry>
- <entry>
- Se ligado, o Hibernate irá gerar comentários dentro do SQL,
- para facilitar o debugging, o valor default é
<literal>false</literal>.
- <para>
- <emphasis
role="strong">eg.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table frame="topbot" id="configuration-jdbc-properties"
revision="8">
- <title>JDBC Hibernate e Propriedades de Conexão</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
- <literal>hibernate.jdbc.fetch_size</literal>
- </entry>
- <entry>
- Um valor maior que zero determina o tamanho do fetch
- do JDBC( chamadas
<literal>Statement.setFetchSize()</literal>).
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.jdbc.batch_size</literal>
- </entry>
- <entry>
- Um valor maior que zero habilita uso de batch updates JDBC2
pelo Hibernate.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- valores recomentados entre
<literal>5</literal> e <literal>30</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.jdbc.batch_versioned_data</literal>
- </entry>
- <entry>
- Sete esta propriedade como
<literal>true</literal> se seu driver JDBC retorna
- o número correto de linhas no
<literal>executeBatch()</literal> ( É usualmente
- seguro tornar esta opção ligada). O Hibernate então irá usar
betched DML
- para automaticamente versionar dados.
<literal>false</literal> por default.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.jdbc.factory_class</literal>
- </entry>
- <entry>
- Escolher um <literal>Batcher</literal>
customizado. Muitas
- aplicações não irão necessitar desta propriedade de
configuração
- <para>
- <emphasis
role="strong">Ex.</emphasis>
-
<literal>classname.of.BatcherFactory</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.jdbc.use_scrollable_resultset</literal>
- </entry>
- <entry>
- Habilita o uso de JDBC2 scrollable resultsets pelo
Hibernate.
- Essa propriedade somente é necessaria quando se usa
Conexeções
- JDBC providas pelo usuário, caso contrário o Hibernate os os
- metadados da conexão.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.jdbc.use_streams_for_binary</literal>
- </entry>
- <entry>
- Use streams para escrever/ler tipos
<literal>binary</literal>
- ou <literal>serializable</literal> para/a o JDBC(
propriedade a nível de sistema).
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.jdbc.use_get_generated_keys</literal>
- </entry>
- <entry>
- Possibilita o uso
<literal>PreparedStatement.getGeneratedKeys()</literal>
- do JDBC3 para recuperar chaves geradas nativamente depois da
inserçãp.
- Requer driver JDBC3+ e JRE1.4+, determine para false se seu
driver tem
- problemas com gerador de indentificadores Hibernate. Por
default, tente
- determinar o driver capaz de usar metadados da conexão.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true|false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.connection.provider_class</literal>
- </entry>
- <entry>
- O nome da classe de um
<literal>ConnectionProvider</literal> personalizado
- o qual proverá conexões JDBC para o Hibernate.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
-
<literal>classname.of.ConnectionProvider</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.connection.isolation</literal>
- </entry>
- <entry>
- Determina o nível de isolamento de uma transação JDBC.
- Verifique <literal>java.sql.Connection</literal> para
valores
- siginificativos mas note que a maior parte dos bancos de dados
- não suportam todos os níveis de isolamento.
- <para>
- <emphasis role="strong">Ex.</emphasis>
- <literal>1, 2, 4, 8</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.connection.autocommit</literal>
- </entry>
- <entry>
- Habilita autocommit para conexões no pool JDBC( não
recomendado).
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.connection.release_mode</literal>
- </entry>
- <entry>
- Especifica quando o Hibernate deve liberar conexões JDBC. Por
default,
- uma conexão JDBC é retida até a sessão está explicitamente
fechada
- ou desconectada. Para um datasource JTA do servidor de
aplicação, você deve
- usar <literal>after_statement</literal> para
forçar s 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
- <literal>after_transaction</literal>.
<literal>auto</literal> escolheremos
- <literal>after_statement</literal> para as
estratégias de transaçãoes JTA e CMT
- e <literal>after_transaction</literal> para as
estratégias de transação JDBC
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>auto</literal> (default) |
<literal>on_close</literal> |
- <literal>after_transaction</literal> |
<literal>after_statement</literal>
- </para>
- <para>
- Note that this setting only affects
<literal>Session</literal>s returned from
-
<literal>SessionFactory.openSession</literal>. For
<literal>Session</literal>s
- obtained through
<literal>SessionFactory.getCurrentSession</literal>, the
- <literal>CurrentSessionContext</literal>
implementation configured for use
- controls the connection release mode for those
<literal>Session</literal>s.
- See <xref
linkend="architecture-current-session"/>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.connection.<emphasis><propertyName></emphasis></literal>
- </entry>
- <entry>
- Passa a propriedade JDBC
<literal>propertyName</literal>
- para
<literal>DriverManager.getConnection()</literal>.
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.jndi.<emphasis><propertyName></emphasis></literal>
- </entry>
- <entry>
- Passar a propriedade
<literal>propertyName</literal> para
- o <literal>InitialContextFactory</literal> JNDI.
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table frame="topbot" id="configuration-cache-properties"
revision="7">
- <title>Propriedades de Cachê do Hibernate</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
-
<literal>hibernate.cache.provider_class</literal>
- </entry>
- <entry>
- O nome da classe de um
<literal>CacheProvider</literal> customizado.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
-
<literal>classname.of.CacheProvider</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.cache.use_minimal_puts</literal>
- </entry>
- <entry>
- Otimizar operação de cachê de segundo nível para minimizar
escritas,
- ao custo de leituras mais frequantes. Esta configuração é
mais útil
- para cachês clusterizados e, no Hibernate3, é habilitado por
default
- para implementações de cachê clusterizar.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true|false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.cache.use_query_cache</literal>
- </entry>
- <entry>
- Habilita a cache de consultas, Mesmo assim, consultas
individuais ainda tem que ser
- habilitadas para o cache.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true|false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.cache.use_second_level_cache</literal>
- </entry>
- <entry>
- May be used to completely disable the second level cache,
which is enabled
- by default for classes which specify a
<literal><cache></literal>
- mapping.
- Pode ser usada para desabilitar completamente ocache de
segundo nível,
- o qual está habilitado por default para classes que
especificam
- um mapeamento
<literal><cache></literal>.
-
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true|false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.cache.query_cache_factory</literal>
- </entry>
- <entry>
- O nome de uma classe que implementa a interface
- <literal>QueryCache</literal> personalizada, por
- default, um
<literal>StandardQueryCache</literal>
- criado automaticamente.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>classname.of.QueryCache</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.cache.region_prefix</literal>
- </entry>
- <entry>
- Um prefixo para usar nos nomes da área especial
- do cachê de segundo nível.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>prefix</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.cache.use_structured_entries</literal>
- </entry>
- <entry>
- Forces Hibernate to store data in the second-level cache
- in a more human-friendly format.
- Força o Hibernate armazenar dados no cachê se segundo
- nível em um formato mais legivel.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true|false</literal>
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table frame="topbot"
id="configuration-transaction-properties" revision="9">
- <title>Propriedades de Transação do Hibernate</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
-
<literal>hibernate.transaction.factory_class</literal>
- </entry>
- <entry>
- O nome da clase de um a
<literal>TransactionFactory</literal>
- para usar com API <literal>Transaction</literal>
- ( por default JDBCTransactionFactory).
- <para>
- <emphasis
role="strong">Ex.</emphasis>
-
<literal>classname.of.TransactionFactory</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>jta.UserTransaction</literal>
- </entry>
- <entry>
- Um nome JNDI usado pelo
<literal>JTATransactionFactory</literal>
- para obter uma <literal>UserTransaction</literal>
JTA a partir
- do servidor de aplicação.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>jndi/composite/name</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.transaction.manager_lookup_class</literal>
- </entry>
- <entry>
- O nome da classe de um
<literal>TransactionManagerLookup</literal>
- – requerido quando caching a nível JVM esta habilitado ou
quando
- estivermos usando um generator hilo em um ambiente JTA.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
-
<literal>classname.of.TransactionManagerLookup</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.transaction.flush_before_completion</literal>
- </entry>
- <entry>
- Se habilitado, a sessão será automaticamente limpa antes da
fase de
- conclusão da transação. É preferivel a gerência interna e
- automática do contexto da sessão, veja
- <xref
linkend="architecture-current-session"/>
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.transaction.auto_close_session</literal>
- </entry>
- <entry>
- Se habilitado, a sessão será automaticamente fechada após a
fase de
- conclusão da transação. É preferivel a gerência interna e
- automática do contexto da sessão, veja
- <xref
linkend="architecture-current-session"/>
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <table frame="topbot" id="configuration-misc-properties"
revision="10">
- <title>Propriedades Variadas</title>
- <tgroup cols="2">
- <colspec colname="c1" colwidth="1*"/>
- <colspec colname="c2" colwidth="1*"/>
- <thead>
- <row>
- <entry>Nome da Propriedade</entry>
- <entry>Propósito</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>
-
<literal>hibernate.current_session_context_class</literal>
- </entry>
- <entry>
- Forneçe uma estratégia (personalizada) para extensão
- da <literal>Session</literal>
"corrente". Veja
- <xref
linkend="architecture-current-session"/> para
- mais informação sobre estratégias internas.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>jta</literal> |
<literal>thread</literal> |
- <literal>managed</literal> |
<literal>custom.Class</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.query.factory_class</literal>
- </entry>
- <entry>
- Escolha a implementação de análise HQL.
- <para>
- <emphasis
role="strong">eg.</emphasis>
-
<literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
-
<literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.query.substitutions</literal>
- </entry>
- <entry>
- Mapeamento a partir de símbolos em consultas HQL para
- símbolos SQL( símbolos devem ser funções ou nome literais
- , por exemplo).
- <para>
- <emphasis
role="strong">eg.</emphasis>
- <literal>hqlLiteral=SQL_LITERAL,
hqlFunction=SQLFUNC</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
- <literal>hibernate.hbm2ddl.auto</literal>
- </entry>
- <entry>
- Automaticamente valida ou exporta schema DDL para o banco de
- dados quando o <literal>SessionFactory</literal>
é criads.
- Com <literal>create-drop</literal>, o schema do
banco de dados
- será excluido quando a
<literal>create-drop</literal> for
- fechada esplicitamente.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>validate</literal> |
<literal>update</literal> |
- <literal>create</literal> |
<literal>create-drop</literal>
- </para>
- </entry>
- </row>
- <row>
- <entry>
-
<literal>hibernate.cglib.use_reflection_optimizer</literal>
- </entry>
- <entry>
- Habilita o uso de CGLIB em vez de reflexão em tempo de
execução
- ( propriedade a nível de sistema). Reflexão pode algumas
vezes ser ú
- til quando controlar erros, note que o Hibernate sempre irá
requerer a CGLIB
- mesmo se você desligar o otimizador. Você não pode determinar
esta
- propriedade no hibernate.cfg.xml.
- <para>
- <emphasis
role="strong">Ex.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
- </para>
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <sect2 id="configuration-optional-dialects"
revision="1">
- <title>Dialetos SQL</title>
-
- <para>
- Você deve sempre determinar a propriedade
<literal>hibernate.dialect</literal>
- para a subclasse de
<literal>org.hibernate.dialect.Dialect</literal> correta de seu
- banco de dados. Se você especificar um dialeto, Hibernate usará defaults
lógicos
- para qualquer um das outras propriedades listadas abaixo, reduzindo o
esforço de
- especificá-los manualmente.
- </para>
-
- <table frame="topbot" id="sql-dialects"
revision="2">
- <title>Hibernate SQL Dialects
(<literal>hibernate.dialect</literal>)</title>
- <tgroup cols="2">
- <colspec colwidth="1*"/>
- <colspec colwidth="2.5*"/>
- <thead>
- <row>
- <entry>RDBMS</entry>
- <entry>Dialect</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry>DB2</entry>
<entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
- </row>
- <row>
- <entry>DB2 AS/400</entry>
<entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
- </row>
- <row>
- <entry>DB2 OS390</entry>
<entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
- </row>
- <row>
- <entry>PostgreSQL</entry>
<entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
- </row>
- <row>
- <entry>MySQL</entry>
<entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
- </row>
- <row>
- <entry>MySQL with InnoDB</entry>
<entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
- </row>
- <row>
- <entry>MySQL with MyISAM</entry>
<entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
- </row>
- <row>
- <entry>Oracle (any version)</entry>
<entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
- </row>
- <row>
- <entry>Oracle 9i/10g</entry>
<entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
- </row>
- <row>
- <entry>Sybase</entry>
<entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
- </row>
- <row>
- <entry>Sybase Anywhere</entry>
<entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
- </row>
- <row>
- <entry>Microsoft SQL Server</entry>
<entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
- </row>
- <row>
- <entry>SAP DB</entry>
<entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
- </row>
- <row>
- <entry>Informix</entry>
<entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
- </row>
- <row>
- <entry>HypersonicSQL</entry>
<entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
- </row>
- <row>
- <entry>Ingres</entry>
<entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
- </row>
- <row>
- <entry>Progress</entry>
<entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
- </row>
- <row>
- <entry>Mckoi SQL</entry>
<entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
- </row>
- <row>
- <entry>Interbase</entry>
<entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
- </row>
- <row>
- <entry>Pointbase</entry>
<entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
- </row>
- <row>
- <entry>FrontBase</entry>
<entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
- </row>
- <row>
- <entry>Firebird</entry>
<entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- </sect2>
-
- <sect2 id="configuration-optional-outerjoin"
revision="4">
- <title>Recuperação por união externa (Outer Join
Fetching)</title>
-
- <para>
- Se seu banco de dados suporta Recuperação por união externa (Outer Join
Fetching) no estilo ANSI,
- Oracle ou Sybase, A recuperação por união externa (Outer Join Fetching)
frequentemente aumentará
- o desempenho limitando o número de chamadas (round trips) ao banco de
dados( ao custo de
- possivelmente mais trabalho desempenhado pelo próprio banco de dados). A
recuperação por
- união externa (Outer Join Fetching)permite um gráfico completo de objetos
conectados
- por muitos-para-um, um-para-muitos, muitos-para-muitos e associações
um-para-um para ser
- recuperadas em um simples instrução SQL SELECT .
-
- </para>
-
- <para>
- A recuperação por união externa (Outer Join Fetching) pode ser
desabilitado
- <emphasis>globalmente</emphasis> setando a propriedade
- <literal>hibernate.max_fetch_depth</literal> para
<literal>0</literal>.
- Uma valor 1 ou maior habilita o outer join fetching para associações
um-para-um
- e muitos-para-umos cujos quais tem sido mapeado com
<literal>fetch="join"</literal>.
- </para>
-
- <para>
- Veja <xref linkend="performance-fetching"/> para mais
informações.
- </para>
-
- </sect2>
-
- <sect2 id="configuration-optional-binarystreams"
revision="1">
- <title>Fluxos Binários (Binary Streams)</title>
-
- <para>
- O Oracle limita o tamanho de arrays de
<literal>byte</literal> que pode ser
- passado para/de o driver JDBC. Se você desejar usar grandes instâncias de
- tipos <literal>binary</literal> ou
<literal>serializable</literal>, você
- deve habilitar
<literal>hibernate.jdbc.use_streams_for_binary</literal>.
- <emphasis>Essa é uma configuração que só pode ser feita a nível de
sistema.</emphasis>
- </para>
-
- </sect2>
-
- <sect2 id="configuration-optional-cacheprovider"
revision="2">
- <title>Cachê de segundo nível e query</title>
-
- <para>
- As propriedades prefixadas pelo
<literal>hibernate.cache</literal>
- permite você usar um sistema de cachê de segundo nível
- em um processo executado em clustercom Hibernate.
- Veja <xref linkend="performance-cache"/> para mais
detalhes.
- </para>
-
- </sect2>
-
- <sect2 id="configuration-optional-querysubstitution">
- <title>Substituições na Linguagem de Consulta</title>
-
- <para>
- Você pode definir novos símbolos de consulta Hibernate usando
- <literal>hibernate.query.substitutions</literal>.
- Por exemplo:
- </para>
-
- <programlisting>hibernate.query.substitutions true=1,
false=0</programlisting>
-
- <para>
- Faria com que os símbolos <literal>true</literal> e
<literal>false</literal>
- passasem a ser traduzidos para literais inteiro no SQL gerado.
- </para>
-
- <programlisting>hibernate.query.substitutions
toLowercase=LOWER</programlisting>
-
- <para>
- permitirá você renomear a função <literal>LOWER</literal> no
SQL.
- </para>
-
- </sect2>
-
- <sect2 id="configuration-optional-statistics"
revision="2">
- <title>Estatísticas do Hibernate</title>
-
- <para>
- If you enable
<literal>hibernate.generate_statistics</literal>, Hibernate will
- expose a number of metrics that are useful when tuning a running system
via
- <literal>SessionFactory.getStatistics()</literal>. Hibernate
can even be configured
- to expose these statistics via JMX. Read the Javadoc of the interfaces
in
- <literal>org.hibernate.stats</literal> for more information.
-
- Se você habilitar
<literal>hibernate.generate_statistics</literal>, o Hibernate
- exibirá um número de métricas bastante útil ao ajustar um sistema via
- <literal>SessionFactory.getStatistics()</literal>. O
Hibernate pode até ser
- configurado para exibir essas estatísticas via JMX. Leia o Javadoc da
interface
- <literal>org.hibernate.stats</literal> para mais
informações.
- </para>
-
- </sect2>
- </sect1>
-
- <sect1 id="configuration-logging">
- <title>Logging</title>
-
- <para>
- Hibernate registra vários eventos usando Apache commons-logging.
- </para>
-
- <para>
- O serviço commons-logging direcionará a saída para o Apache Log4j
- ( se você incluir <literal>log4j.jar</literal>r no seu classpath)
ou
- JDK1.4 logging( se estiver em uso JDK1.4 ou maior). Você pode fazer o
- download do Log4j a partir de
<literal>http://jakarta.apache.org</literal>.
- Para usar Log4j você necessitará colocar um arquivo
- <literal>log4j.properties</literal> no seu classpath, um exemplo
de arquivo
- de propriedades é distribuído com o Hibernate no diretório
- <literal>src/</literal>.
-
- </para>
-
- <para>
- We strongly recommend that you familiarize yourself with Hibernate's log
- messages. A lot of work has been put into making the Hibernate log as
- detailed as possible, without making it unreadable. It is an essential
- troubleshooting device. The most interesting log categories are the
- following:
-
- Nós recomendamos enfaticamente que você se familiarize-se com mensagens de
- log do Hibernate. Uma parte do trabalho tem sido posto em fazer o log
- Hibernate tão detalhado quanto possível, sem fazê-lo ilegível.
- É um essencial dispositivos de controle de erros. As categorias de log
- mais interessantes são as seguintes:
- </para>
-
- <table frame="topbot" id="log-categories"
revision="2">
- <title>Categorias de Log do Hibernate</title>
- <tgroup cols="2">
- <colspec colwidth="1*"/>
- <colspec colwidth="2.5*"/>
- <thead>
- <row>
- <entry>Categoria</entry>
- <entry>Função</entry>
- </row>
- </thead>
- <tbody>
- <row>
-
<entry><literal>org.hibernate.SQL</literal></entry>
- <entry>Registra todas as instruções SQL DML a medida
que elas são executadas</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.type</literal></entry>
- <entry>Registra todos os parâmetros JDBC</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
- <entry>Registra todas as instruções SQL DDL a medida
que elas são executadas</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.pretty</literal></entry>
- <entry>
- Log the state of all entities (max 20 entities)
associated
- with the session at flush time
- Registra o estado de todas as entidades (máximo 20
entidades)
- associadas a session no momento da limpeza (flush).
- </entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.cache</literal></entry>
- <entry>Registra todas as atividades de cachê de segundo
nível</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction</literal></entry>
- <entry>Registra atividades relacionada a
transação</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.jdbc</literal></entry>
- <entry>Registra todas as requisições de recursos
JDBC</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.hql.ast.AST</literal></entry>
- <entry>
- Registra instruções SQL e HQL durante a análise da
consultas
- </entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.secure</literal></entry>
- <entry>Registra todas as requisições de autorização
JAAS</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate</literal></entry>
- <entry>
- Registra tudo ( uma parte das informações, mas muito
- útil para controle de erros )
- </entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- <para>
- Quando desenvolver aplicações com Hibernate, você deve quase sempre trabalhar
com
- debug <literal>debug</literal> para a categoria
<literal>org.hibernate.SQL</literal>,
- ou, alternativamente, a com a propriedade
<literal>hibernate.show_sql</literal> habilitada.
- </para>
-
-
- </sect1>
-
- <sect1 id="configuration-namingstrategy">
- <title>Implementado uma
<literal>NamingStrategy</literal></title>
-
- <para>
- A interface <literal>org.hibernate.cfg.NamingStrategy</literal>
permite você
- especificar um "padrão de nomeação" para objetos do banco de dados
e elementos schema.
- </para>
-
- <para>
- Você deve criar regras para a geração automaticamente de identificadores
- do banco de dados a partir de identificadores Java ou para processar
- colunas "computadas" e nomes de tabelas dado o arquivo de
mapeamento
- para nomes "físicos" de tabelas e colunas. Esta característica
ajuda a
- reduzir a verbosidade do documento de mapeamento, eliminando interferências
- repetitivas( <literal>TBL_</literal>prefixos, por exemplo). A
estratégia
- default usada pelo Hibernate é completamente mínima.
- </para>
-
- <para>
- Você pode especificar uma estratégia diferente ao chamar
- <literal>Configuration.setNamingStrategy()</literal> antes de
adicionar
- os mapeamentos:
- </para>
-
- <programlisting><![CDATA[SessionFactory sf = new Configuration()
- .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
- .addFile("Item.hbm.xml")
- .addFile("Bid.hbm.xml")
- .buildSessionFactory();]]></programlisting>
-
- <para>
- <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal> é uma
estratégia
- interna que pode ser um ponto de começo útil para algumas aplicações.
- </para>
-
- </sect1>
-
- <sect1 id="configuration-xmlconfig" revision="2">
- <title>Arquivo de configuração XML</title>
-
- <para>
- Uma maneira alternativa de configuração é especificar uma configuração
completa
- em um arquivo chamado <literal>hibernate.cfg.xml</literal>. Este
arquivo pode
- ser usado como um substituto para o arquivo
<literal>hibernate.properties</literal>
- ou, se ambos estão presentes, sobrescrever propriedades.
- </para>
-
- <para>
- The XML configuration file is by default expected to be in the root o
- your <literal>CLASSPATH</literal>. Here is an example:
- O arquivo XML de configuração é por default esperado para estar na
- raiz do seu <literal>CLASSPATH</literal>. Veja um exemplo:
- </para>
-
- <programlisting><![CDATA[<?xml version='1.0'
encoding='utf-8'?>
-<!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD//EN"
- "http://hibernate.sourceforge.net/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>]]></programlisting>
-
- <para>
- Como você pode ver, a vantagem deste enfoque é a externalização dos nomes dos
- arquivos de mapeamento para configuração. O
<literal>hibernate.cfg.xml</literal>
- também é mais conveniente caso você tenha que ajustar o cache do Hibernate.
- Note que a escolha é sua em usar
<literal>hibernate.properties</literal> ou
- <literal>hibernate.cfg.xml</literal>, ambos são equivalente, à
exceção dos benefícios
- acima mencionados de usar a sintaxe de XML.
- </para>
-
- <para>
- Com a configuração do XML, iniciar o Hibernate é então tão simples como
- </para>
-
- <programlisting><![CDATA[SessionFactory sf = new
Configuration().configure().buildSessionFactory();]]></programlisting>
-
- <para>
- You can pick a different XML configuration file using
- </para>
-
- <programlisting><![CDATA[SessionFactory sf = new Configuration()
- .configure("catdb.cfg.xml")
- .buildSessionFactory();]]></programlisting>
-
- </sect1>
-
- <sect1 id="configuration-j2ee" revision="1">
- <title>Integração com servidores de aplicação J2EE</title>
-
- <para>
- O Hibernate tem os seguintes pontos da integração para o infraestrutura de
J2EE:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>DataSources gerenciados pelo container</emphasis>:
O Hibernate pode
- usar conexões JDBC gerenciadas pelo Container e fornecidas pela JNDI.
Geralmente,
- um <literal>TransactionManager</literal> compatível com JTA e
um
- <literal>ResourceManager</literal> cuidam do gerenciamento da
transação ( CMT ),
- especialmente em transações distribuídas manipuladas através de vários
DataSources.
- Naturalmente, você também pode demarcar os limites das transações
programaticamente (BMT)
- ou você poderia querer usar a API opcional do Hibernate
<literal>Transaction</literal>
- para esta manter seu código portável.
- </para>
- </listitem>
- </itemizedlist>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Ligação (binding) automática a JNDI</emphasis>: O
Hibernate pode
- associar sua <literal>SessionFactory</literal> a JNDI depois
de iniciado.
- </para>
- </listitem>
- </itemizedlist>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Ligação (binding) Session na JTA:</emphasis>
- A <literal>Session</literal> do Hibernate pode
automaticamente ser ligada
- ao escopo da transações JTA. Simplesmente localizando a
<literal>SessionFactory</literal>
- da JNDI e obtendo a<literal>Session</literal> corrente. Deixe
o Hibernate cuidar
- da limpeza e encerramento da <literal>Session</literal>
quando as transações JTA
- terminarem. A Demarcação de transação pode ser declarativa (CMT) ou
- programática(BMT/Transação do usuário).
- </para>
- </listitem>
- </itemizedlist>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>JMX deployment:</emphasis> Se você usa um JMX
servidor de
- aplicações capaz (ex. Jboss AS), você pode fazer a instação do Hibernate
- como um Mbean controlado. Isto evita ter que iniciar uma linha de
- código para construir sua <literal>SessionFactory</literal>
de uma
- <literal>Configuration</literal>. O container iniciará seu
- <literal>HibernateService</literal>, e idealmente também
cuidará
- das dependências de serviços (DataSources, têm que estar disponíveis
- antes do Hibernate iniciar, etc.).
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Dependendo em seu ambiente, você poderia ter que ajustar a opção de
configuração
- <literal>hibernate.connection.aggressive_release</literal> para
verdadeiro ( true ),
- se seu servidor de aplicações lançar exeções "retenção de
conecção".
- </para>
-
- <sect2 id="configuration-optional-transactionstrategy"
revision="3">
- <title>Configuração de estratégia de transação</title>
-
- <para>
- A API Hibernate <literal>Session</literal> é 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 <literal>UserTransaction</literal> quando
necessário.
-
- </para>
-
- <para>
- Para manter seu código portável entre estes dois ( e outros ) ambientes,
recomendamos
- a API Hibernate <literal>Transaction</literal>, que envolve e
esconde o sistema subjacente.
- Você tem que especificar um classe construtora para
<literal>Transaction</literal> instanciar
- ajustando a propriedade de configuração do
<literal>hibernate.transaction.factory_class</literal>.
-
- </para>
-
- <para>
- Existem três escolhas (internas) padrões:
- </para>
-
- <variablelist spacing="compact">
- <varlistentry>
-
<term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
- <listitem>
- <para>delegada as transações (JDBC)a bases de dados
(Padrão)</para>
-
- </listitem>
- </varlistentry>
- <varlistentry>
-
<term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
- <listitem>
- <para>
- delegada a transação a um container gerenciador se a
transação
- existente estiver de acordo neste contexto (ex: método bean
sessão EJB),
- se não uma nova transação é iniciada e uma transação
controlado por
- um bean é usada.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
-
<term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
- <listitem>
- <para>delega para um container gerenciador de transações
JTA</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>
- Você também pode definir suas próprias estratégias de transação ( para um
serviço de
- transação CORBA por exemplo).
- </para>
-
- <para>
- Algumas características no Hibernate (ex., o cache de segundo nível,
sessões contextuais
- com JTA, etc.) requerem acesso a JTA
<literal>TransactionManager</literal> em um ambiente
- controlado. Em um servidor de aplicação você tem que especificar como o
Hibernate pode
- obter uma referência para a
<literal>TransactionManager</literal>, pois o J2EE não
- padronize um mecanismo simples :
- </para>
-
- <table frame="topbot" id="jtamanagerlookup"
revision="1">
- <title>Gerenciadores de transações JTA</title>
- <tgroup cols="2">
- <colspec colwidth="2.5*"/>
- <colspec colwidth="1*"/>
- <thead>
- <row>
- <entry>Transaction Factory</entry>
- <entry align="center">Application
Server</entry>
- </row>
- </thead>
- <tbody>
- <row>
-
<entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
- <entry align="center">JBoss</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
- <entry align="center">Weblogic</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
- <entry
align="center">WebSphere</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
- <entry align="center">WebSphere
6</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
- <entry align="center">Orion</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
- <entry align="center">Resin</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
- <entry align="center">JOTM</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
- <entry align="center">JOnAS</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
- <entry align="center">JRun4</entry>
- </row>
- <row>
-
<entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
- <entry align="center">Borland
ES</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
-
- </sect2>
-
- <sect2 id="configuration-optional-jndi" revision="3">
- <title><literal>SessionFactory</literal> ligada a
JNDI</title>
-
- <para>
- Uma <literal>SessionFactory</literal> de Hibernate ligada a
JNDI pode simplificar
- a localização da fabrica e a criação de novas
<literal>Session</literal>s.
- Observe que isto não relacionado a um
<literal>Datasource</literal> ligado
- a JNDI, simplemente ambos usam o mesmo registro!
- </para>
-
- <para>
- If you wish to have the <literal>SessionFactory</literal>
bound to a JNDI namespace, specify
- a name (eg. <literal>java:hibernate/SessionFactory</literal>)
using the property
- <literal>hibernate.session_factory_name</literal>. If this
property is omitted, the
- <literal>SessionFactory</literal> will not be bound to JNDI.
(This is especially useful in
- environments with a read-only JNDI default implementation, e.g. Tomcat.)
- </para>
-
- <para>
- When binding the <literal>SessionFactory</literal> to JNDI,
Hibernate will use the values of
- <literal>hibernate.jndi.url</literal>,
<literal>hibernate.jndi.class</literal> to instantiate
- an initial context. If they are not specified, the default
<literal>InitialContext</literal>
- will be used.
- </para>
-
- <para>
- Hibernate will automatically place the
<literal>SessionFactory</literal> in JNDI after
- you call <literal>cfg.buildSessionFactory()</literal>. This
means you will at least have
- this call in some startup code (or utility class) in your application,
unless you use
- JMX deployment with the <literal>HibernateService</literal>
(discussed later).
- </para>
-
- <para>
- If you use a JNDI <literal>SessionFactory</literal>, an EJB
or any other class may
- obtain the <literal>SessionFactory</literal> using a JNDI
lookup.
- </para>
-
- <para>
- We recommend that you bind the
<literal>SessionFactory</literal> to JNDI in
- a managend environment and use a <literal>static</literal>
singleton otherwise.
- To shield your application code from these details, we also recommend to
hide the
- actual lookup code for a <literal>SessionFactory</literal> in
a helper class,
- such as <literal>HibernateUtil.getSessionFactory()</literal>.
Note that such a
- class is also a convenient way to startup Hibernate—see chapter
1.
- </para>
-
- </sect2>
-
- <sect2 id="configuration-j2ee-currentsession"
revision="4">
- <title>Current Session context management with JTA</title>
-
- <para>
- The easiest way to handle <literal>Session</literal>s and
transactions is
- Hibernates automatic "current"
<literal>Session</literal> management.
- See the discussion of <xref
linkend="architecture-current-session">current sessions</xref>.
- Using the <literal>"jta"</literal> session context,
if there is no Hibernate
- <literal>Session</literal> associated with the current JTA
transaction, one will
- be started and associated with that JTA transaction the first time you call
- <literal>sessionFactory.getCurrentSession()</literal>. The
<literal>Session</literal>s
- retrieved via <literal>getCurrentSession()</literal> in
<literal>"jta"</literal> context
- will be set to automatically flush before the transaction completes, close
- after the transaction completes, and aggressively release JDBC connections
- after each statement. This allows the
<literal>Session</literal>s 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 <literal>UserTransaction</literal>,
or (recommended
- for portable code) use the Hibernate
<literal>Transaction</literal> API to set
- transaction boundaries. If you run in an EJB container, declarative
transaction
- demarcation with CMT is preferred.
- </para>
-
- </sect2>
-
- <sect2 id="configuration-j2ee-jmx" revision="1">
- <title>JMX deployment</title>
-
- <para>
- The line <literal>cfg.buildSessionFactory()</literal> still
has to be executed
- somewhere to get a <literal>SessionFactory</literal> into
JNDI. You can do this
- either in a <literal>static</literal> initializer block (like
the one in
- <literal>HibernateUtil</literal>) or you deploy Hibernate as
a <emphasis>managed
- service</emphasis>.
- </para>
-
- <para>
- Hibernate is distributed with
<literal>org.hibernate.jmx.HibernateService</literal>
- for deployment on an application server with JMX capabilities, such as
JBoss AS.
- The actual deployment and configuration is vendor specific. Here is an
example
- <literal>jboss-service.xml</literal> for JBoss 4.0.x:
- </para>
-
- <programlisting><![CDATA[<?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>]]></programlisting>
-
- <para>
- This file is deployed in a directory called
<literal>META-INF</literal> and packaged
- in a JAR file with the extension <literal>.sar</literal>
(service archive). You also need
- to package Hibernate, its required third-party libraries, your compiled
persistent classes,
- as well as your mapping files in the same archive. Your enterprise beans
(usually session
- beans) may be kept in their own JAR file, but you may include this EJB
JAR file in the
- main service archive to get a single (hot-)deployable unit. Consult the
JBoss AS
- documentation for more information about JMX service and EJB deployment.
- </para>
-
- </sect2>
-
- </sect1>
-
-</chapter>
-
+<chapter id="session-configuration" revision="1">
+
+ <title>Configuração</title>
+
+ <para>
+ Devido ao fato de o Hibernate ser projetado para operar em vários ambientes
diferentes,
+ há um grande número de parâmetros de configuração. Felizmente, a maioria tem
valores default
+ lógicos e o Hibernate é distribuído com um arquivo
<literal>hibernate.properties</literal>
+ de exemplo no <literal>etc/</literal> que mostra várias opções.
Apenas coloque o arquivo
+ de exemplo no seu classpath e personalize-o.
+ </para>
+
+ <sect1 id="configuration-programmatic" revision="1">
+ <title>1.11 Configuração programática</title>
+
+ <para>
+ Uma instância de
<literal>org.hibernate.cfg.Configuration</literal>
+ representa um conjunto inteiro de mapeamentos de tipos Java da aplicação para
+ um banco de dados SQL. O <literal>Configuration</literal> é usado
para construir
+ uma <literal>SessionFactory</literal> (imutável). Os mapeamentos
são compilados
+ a partir de arquivos de mapeamento XML.
+
+ </para>
+
+ <para>
+ Você pode obter uma instância <literal>Configuration</literal>
intanciando-
+ o diretamente e especificando documentos de mapeamento XML. Se o arquivo
+ de mapeamento estão no classpath, use use
<literal>addResource()</literal>:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addResource("Item.hbm.xml")
+ .addResource("Bid.hbm.xml");]]></programlisting>
+
+ <para>
+ Uma alternativa (às vezes melhor) é especificar a classe mapeada,
+ e permitir que o Hibernate encontre o documento de mapeamento para você:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+ <para>
+ Então o Hibernate procurará pelos arquivos de mapeamento chamados
+ <literal>/org/hibernate/auction/Item.hbm.xml</literal> e
+ <literal>/org/hibernate/auction/Bid.hbm.xml</literal> no
classpath.
+ Esta abordagem elimina qualquer nome de arquivo de difícil compreensão.
+ </para>
+
+ <para>
+ Uma <literal>Configuration</literal> também permite você
especificar
+ propriedades de configuração:
+ </para>
+
+ <programlisting><![CDATA[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");]]></programlisting>
+
+ <para>
+ Este não é o único caminho para passar as propriedades de configuração
+ para o Hibernate. As várias opções incluem:
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Passar uma instância de
<literal>java.util.Properties</literal>
+ para <literal>Configuration.setProperties()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Colocar <literal>hibernate.properties</literal> no
diretório
+ raiz do classpath.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Determinar as propriedades do <literal>System</literal>
+ usando <literal>java -Dproperty=value</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Include <literal><property></literal>
elements in
+ <literal>hibernate.cfg.xml</literal> (discussed later).
+ Incluir elementos
<literal><property></literal> no
+ <literal>hibernate.cfg.xml</literal> (discutido mais
tarde).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ <literal>hibernate.properties</literal> é o caminho mais facil
+ se você quer começar mais rápido.
+ </para>
+
+ <para>
+ O <literal>Configuration</literal> é entendido como um objeto
startup-time,
+ é descartado uma vez que a <literal>SessionFactory</literal> é
criada.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-sessionfactory">
+ <title>Obtendo uma SessionFactory</title>
+
+ <para>
+ Quando todos os mapeamentos têm sido analisados pelo
<literal>Configuration</literal>,
+ a aplicação deve obter uma factory para as instâncias da
<literal>Session</literal>.
+ O objetivo desta factory é ser compartilhado por todas as threads da
aplicação:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sessions =
cfg.buildSessionFactory();]]></programlisting>
+
+ <para>
+ Hibernate permite sua aplicação instanciar mais do que uma
+ <literal>SessionFactory</literal>. Isto é útil se você está
usando mais
+ do que um banco de dados.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-hibernatejdbc" revision="1">
+ <title>Conexões JDBC</title>
+
+ <para>
+ Normalmente, você quer mandar criar a
<literal>SessionFactory</literal> criar um
+ pool de conexões JDBC para você. Se você seguir essa abordagem, a abertura de
uma
+ <literal>Session</literal> é tão simples quanto:
+
+ </para>
+
+ <programlisting><![CDATA[Session session = sessions.openSession(); //
open a new Session]]></programlisting>
+
+ <para>
+ Assim que você fizer algo que requer o acesso ao banco de dados, uma
+ conexão JDBC será obtida do pool.
+ </para>
+
+ <para>
+ Para esse trabalho, nós necessitamos passar algumas propriedades da conexão
JDBC
+ para o Hibernate. Todos os nomes de propriedades Hibernate e semânticas são
definidas
+ <literal>org.hibernate.cfg.Environment</literal>. Nós iremos
descrever agora
+ o mais importantes configurações de conexão JDBC.
+ </para>
+
+ <para>
+ O Hibernate obterá conexões( e pool) usando
<literal>java.sql.DriverManager</literal>
+ se você determinar as seguintes propriedades:
+ </para>
+
+ <table frame="topbot">
+ <title>Propriedades JDBC Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.driver_class</literal>
+ </entry>
+ <entry>
+ <emphasis>Classe driver jdbc</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL jdbc</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>Usuário do banco de dados</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>Senha do usuário do banco de dados</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.pool_size</literal>
+ </entry>
+ <entry>
+ <emphasis>Número máximo de connecxões no pool</emphasis>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ O algoritmo de pool de conexões do próprio Hibernate entretanto é
completamente
+ rudimentar. A intenção dele e ajudar a iniciar e <emphasis>não para
usar em um
+ sistema de produção</emphasis> ou até para testar desempenho. Você
deveria usar
+ uma ferramente de pool de terceiros para conseguir melhor desempenho e
estabilidade.
+ Apenas especifique a propriedade
<literal>hibernate.connection.pool_size</literal>
+ com a definição do pool de conexões. Isto irá desligar o pool interno do
Hibernate.
+ Por exemplo, você pode gostar de usar C3P0.
+ </para>
+
+ <para>
+ O C3P0 é um pool conexão JDBC de código aberto distribuído junto com
+ Hibernate no diretório <literal>lib</literal>. O Hibernate
usará o
+ <literal>C3P0ConnectionProvider</literal> para o pool de conexão
se
+ você configurar a propriedade
<literal>hibernate.c3p0.*</literal>. Se você
+ gostar de usar Proxool consulte ao pacote
<literal>hibernate.properties</literal>
+ e o web site do Hibernate para mais informações.
+ </para>
+
+ <para>
+ Aqui é um exemplo de arquivo
<literal>hibernate.properties</literal> para C3P0:
+ </para>
+
+ <programlisting id="c3p0-configuration"
revision="1"><![CDATA[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]]></programlisting>
+
+ <para>
+ Para usar dentro de um servidor de aplicação, você deve configurar
+ o Hibernate para obter conexões de um application server
+ <literal>Datasource</literal> registrado no JNDI. Você
necessitará
+ determinar pelo menos uma das seguintes propriedades:
+ </para>
+
+ <table frame="topbot">
+ <title>Propriedades do Datasource do Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.datasource</literal>
+ </entry>
+ <entry>
+ <emphasis>Nome datasource JNDI</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL do fornecedor JNDI</emphasis> (opcional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.class</literal>
+ </entry>
+ <entry>
+ <emphasis>Classe do JNDI
<literal>InitialContextFactory</literal></emphasis> (opcional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>Usuário do banco de dados</emphasis>
(opcional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>Senha do usuário do banco de dados</emphasis>
(opcional)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Eis um exemplo de arquivo <literal>hibernate.properties</literal>
para
+ um servidor de aplicação fornecedor de datasources JNDI:
+ </para>
+
+ <programlisting><![CDATA[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]]></programlisting>
+
+ <para>
+ Conexões JDBC obtidas de um datasource JNDI irão automaticamente irão
participar
+ das transações gerenciadas pelo container no servidor de aplicação.
+ </para>
+
+ <para>
+ Arbitrariamente as propriedades de conexão podem ser acrescentandas ao
+ "<literal>hibernate.connnection</literal>" ao nome da
propriedade. Por exemplo,
+ você deve especificar o <literal>charSet</literal> usando
<literal>hibernate.connection.charSet</literal>.t.
+ </para>
+
+ <para>
+ Você pode definir sua própria estratégia de plugin para obter conexões JDBC
implementando
+ a interface
<literal>org.hibernate.connection.ConnectionProvider</literal>. Você pode
+ escolher uma implementação customizada setando
<literal>hibernate.connection.provider_class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-optional" revision="1">
+ <title>Propriedades opcionais de configuração</title>
+
+ <para>
+ Há um grande número de outras propriedades que controlam o comportamento do
Hibernate
+ em tempo de execução. Todos são opcionais e tem valores default lógicos.
+ </para>
+
+ <para>
+ <emphasis>Aviso: algumas destas propriedades são somente a "nível
de sistema".</emphasis>
+ Propriedades nível de sistema podem ser determinados somente via
<literal>java -Dproperty=value</literal>
+ ou <literal>hibernate.properties</literal>. Elas
<emphasis>não</emphasis>podem ser
+ configuradas por outras técnicas descritas abaixo.
+ </para>
+
+ <table frame="topbot"
id="configuration-optional-properties" revision="8">
+ <title>Hibernate Configuration Properties</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.dialect</literal>
+ </entry>
+ <entry>
+ O nome da classe de um <literal>Dialeto</literal>
+ que permite o Hibernate gerar SQL otimizado para um banco de
+ dados relacional em particular.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>full.classname.of.Dialect</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.show_sql</literal>
+ </entry>
+ <entry>
+ Escreve todas as instruções SQL no console. Esta é uma
alternativa
+ a configurar a categoria de log
<literal>org.hibernate.SQL</literal>
+ para <literal>debug</literal>.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.format_sql</literal>
+ </entry>
+ <entry>
+ Imprime o SQL formatado no log e console.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_schema</literal>
+ </entry>
+ <entry>
+ Qualifica no sql gerado, os nome das tabelas sem qualificar
+ com schena/tablespace dado
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>SCHEMA_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_catalog</literal>
+ </entry>
+ <entry>
+ Qualifica no sql gerado, os nome das tabelas sem qualificar
+ com catálogo dado
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>CATALOG_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.session_factory_name</literal>
+ </entry>
+ <entry>
+ O <literal>SessionFactory</literal> irá
automaticamente
+ se ligar a este nome no JNDI depois de ter sido criado.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>jndi/composite/name</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.max_fetch_depth</literal>
+ </entry>
+ <entry>
+ Estabelece a "profundidade" máxima para árvore
outer join fetch
+ para associações finais únicas(one-to-one,many-to-one).
+ Um <literal>0</literal> desativa por default a
busca outer join.
+ <para>
+ <emphasis
role="strong">eg.</emphasis>
+ Valores recomendados
entre<literal>0</literal> e <literal>3</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.default_batch_fetch_size</literal>
+ </entry>
+ <entry>
+ Determina um tamanho default para busca de associações em
lotes do Hibernate
+ <para>
+ <emphasis
role="strong">eg.</emphasis>
+ Valores recomendados <literal>4</literal>,
<literal>8</literal>,
+ <literal>16</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_entity_mode</literal>
+ </entry>
+ <entry>
+ Determina um modo default para representação de entidades
+ para todas as sessões abertas desta
<literal>SessionFactory</literal>
+ <para>
+ <literal>dynamic-map</literal>,
<literal>dom4j</literal>,
+ <literal>pojo</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.order_updates</literal>
+ </entry>
+ <entry>
+ Força o Hibernate a ordenar os updates SQL pelo valor da
chave
+ primária dos itens a serem atualizados. Isto resultará em
menos
+ deadlocks nas transações em sistemas altamente concorrente.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.generate_statistics</literal>
+ </entry>
+ <entry>
+ If enabled, Hibernate will collect statistics useful for
+ performance tuning.
+ Se habilitado, o Hibernate coletará estatísticas úties
+ para performance tuning dos bancos.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.use_identifer_rollback</literal>
+ </entry>
+ <entry>
+ Se habilitado, propriedades identificadoras geradas
+ serão zeradas para os valores default quando os
+ objetos forem apagados.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_sql_comments</literal>
+ </entry>
+ <entry>
+ Se ligado, o Hibernate irá gerar comentários dentro do SQL,
+ para facilitar o debugging, o valor default é
<literal>false</literal>.
+ <para>
+ <emphasis
role="strong">eg.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-jdbc-properties"
revision="8">
+ <title>JDBC Hibernate e Propriedades de Conexão</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.fetch_size</literal>
+ </entry>
+ <entry>
+ Um valor maior que zero determina o tamanho do fetch
+ do JDBC( chamadas
<literal>Statement.setFetchSize()</literal>).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_size</literal>
+ </entry>
+ <entry>
+ Um valor maior que zero habilita uso de batch updates JDBC2
pelo Hibernate.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ valores recomentados entre
<literal>5</literal> e <literal>30</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.jdbc.batch_versioned_data</literal>
+ </entry>
+ <entry>
+ Sete esta propriedade como
<literal>true</literal> se seu driver JDBC retorna
+ o número correto de linhas no
<literal>executeBatch()</literal> ( É usualmente
+ seguro tornar esta opção ligada). O Hibernate então irá usar
betched DML
+ para automaticamente versionar dados.
<literal>false</literal> por default.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.factory_class</literal>
+ </entry>
+ <entry>
+ Escolher um <literal>Batcher</literal>
customizado. Muitas
+ aplicações não irão necessitar desta propriedade de
configuração
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+
<literal>classname.of.BatcherFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.jdbc.use_scrollable_resultset</literal>
+ </entry>
+ <entry>
+ Habilita o uso de JDBC2 scrollable resultsets pelo
Hibernate.
+ Essa propriedade somente é necessaria quando se usa
Conexeções
+ JDBC providas pelo usuário, caso contrário o Hibernate os os
+ metadados da conexão.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.jdbc.use_streams_for_binary</literal>
+ </entry>
+ <entry>
+ Use streams para escrever/ler tipos
<literal>binary</literal>
+ ou <literal>serializable</literal> para/a o JDBC(
propriedade a nível de sistema).
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.jdbc.use_get_generated_keys</literal>
+ </entry>
+ <entry>
+ Possibilita o uso
<literal>PreparedStatement.getGeneratedKeys()</literal>
+ do JDBC3 para recuperar chaves geradas nativamente depois da
inserçãp.
+ Requer driver JDBC3+ e JRE1.4+, determine para false se seu
driver tem
+ problemas com gerador de indentificadores Hibernate. Por
default, tente
+ determinar o driver capaz de usar metadados da conexão.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.connection.provider_class</literal>
+ </entry>
+ <entry>
+ O nome da classe de um
<literal>ConnectionProvider</literal> personalizado
+ o qual proverá conexões JDBC para o Hibernate.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+
<literal>classname.of.ConnectionProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.isolation</literal>
+ </entry>
+ <entry>
+ Determina o nível de isolamento de uma transação JDBC.
+ Verifique <literal>java.sql.Connection</literal> para
valores
+ siginificativos mas note que a maior parte dos bancos de dados
+ não suportam todos os níveis de isolamento.
+ <para>
+ <emphasis role="strong">Ex.</emphasis>
+ <literal>1, 2, 4, 8</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.connection.autocommit</literal>
+ </entry>
+ <entry>
+ Habilita autocommit para conexões no pool JDBC( não
recomendado).
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.connection.release_mode</literal>
+ </entry>
+ <entry>
+ Especifica quando o Hibernate deve liberar conexões JDBC. Por
default,
+ uma conexão JDBC é retida até a sessão está explicitamente
fechada
+ ou desconectada. Para um datasource JTA do servidor de
aplicação, você deve
+ usar <literal>after_statement</literal> para
forçar s 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
+ <literal>after_transaction</literal>.
<literal>auto</literal> escolheremos
+ <literal>after_statement</literal> para as
estratégias de transaçãoes JTA e CMT
+ e <literal>after_transaction</literal> para as
estratégias de transação JDBC
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>auto</literal> (default) |
<literal>on_close</literal> |
+ <literal>after_transaction</literal> |
<literal>after_statement</literal>
+ </para>
+ <para>
+ Note that this setting only affects
<literal>Session</literal>s returned from
+
<literal>SessionFactory.openSession</literal>. For
<literal>Session</literal>s
+ obtained through
<literal>SessionFactory.getCurrentSession</literal>, the
+ <literal>CurrentSessionContext</literal>
implementation configured for use
+ controls the connection release mode for those
<literal>Session</literal>s.
+ See <xref
linkend="architecture-current-session"/>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.connection.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Passa a propriedade JDBC
<literal>propertyName</literal>
+ para
<literal>DriverManager.getConnection()</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.jndi.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Passar a propriedade
<literal>propertyName</literal> para
+ o <literal>InitialContextFactory</literal> JNDI.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-cache-properties"
revision="7">
+ <title>Propriedades de Cachê do Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+
<literal>hibernate.cache.provider_class</literal>
+ </entry>
+ <entry>
+ O nome da classe de um
<literal>CacheProvider</literal> customizado.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+
<literal>classname.of.CacheProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.cache.use_minimal_puts</literal>
+ </entry>
+ <entry>
+ Otimizar operação de cachê de segundo nível para minimizar
escritas,
+ ao custo de leituras mais frequantes. Esta configuração é
mais útil
+ para cachês clusterizados e, no Hibernate3, é habilitado por
default
+ para implementações de cachê clusterizar.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.cache.use_query_cache</literal>
+ </entry>
+ <entry>
+ Habilita a cache de consultas, Mesmo assim, consultas
individuais ainda tem que ser
+ habilitadas para o cache.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.cache.use_second_level_cache</literal>
+ </entry>
+ <entry>
+ Pode ser usada para desabilitar completamente ocache de
segundo nível,
+ o qual está habilitado por default para classes que
especificam
+ um mapeamento
<literal><cache></literal>.
+
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.cache.query_cache_factory</literal>
+ </entry>
+ <entry>
+ O nome de uma classe que implementa a interface
+ <literal>QueryCache</literal> personalizada, por
+ default, um
<literal>StandardQueryCache</literal>
+ criado automaticamente.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>classname.of.QueryCache</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.region_prefix</literal>
+ </entry>
+ <entry>
+ Um prefixo para usar nos nomes da área especial
+ do cachê de segundo nível.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>prefix</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.cache.use_structured_entries</literal>
+ </entry>
+ <entry>
+ Forces Hibernate to store data in the second-level cache
+ in a more human-friendly format.
+ Força o Hibernate armazenar dados no cachê se segundo
+ nível em um formato mais legivel.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot"
id="configuration-transaction-properties" revision="9">
+ <title>Propriedades de Transação do Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+
<literal>hibernate.transaction.factory_class</literal>
+ </entry>
+ <entry>
+ O nome da clase de um a
<literal>TransactionFactory</literal>
+ para usar com API <literal>Transaction</literal>
+ ( por default <literal>JDBCTransactionFactory</literal>).
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+
<literal>classname.of.TransactionFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>jta.UserTransaction</literal>
+ </entry>
+ <entry>
+ Um nome JNDI usado pelo
<literal>JTATransactionFactory</literal>
+ para obter uma <literal>UserTransaction</literal>
JTA a partir
+ do servidor de aplicação.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>jndi/composite/name</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.transaction.manager_lookup_class</literal>
+ </entry>
+ <entry>
+ O nome da classe de um
<literal>TransactionManagerLookup</literal>
+ – requerido quando caching a nível JVM esta habilitado ou
quando
+ estivermos usando um generator hilo em um ambiente JTA.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+
<literal>classname.of.TransactionManagerLookup</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.transaction.flush_before_completion</literal>
+ </entry>
+ <entry>
+ Se habilitado, a sessão será automaticamente limpa antes da
fase de
+ conclusão da transação. É preferivel a gerência interna e
+ automática do contexto da sessão, veja
+ <xref
linkend="architecture-current-session"/>
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.transaction.auto_close_session</literal>
+ </entry>
+ <entry>
+ Se habilitado, a sessão será automaticamente fechada após a
fase de
+ conclusão da transação. É preferivel a gerência interna e
+ automática do contexto da sessão, veja
+ <xref
linkend="architecture-current-session"/>
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-misc-properties"
revision="10">
+ <title>Propriedades Variadas</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nome da Propriedade</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+
<literal>hibernate.current_session_context_class</literal>
+ </entry>
+ <entry>
+ Forneçe uma estratégia (personalizada) para extensão
+ da <literal>Session</literal>
"corrente". Veja
+ <xref
linkend="architecture-current-session"/> para
+ mais informação sobre estratégias internas.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>jta</literal> |
<literal>thread</literal> |
+ <literal>managed</literal> |
<literal>custom.Class</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.factory_class</literal>
+ </entry>
+ <entry>
+ Escolha a implementação de análise HQL.
+ <para>
+ <emphasis
role="strong">eg.</emphasis>
+
<literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+
<literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.substitutions</literal>
+ </entry>
+ <entry>
+ Mapeamento a partir de símbolos em consultas HQL para
+ símbolos SQL( símbolos devem ser funções ou nome literais
+ , por exemplo).
+ <para>
+ <emphasis
role="strong">eg.</emphasis>
+ <literal>hqlLiteral=SQL_LITERAL,
hqlFunction=SQLFUNC</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.hbm2ddl.auto</literal>
+ </entry>
+ <entry>
+ Automaticamente valida ou exporta schema DDL para o banco de
+ dados quando o <literal>SessionFactory</literal>
é criads.
+ Com <literal>create-drop</literal>, o schema do
banco de dados
+ será excluido quando a
<literal>create-drop</literal> for
+ fechada esplicitamente.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>validate</literal> |
<literal>update</literal> |
+ <literal>create</literal> |
<literal>create-drop</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+
<literal>hibernate.cglib.use_reflection_optimizer</literal>
+ </entry>
+ <entry>
+ Habilita o uso de CGLIB em vez de reflexão em tempo de
execução
+ ( propriedade a nível de sistema). Reflexão pode algumas
vezes ser ú
+ til quando controlar erros, note que o Hibernate sempre irá
requerer a CGLIB
+ mesmo se você desligar o otimizador. Você não pode determinar
esta
+ propriedade no <literal>hibernate.cfg.xml</literal>.
+ <para>
+ <emphasis
role="strong">Ex.</emphasis>
+ <literal>true</literal> |
<literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="configuration-optional-dialects"
revision="1">
+ <title>Dialetos SQL</title>
+
+ <para>
+ Você deve sempre determinar a propriedade
<literal>hibernate.dialect</literal>
+ para a subclasse de
<literal>org.hibernate.dialect.Dialect</literal> correta de seu
+ banco de dados. Se você especificar um dialeto, Hibernate usará defaults
lógicos
+ para qualquer um das outras propriedades listadas abaixo, reduzindo o
esforço de
+ especificá-los manualmente.
+ </para>
+
+ <table frame="topbot" id="sql-dialects"
revision="2">
+ <title>Hibernate SQL Dialects
(<literal>hibernate.dialect</literal>)</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>RDBMS</entry>
+ <entry>Dialect</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>DB2</entry>
<entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 AS/400</entry>
<entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 OS390</entry>
<entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>PostgreSQL</entry>
<entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL</entry>
<entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL with InnoDB</entry>
<entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL with MyISAM</entry>
<entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle (any version)</entry>
<entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle 9i/10g</entry>
<entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase</entry>
<entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase Anywhere</entry>
<entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Microsoft SQL Server</entry>
<entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+ </row>
+ <row>
+ <entry>SAP DB</entry>
<entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Informix</entry>
<entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+ </row>
+ <row>
+ <entry>HypersonicSQL</entry>
<entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Ingres</entry>
<entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Progress</entry>
<entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Mckoi SQL</entry>
<entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Interbase</entry>
<entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Pointbase</entry>
<entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>FrontBase</entry>
<entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Firebird</entry>
<entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-outerjoin"
revision="4">
+ <title>Recuperação por união externa (Outer Join
Fetching)</title>
+
+ <para>
+ Se seu banco de dados suporta Recuperação por união externa (Outer Join
Fetching) no estilo ANSI,
+ Oracle ou Sybase, A recuperação por união externa (Outer Join Fetching)
frequentemente aumentará
+ o desempenho limitando o número de chamadas (round trips) ao banco de
dados( ao custo de
+ possivelmente mais trabalho desempenhado pelo próprio banco de dados). A
recuperação por
+ união externa (Outer Join Fetching)permite um gráfico completo de objetos
conectados
+ por muitos-para-um, um-para-muitos, muitos-para-muitos e associações
um-para-um para ser
+ recuperadas em um simples instrução SQL SELECT .
+
+ </para>
+
+ <para>
+ A recuperação por união externa (Outer Join Fetching) pode ser
desabilitado
+ <emphasis>globalmente</emphasis> setando a propriedade
+ <literal>hibernate.max_fetch_depth</literal> para
<literal>0</literal>.
+ Uma valor 1 ou maior habilita o outer join fetching para associações
um-para-um
+ e muitos-para-umos cujos quais tem sido mapeado com
<literal>fetch="join"</literal>.
+ </para>
+
+ <para>
+ Veja <xref linkend="performance-fetching"/> para mais
informações.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-binarystreams"
revision="1">
+ <title>Fluxos Binários (Binary Streams)</title>
+
+ <para>
+ O Oracle limita o tamanho de arrays de
<literal>byte</literal> que pode ser
+ passado para/de o driver JDBC. Se você desejar usar grandes instâncias de
+ tipos <literal>binary</literal> ou
<literal>serializable</literal>, você
+ deve habilitar
<literal>hibernate.jdbc.use_streams_for_binary</literal>.
+ <emphasis>Essa é uma configuração que só pode ser feita a nível de
sistema.</emphasis>
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-cacheprovider"
revision="2">
+ <title>Cachê de segundo nível e query</title>
+
+ <para>
+ As propriedades prefixadas pelo
<literal>hibernate.cache</literal>
+ permite você usar um sistema de cachê de segundo nível
+ em um processo executado em clustercom Hibernate.
+ Veja <xref linkend="performance-cache"/> para mais
detalhes.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-querysubstitution">
+ <title>Substituições na Linguagem de Consulta</title>
+
+ <para>
+ Você pode definir novos símbolos de consulta Hibernate usando
+ <literal>hibernate.query.substitutions</literal>.
+ Por exemplo:
+ </para>
+
+ <programlisting>hibernate.query.substitutions true=1,
false=0</programlisting>
+
+ <para>
+ Faria com que os símbolos <literal>true</literal> e
<literal>false</literal>
+ passasem a ser traduzidos para literais inteiro no SQL gerado.
+ </para>
+
+ <programlisting>hibernate.query.substitutions
toLowercase=LOWER</programlisting>
+
+ <para>
+ permitirá você renomear a função <literal>LOWER</literal> no
SQL.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-statistics"
revision="2">
+ <title>Estatísticas do Hibernate</title>
+
+ <para>
+ If you enable
<literal>hibernate.generate_statistics</literal>, Hibernate will
+ expose a number of metrics that are useful when tuning a running system
via
+ <literal>SessionFactory.getStatistics()</literal>. Hibernate
can even be configured
+ to expose these statistics via JMX. Read the Javadoc of the interfaces
in
+ <literal>org.hibernate.stats</literal> for more information.
+
+ Se você habilitar
<literal>hibernate.generate_statistics</literal>, o Hibernate
+ exibirá um número de métricas bastante útil ao ajustar um sistema via
+ <literal>SessionFactory.getStatistics()</literal>. O
Hibernate pode até ser
+ configurado para exibir essas estatísticas via JMX. Leia o Javadoc da
interface
+ <literal>org.hibernate.stats</literal> para mais
informações.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="configuration-logging">
+ <title>Logging</title>
+
+ <para>
+ Hibernate registra vários eventos usando Apache commons-logging.
+ </para>
+
+ <para>
+ O serviço commons-logging direcionará a saída para o Apache Log4j
+ ( se você incluir <literal>log4j.jar</literal>r no seu classpath)
ou
+ JDK1.4 logging( se estiver em uso JDK1.4 ou maior). Você pode fazer o
+ download do Log4j a partir de
<literal>http://jakarta.apache.org</literal>.
+ Para usar Log4j você necessitará colocar um arquivo
+ <literal>log4j.properties</literal> no seu classpath, um exemplo
de arquivo
+ de propriedades é distribuído com o Hibernate no diretório
+ <literal>src/</literal>.
+
+ </para>
+
+ <para>
+ We strongly recommend that you familiarize yourself with Hibernate's log
+ messages. A lot of work has been put into making the Hibernate log as
+ detailed as possible, without making it unreadable. It is an essential
+ troubleshooting device. The most interesting log categories are the
+ following:
+
+ Nós recomendamos enfaticamente que você se familiarize-se com mensagens de
+ log do Hibernate. Uma parte do trabalho tem sido posto em fazer o log
+ Hibernate tão detalhado quanto possível, sem fazê-lo ilegível.
+ É um essencial dispositivos de controle de erros. As categorias de log
+ mais interessantes são as seguintes:
+ </para>
+
+ <table frame="topbot" id="log-categories"
revision="2">
+ <title>Categorias de Log do Hibernate</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Categoria</entry>
+ <entry>Função</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+
<entry><literal>org.hibernate.SQL</literal></entry>
+ <entry>Registra todas as instruções SQL DML a medida
que elas são executadas</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.type</literal></entry>
+ <entry>Registra todos os parâmetros JDBC</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+ <entry>Registra todas as instruções SQL DDL a medida
que elas são executadas</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.pretty</literal></entry>
+ <entry>
+ Log the state of all entities (max 20 entities)
associated
+ with the session at flush time
+ Registra o estado de todas as entidades (máximo 20
entidades)
+ associadas a session no momento da limpeza (flush).
+ </entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.cache</literal></entry>
+ <entry>Registra todas as atividades de cachê de segundo
nível</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction</literal></entry>
+ <entry>Registra atividades relacionada a
transação</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.jdbc</literal></entry>
+ <entry>Registra todas as requisições de recursos
JDBC</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.hql.ast.AST</literal></entry>
+ <entry>
+ Registra instruções SQL e HQL durante a análise da
consultas
+ </entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.secure</literal></entry>
+ <entry>Registra todas as requisições de autorização
JAAS</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate</literal></entry>
+ <entry>
+ Registra tudo ( uma parte das informações, mas muito
+ útil para controle de erros )
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Quando desenvolver aplicações com Hibernate, você deve quase sempre trabalhar
com
+ debug <literal>debug</literal> para a categoria
<literal>org.hibernate.SQL</literal>,
+ ou, alternativamente, a com a propriedade
<literal>hibernate.show_sql</literal> habilitada.
+ </para>
+
+
+ </sect1>
+
+ <sect1 id="configuration-namingstrategy">
+ <title>Implementado uma
<literal>NamingStrategy</literal></title>
+
+ <para>
+ A interface <literal>org.hibernate.cfg.NamingStrategy</literal>
permite você
+ especificar um "padrão de nomeação" para objetos do banco de dados
e elementos schema.
+ </para>
+
+ <para>
+ Você deve criar regras para a geração automaticamente de identificadores
+ do banco de dados a partir de identificadores Java ou para processar
+ colunas "computadas" e nomes de tabelas dado o arquivo de
mapeamento
+ para nomes "físicos" de tabelas e colunas. Esta característica
ajuda a
+ reduzir a verbosidade do documento de mapeamento, eliminando interferências
+ repetitivas( <literal>TBL_</literal>prefixos, por exemplo). A
estratégia
+ default usada pelo Hibernate é completamente mínima.
+ </para>
+
+ <para>
+ Você pode especificar uma estratégia diferente ao chamar
+ <literal>Configuration.setNamingStrategy()</literal> antes de
adicionar
+ os mapeamentos:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration()
+ .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+ .addFile("Item.hbm.xml")
+ .addFile("Bid.hbm.xml")
+ .buildSessionFactory();]]></programlisting>
+
+ <para>
+ <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal> é uma
estratégia
+ interna que pode ser um ponto de começo útil para algumas aplicações.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-xmlconfig" revision="2">
+ <title>Arquivo de configuração XML</title>
+
+ <para>
+ Uma maneira alternativa de configuração é especificar uma configuração
completa
+ em um arquivo chamado <literal>hibernate.cfg.xml</literal>. Este
arquivo pode
+ ser usado como um substituto para o arquivo
<literal>hibernate.properties</literal>
+ ou, se ambos estão presentes, sobrescrever propriedades.
+ </para>
+
+ <para>
+ The XML configuration file is by default expected to be in the root o
+ your <literal>CLASSPATH</literal>. Here is an example:
+ O arquivo XML de configuração é por default esperado para estar na
+ raiz do seu <literal>CLASSPATH</literal>. Veja um exemplo:
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0'
encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD//EN"
+ "http://hibernate.sourceforge.net/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>]]></programlisting>
+
+ <para>
+ Como você pode ver, a vantagem deste enfoque é a externalização dos nomes dos
+ arquivos de mapeamento para configuração. O
<literal>hibernate.cfg.xml</literal>
+ também é mais conveniente caso você tenha que ajustar o cache do Hibernate.
+ Note que a escolha é sua em usar
<literal>hibernate.properties</literal> ou
+ <literal>hibernate.cfg.xml</literal>, ambos são equivalente, à
exceção dos benefícios
+ acima mencionados de usar a sintaxe de XML.
+ </para>
+
+ <para>
+ Com a configuração do XML, iniciar o Hibernate é então tão simples como
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new
Configuration().configure().buildSessionFactory();]]></programlisting>
+
+ <para>
+ You can pick a different XML configuration file using
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration()
+ .configure("catdb.cfg.xml")
+ .buildSessionFactory();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="configuration-j2ee" revision="1">
+ <title>Integração com servidores de aplicação J2EE</title>
+
+ <para>
+ O Hibernate tem os seguintes pontos da integração para o infraestrutura de
J2EE:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>DataSources gerenciados pelo container</emphasis>:
O Hibernate pode
+ usar conexões JDBC gerenciadas pelo Container e fornecidas pela JNDI.
Geralmente,
+ um <literal>TransactionManager</literal> compatível com JTA e
um
+ <literal>ResourceManager</literal> cuidam do gerenciamento da
transação ( CMT ),
+ especialmente em transações distribuídas manipuladas através de vários
DataSources.
+ Naturalmente, você também pode demarcar os limites das transações
programaticamente (BMT)
+ ou você poderia querer usar a API opcional do Hibernate
<literal>Transaction</literal>
+ para esta manter seu código portável.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Ligação (binding) automática a JNDI</emphasis>: O
Hibernate pode
+ associar sua <literal>SessionFactory</literal> a JNDI depois
de iniciado.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Ligação (binding) Session na JTA:</emphasis>
+ A <literal>Session</literal> do Hibernate pode
automaticamente ser ligada
+ ao escopo da transações JTA. Simplesmente localizando a
<literal>SessionFactory</literal>
+ da JNDI e obtendo a<literal>Session</literal> corrente. Deixe
o Hibernate cuidar
+ da limpeza e encerramento da <literal>Session</literal>
quando as transações JTA
+ terminarem. A Demarcação de transação pode ser declarativa (CMT) ou
+ programática(BMT/Transação do usuário).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>JMX deployment:</emphasis> Se você usa um JMX
servidor de
+ aplicações capaz (ex. Jboss AS), você pode fazer a instação do Hibernate
+ como um Mbean controlado. Isto evita ter que iniciar uma linha de
+ código para construir sua <literal>SessionFactory</literal>
de uma
+ <literal>Configuration</literal>. O container iniciará seu
+ <literal>HibernateService</literal>, e idealmente também
cuidará
+ das dependências de serviços (DataSources, têm que estar disponíveis
+ antes do Hibernate iniciar, etc.).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Dependendo em seu ambiente, você poderia ter que ajustar a opção de
configuração
+ <literal>hibernate.connection.aggressive_release</literal> para
verdadeiro ( true ),
+ se seu servidor de aplicações lançar exeções "retenção de
conecção".
+ </para>
+
+ <sect2 id="configuration-optional-transactionstrategy"
revision="3">
+ <title>Configuração de estratégia de transação</title>
+
+ <para>
+ A API Hibernate <literal>Session</literal> é 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 <literal>UserTransaction</literal> quando
necessário.
+
+ </para>
+
+ <para>
+ Para manter seu código portável entre estes dois ( e outros ) ambientes,
recomendamos
+ a API Hibernate <literal>Transaction</literal>, que envolve e
esconde o sistema subjacente.
+ Você tem que especificar um classe construtora para
<literal>Transaction</literal> instanciar
+ ajustando a propriedade de configuração do
<literal>hibernate.transaction.factory_class</literal>.
+
+ </para>
+
+ <para>
+ Existem três escolhas (internas) padrões:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+
<term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+ <listitem>
+ <para>delegada as transações (JDBC)a bases de dados
(Padrão)</para>
+
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+ <listitem>
+ <para>
+ delegada a transação a um container gerenciador se a
transação
+ existente estiver de acordo neste contexto (ex: método bean
sessão EJB),
+ se não uma nova transação é iniciada e uma transação
controlado por
+ um bean é usada.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+
<term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+ <listitem>
+ <para>delega para um container gerenciador de transações
JTA</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Você também pode definir suas próprias estratégias de transação ( para um
serviço de
+ transação CORBA por exemplo).
+ </para>
+
+ <para>
+ Algumas características no Hibernate (ex., o cache de segundo nível,
sessões contextuais
+ com JTA, etc.) requerem acesso a JTA
<literal>TransactionManager</literal> em um ambiente
+ controlado. Em um servidor de aplicação você tem que especificar como o
Hibernate pode
+ obter uma referência para a
<literal>TransactionManager</literal>, pois o J2EE não
+ padronize um mecanismo simples :
+ </para>
+
+ <table frame="topbot" id="jtamanagerlookup"
revision="1">
+ <title>Gerenciadores de transações JTA</title>
+ <tgroup cols="2">
+ <colspec colwidth="2.5*"/>
+ <colspec colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Transaction Factory</entry>
+ <entry align="center">Application
Server</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+
<entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+ <entry align="center">JBoss</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+ <entry align="center">Weblogic</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+ <entry
align="center">WebSphere</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+ <entry align="center">WebSphere
6</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+ <entry align="center">Orion</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+ <entry align="center">Resin</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+ <entry align="center">JOTM</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+ <entry align="center">JOnAS</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+ <entry align="center">JRun4</entry>
+ </row>
+ <row>
+
<entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+ <entry align="center">Borland
ES</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-jndi" revision="3">
+ <title><literal>SessionFactory</literal> ligada a
JNDI</title>
+
+ <para>
+ Uma <literal>SessionFactory</literal> de Hibernate ligada a
JNDI pode simplificar
+ a localização da fabrica e a criação de novas
<literal>Session</literal>s.
+ Observe que isto não relacionado a um
<literal>Datasource</literal> ligado
+ a JNDI, simplemente ambos usam o mesmo registro!
+ </para>
+
+ <para>
+ If you wish to have the <literal>SessionFactory</literal>
bound to a JNDI namespace, specify
+ a name (eg. <literal>java:hibernate/SessionFactory</literal>)
using the property
+ <literal>hibernate.session_factory_name</literal>. If this
property is omitted, the
+ <literal>SessionFactory</literal> will not be bound to JNDI.
(This is especially useful in
+ environments with a read-only JNDI default implementation, e.g. Tomcat.)
+ </para>
+
+ <para>
+ When binding the <literal>SessionFactory</literal> to JNDI,
Hibernate will use the values of
+ <literal>hibernate.jndi.url</literal>,
<literal>hibernate.jndi.class</literal> to instantiate
+ an initial context. If they are not specified, the default
<literal>InitialContext</literal>
+ will be used.
+ </para>
+
+ <para>
+ Hibernate will automatically place the
<literal>SessionFactory</literal> in JNDI after
+ you call <literal>cfg.buildSessionFactory()</literal>. This
means you will at least have
+ this call in some startup code (or utility class) in your application,
unless you use
+ JMX deployment with the <literal>HibernateService</literal>
(discussed later).
+ </para>
+
+ <para>
+ If you use a JNDI <literal>SessionFactory</literal>, an EJB
or any other class may
+ obtain the <literal>SessionFactory</literal> using a JNDI
lookup.
+ </para>
+
+ <para>
+ We recommend that you bind the
<literal>SessionFactory</literal> to JNDI in
+ a managend environment and use a <literal>static</literal>
singleton otherwise.
+ To shield your application code from these details, we also recommend to
hide the
+ actual lookup code for a <literal>SessionFactory</literal> in
a helper class,
+ such as <literal>HibernateUtil.getSessionFactory()</literal>.
Note that such a
+ class is also a convenient way to startup Hibernate—see chapter
1.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-currentsession"
revision="4">
+ <title>Current Session context management with JTA</title>
+
+ <para>
+ The easiest way to handle <literal>Session</literal>s and
transactions is
+ Hibernates automatic "current"
<literal>Session</literal> management.
+ See the discussion of <xref
linkend="architecture-current-session">current sessions</xref>.
+ Using the <literal>"jta"</literal> session context,
if there is no Hibernate
+ <literal>Session</literal> associated with the current JTA
transaction, one will
+ be started and associated with that JTA transaction the first time you call
+ <literal>sessionFactory.getCurrentSession()</literal>. The
<literal>Session</literal>s
+ retrieved via <literal>getCurrentSession()</literal> in
<literal>"jta"</literal> context
+ will be set to automatically flush before the transaction completes, close
+ after the transaction completes, and aggressively release JDBC connections
+ after each statement. This allows the
<literal>Session</literal>s 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 <literal>UserTransaction</literal>,
or (recommended
+ for portable code) use the Hibernate
<literal>Transaction</literal> API to set
+ transaction boundaries. If you run in an EJB container, declarative
transaction
+ demarcation with CMT is preferred.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-jmx" revision="1">
+ <title>JMX deployment</title>
+
+ <para>
+ The line <literal>cfg.buildSessionFactory()</literal> still
has to be executed
+ somewhere to get a <literal>SessionFactory</literal> into
JNDI. You can do this
+ either in a <literal>static</literal> initializer block (like
the one in
+ <literal>HibernateUtil</literal>) or you deploy Hibernate as
a <emphasis>managed
+ service</emphasis>.
+ </para>
+
+ <para>
+ Hibernate is distributed with
<literal>org.hibernate.jmx.HibernateService</literal>
+ for deployment on an application server with JMX capabilities, such as
JBoss AS.
+ The actual deployment and configuration is vendor specific. Here is an
example
+ <literal>jboss-service.xml</literal> for JBoss 4.0.x:
+ </para>
+
+ <programlisting><![CDATA[<?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>]]></programlisting>
+
+ <para>
+ This file is deployed in a directory called
<literal>META-INF</literal> and packaged
+ in a JAR file with the extension <literal>.sar</literal>
(service archive). You also need
+ to package Hibernate, its required third-party libraries, your compiled
persistent classes,
+ as well as your mapping files in the same archive. Your enterprise beans
(usually session
+ beans) may be kept in their own JAR file, but you may include this EJB
JAR file in the
+ main service archive to get a single (hot-)deployable unit. Consult the
JBoss AS
+ documentation for more information about JMX service and EJB deployment.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/events.xml
===================================================================
--- core/trunk/documentation/manual/pt-BR/src/main/docbook/content/events.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++ core/trunk/documentation/manual/pt-BR/src/main/docbook/content/events.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="events">
+<chapter id="events">
<title>Interceptadores e Eventos</title>
<para>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_mappings.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_mappings.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_mappings.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="example-mappings">
+<chapter id="example-mappings">
<title>Exemplo: Vários Mapeamentos</title>
<para>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_parentchild.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_parentchild.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_parentchild.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="example-parentchild">
+<chapter id="example-parentchild">
<title>Example: Parent/Child</title>
<para>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_weblog.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_weblog.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/example_weblog.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="example-weblog">
+<chapter id="example-weblog">
<title>Example: Weblog Application</title>
<sect1 id="example-weblog-classes">
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/filters.xml
===================================================================
--- core/trunk/documentation/manual/pt-BR/src/main/docbook/content/filters.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++ core/trunk/documentation/manual/pt-BR/src/main/docbook/content/filters.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="filters">
+<chapter id="filters">
<title>Filtrando dados</title>
<para>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/inheritance_mapping.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/inheritance_mapping.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/inheritance_mapping.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="inheritance">
+<chapter id="inheritance">
<title>Mapeamento de Herança</title>
<sect1 id="inheritance-strategies" revision="3">
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/performance.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/performance.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/performance.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="performance">
+<chapter id="performance">
<title>Aumentando a performance</title>
<sect1 id="performance-fetching" revision="2">
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/persistent_classes.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/persistent_classes.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/persistent_classes.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="persistent-classes" revision="2">
+<chapter id="persistent-classes" revision="2">
<title>Persistent Classes</title>
<para>
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/preface.xml
===================================================================
--- core/trunk/documentation/manual/pt-BR/src/main/docbook/content/preface.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++ core/trunk/documentation/manual/pt-BR/src/main/docbook/content/preface.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<preface id="preface" revision="2">
+<preface id="preface" revision="2">
<title>Prefácio</title>
<para>
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_criteria.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_criteria.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_criteria.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="querycriteria">
+<chapter id="querycriteria">
<title>Consultas por critérios</title>
<para>
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_hql.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_hql.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_hql.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,1163 +1,1174 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="queryhql">
- <title>HQL: A linguagem de Queries do Hibernate</title>
-
- <para>
- O Hibernate vem com uma poderosa linguagem que é (intencionalmente) muito
parecida
- com o SQL. Mas não seja enganado pela sintaxe; a HQL é totalmente orientada à
objetos,
- requer conhecimentos de herança, polimorfismo e associações.
- </para>
-
- <sect1 id="queryhql-casesensitivity">
- <title>Case Sensitíve</title>
-
- <para>
- As Queries não são case-sensitive, exceto pelo nomes das classes e
propriedades Java.
- <literal>sELEct</literal> e o mesmo que
- <literal>SELECT</literal> mas
- <literal>org.hibernate.eg.FOO</literal> não é
- <literal>org.hibernate.eg.Foo</literal> e
- <literal>foo.barSet</literal> não é
- <literal>foo.BARSET</literal>.
-
- </para>
-
- <para>
- Esse manual usa as palavras chave HQL em letras minúsculas. Alguns usuários
acham que
- com letras maiúsculas as queries ficam mais legíveis, mas nós achamos essa
convenção feia
- dentro do código Java.
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-from">
- <title>A clausula from</title>
-
- <para>
- A mais simples query possível do Hibernate é a assim:
- </para>
-
- <programlisting><![CDATA[from eg.Cat]]></programlisting>
-
- <para>
- Ela irá retornar todas as instancias da classe
<literal>eg.Cat</literal>.
- Necessariamente não precisamos qualificar o nome da classe, pois é realizado
- <literal>auto-import</literal> por padrão. Por isso na maior
parte do tempos
- nós simplesmente escrevemos:
- </para>
-
- <programlisting><![CDATA[from Cat]]></programlisting>
-
- <para>
- Na maior parte do tempo, você precisará atribuir um
<emphasis>alias</emphasis>,
- desde que você queira se referia ao <literal>Cat</literal> em
outras partes da
- query.
- </para>
-
- <programlisting><![CDATA[from Cat as cat]]></programlisting>
-
- <para>
- Essa query atribui um alias a <literal>cat</literal> para as
instancias de
- <literal>Cat</literal>, então nós podemos usar esse alias depois
na query.
- A palavra chave as é opcional; poderíamos escrever assim:
- </para>
-
- <programlisting><![CDATA[from Cat cat]]></programlisting>
-
- <para>
- Múltiplas classes pode ser envolvidas, resultando em um produto cartesiano ou
"cross" join.
- </para>
-
- <programlisting><![CDATA[from Formula,
Parameter]]></programlisting>
- <programlisting><![CDATA[from Formula as form, Parameter as
param]]></programlisting>
-
- <para>
- É considerada uma boa prática os nomes dos aliases começarem com letra
minúscula,
- aderente com os padrões Java para variáveis locais (ex:
<literal>domesticCat</literal>).
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-joins" revision="2">
- <title>Associações e joins</title>
-
- <para>
- Nós também podemos querer atribuir aliases em uma entidade associada, ou
mesmo
- em elementos de uma coleção de valores, usando um
<literal>join</literal>.
- </para>
-
- <programlisting><![CDATA[from Cat as cat
- inner join cat.mate as mate
- left outer join cat.kittens as kitten]]></programlisting>
-
- <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as
kittens]]></programlisting>
-
- <programlisting><![CDATA[from Formula form full join form.parameter
param]]></programlisting>
-
- <para>
- Os tipos de joins suportados foram inspirados no SQL ANSI:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>inner join</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>left outer join</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>right outer join</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>full join</literal> (geralmente não é útil)
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- The <literal>inner join</literal>, <literal>left outer
join</literal> and
- <literal>right outer join</literal> constructs may be
abbreviated.
- As construções <literal>inner join</literal>, <literal>left
outer join</literal> e
- <literal>right outer join</literal> podem ser abreviadas.
- </para>
-
- <programlisting><![CDATA[from Cat as cat
- join cat.mate as mate
- left join cat.kittens as kitten]]></programlisting>
-
- <para>
- Você pode fornecer condições extras de join usando a palavra
- chave do HQL <literal>with</literal>.
- </para>
-
- <programlisting><![CDATA[from Cat as cat
- left join cat.kittens as kitten
- <literal>with</literal> kitten.bodyWeight >
10.0]]></programlisting>
-
- <para>
- Adicionalmente, um "fetch" join permite que associações ou coleções
de valores
- sejam inicializadas junto com o objeto pai, usando apenas um select. Isso é
- muito útil no caso das coleções. Isso efetivamente sobre escreve as
declarações
- outer join e lazy do arquivo mapeamento para associações e coleções.
- Veja a seção <xref linkend="performance-fetching"/> para
mais informações.
- </para>
-
- <programlisting><![CDATA[from Cat as cat
- inner join <literal>fetch</literal>cat.mate
- left join
<literal>fetch</literal>cat.kittens]]></programlisting>
-
- <para>
- Usualmente, um <literal>fetch</literal>join não precisa atribuir
um alias, pois o objeto associado não
- deve ser usado na clausula <literal>where</literal> (ou em
qualquer outra clausula).
- Também, os objetos associados não são retornados diretamente nos resultados
da query.
- Ao invés disso, eles devem ser acessados usando o objeto pai. A única razão
que nós
- podemos necessitar de um alias é quando fazemos um fech join recursivamente
em uma
- coleção adicional:
- </para>
-
- <programlisting><![CDATA[from Cat as cat
- inner join <literal>fetch</literal>cat.mate
- left join <literal>fetch</literal>cat.kittens child
- left join
<literal>fetch</literal>child.kittens]]></programlisting>
-
- <para>
- Observe que a construção <literal>fetch</literal> não deve ser
usada em queries invocadas usando
- <literal>iterate()</literal> (embora possa ser usado com
<literal>scroll()</literal>). O
- <literal>fetch</literal> também não deve ser usado junto com o
<literal>setMaxResults()</literal> ou
- <literal>setFirstResult()</literal> pois essas operações são
baseadas nas linhas retornadas, que
- normalmente contem duplicidade devido ao fetching das coleções, então o
número de linhas pode não
- ser o que você espera.
-
- O <literal>fetch</literal> não deve ser usado junto com uma
condição <literal>with</literal> em
- uma condição <literal>with</literal> ad hoc. É possível que seja
criado um produto cartesiano pelo
- join fetching em mais do que uma coleção em uma query, então tome cuidado
nesses casos. Um join
- fetching em varias coleções pode trazer resultados inesperados para
mapeamentos do tipo bag, tome
- cuidado na hora de formular queries como essas. Finalmente, observe o
seguinte, o
- <literal>full join fetch</literal> e <literal>right join
fetch</literal> não são significativos.
- </para>
-
- <para>
-
- Se está usando o nível de propriedade lazy
(<literal>com</literal> instrumentação de bytecode), é possível
- forçar o Hibernate a <literal>buscar</literal> as propriedades
lazy imediatamente (na primeira query),
- usando <literal>fetch all properties </literal>.
- </para>
-
- <programlisting><![CDATA[from Document
<literal>fetch</literal>all properties order by
name]]></programlisting>
- <programlisting><![CDATA[from Document doc
<literal>fetch</literal>all properties where lower(doc.name) like
'%cats%']]></programlisting>
-
- </sect1>
-
- <sect1 id="queryhql-joins-forms">
- <title>Formas e sintaxe de joins</title>
-
- <para>
- O HQL suporta duas formas de associação para união:
<literal>implícita</literal> e <literal>explicita</literal>.
- </para>
-
- <para>
- As queries apresentadas na seção anterior usam a forma
<literal>explicita</literal>, onde a
- palavra chave "join" é explicitamente usada na clausula "from".
Essa é a forma recomendada.
- </para>
-
- <para>
- A forma <literal>implícita</literal> não usa a palavra chave
"join". Entretanto, as associações
- são diferenciadas usando pontuação ("." - dotnation). Uniões implícitas
podem aparecer em
- qualquer das clausulas HQL. A união <literal>implícita</literal>
resulta em declarações
- SQL que contem inner joins.
- </para>
-
- <programlisting><![CDATA[from Cat as cat where cat.mate.name like
'%s%']]></programlisting>
- </sect1>
-
- <sect1 id="queryhql-select">
- <title>Clausula select</title>
-
- <para>
- A clausula <literal>select</literal> seleciona quais obetos e
propriedades retornam
- no resultado da query. Considere:
- </para>
-
- <programlisting><![CDATA[select mate
-from Cat as cat
- inner join cat.mate as mate]]></programlisting>
-
- <para>
- A query selecionará <literal>mate</literal>s (companheiros), de
outros <literal>Cat</literal>s.
- Atualmente, podemos expressar a query de forma mais compacta como:
- </para>
-
- <programlisting><![CDATA[select cat.mate from Cat
cat]]></programlisting>
-
- <para>
- Queries podem retornar propriedades de qualquer tipo de valor, incluindo
propriedades de tipo de componente:
-
- </para>
-
- <programlisting><![CDATA[select cat.name from DomesticCat cat
-where cat.name like 'fri%']]></programlisting>
-
- <programlisting><![CDATA[select cust.name.firstName from Customer as
cust]]></programlisting>
-
- <para>
- Queries podem retornar múltiplos objetos e/ou propriedades como um array do
- tipo Object[],
- </para>
-
- <programlisting><![CDATA[select mother, offspr, mate.name
-from DomesticCat as mother
- inner join mother.mate as mate
- left outer join mother.kittens as offspr]]></programlisting>
-
- <para>
- ou como um <literal>List</literal>,
- </para>
-
- <programlisting><![CDATA[select new list(mother, offspr, mate.name)
-from DomesticCat as mother
- inner join mother.mate as mate
- left outer join mother.kittens as offspr]]></programlisting>
-
- <para>
- ou como um objeto Java typesafe,
- </para>
-
- <programlisting><![CDATA[select new Family(mother, mate, offspr)
-from DomesticCat as mother
- join mother.mate as mate
- left join mother.kittens as offspr]]></programlisting>
-
- <para>
- assumindo que a classe <literal>Family</literal> tenha um
construtor apropriado.
- </para>
-
- <para>
- Pode-se designar referencias a expressões selecionadas,
<literal>as</literal>:
- </para>
-
- <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight)
as min, count(*) as n
-from Cat cat]]></programlisting>
-
- <para>
- Isto é bem mais útil quando usado junto <literal>com</literal>
<literal>select new map</literal>:
- </para>
-
- <programlisting><![CDATA[select new map( max(bodyWeight) as max,
min(bodyWeight) as min, count(*) as n )
-from Cat cat]]></programlisting>
-
- <para>
- Esta query retorna um <literal>Map</literal> de referencias para
valores selecionados.
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-aggregation">
- <title>Funções de agregação</title>
-
- <para>
- As queries HQL podem retornar o resultado de funções agregadas nas
propriedades.
- </para>
-
- <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight),
max(cat.weight), count(cat)
-from Cat cat]]></programlisting>
-
-<!-- NO LONGER SUPPORTED
- <para>
- Collections may also appear inside aggregate functions in the
<literal>select</literal>
- clause.
- </para>
-
- <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
-from Cat cat group by cat]]></programlisting>
--->
-
- <para>
- As funções agregadas suportadas são:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>avg(...), sum(...), min(...),
max(...)</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>count(*)</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>count(...), count(distinct ...),
count(all...)</literal>
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Pode-se usar operadores aritiméticos, concatenação e funções SQL
- reconhecidas na clausula select:
- </para>
-
- <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
-from Cat cat
- join cat.kittens kitten
-group by cat.id, cat.weight]]></programlisting>
-
- <programlisting><![CDATA[select firstName||' '||initial||'
'||upper(lastName) from Person]]></programlisting>
-
- <para>
- As palavras <literal>distinct</literal> e
<literal>all</literal> podem ser usadas e têm
- a mesma semântica como no SQL.
- </para>
-
- <programlisting><![CDATA[select distinct cat.name from Cat cat
-
-select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
-
- </sect1>
-
- <sect1 id="queryhql-polymorphism">
- <title>Queries polimórficas</title>
-
- <para>
- A query:
- </para>
-
- <programlisting><![CDATA[from Cat as cat]]></programlisting>
-
- <para>
- retorna instancias não só de <literal>Cat</literal>, mas também
de subclasses como
- <literal>DomesticCat</literal>. As queries do Hibernate podem
nomear qualquer classe Java
- ou interface na clausula <literal>from</literal>. A query
retornará instancias de toda classe
- persistente que extenda a determinada classe ou implemente a determinada
interface. A query
- , a seguir, pode retornar todo objeto persistente:
- </para>
-
- <programlisting><![CDATA[from java.lang.Object
o]]></programlisting>
-
- <para>
- A interface <literal>Named</literal> pode ser implementada por
várias classes persistentes:
- </para>
-
- <programlisting><![CDATA[from Named n, Named m where n.name =
m.name]]></programlisting>
-
- <para>
- Note que as duas últimas queries requerem mais de um SQL SELECT . Isto
significa que a clausula
- <literal>order by</literal> não ordena corretamente todo o
resultado. (Isso também significa que
- você não pode chamar essas queries usando
<literal>Query.scroll()</literal>.)
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-where">
- <title>A clausula where</title>
-
- <para>
- A clausula <literal>where</literal> permite estreitar a lista de
instancias retornada.
- Se não houver referencia alguma, pode-se referir a propriedades pelo nome:
- </para>
-
- <programlisting><![CDATA[from Cat where
name='Fritz']]></programlisting>
-
- <para>
- Se houver uma referência, use o nome da propriedade qualificada:
- </para>
-
- <programlisting><![CDATA[from Cat as cat where
cat.name='Fritz']]></programlisting>
-
- <para>
- retorna instancias de <literal>Cat</literal> com nome ‘Fritz’.
- </para>
-
- <programlisting><![CDATA[select foo
-from Foo foo, Bar bar
-where foo.startDate = bar.date]]></programlisting>
-
- <para>
- retornará todas as instancias de <literal>Foo</literal>, para
cada
- um que tiver uma instancia de <literal>bar</literal> com a
propriedade
- <literal>date</literal> igual a propriedade
- <literal>startDate</literal> de
- <literal>Foo</literal>. Expressões de filtro compostas fazem da
- clausula <literal>where</literal>, extremamente poderosa.
Consideremos:
- </para>
-
- <programlisting><![CDATA[from Cat cat where cat.mate.name is not
null]]></programlisting>
-
- <para>
- Esta query traduzida para uma query SQL <literal>com</literal>
uma tabela (inner) join. Se fosse
- escrever algo como:
- </para>
-
- <programlisting><![CDATA[from Foo foo
-where foo.bar.baz.customer.address.city is not null]]></programlisting>
-
- <para>
- Poderia-se terminar <literal>com</literal> uma query que
necessitasse de join de quatro tabelas,
- no SQL.
- </para>
-
- <para>
- O operador <literal>=</literal> pode ser uasdo para comparar não
apenas propriedades,
- mas também instancias:
- </para>
-
- <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate =
rival.mate]]></programlisting>
-
- <programlisting><![CDATA[select cat, mate
-from Cat cat, Cat mate
-where cat.mate = mate]]></programlisting>
-
- <para>
- A propriedade especial (lowercase) <literal>id</literal> pode
ser usada para referenciar
- o identificador único de um objeto. (Pode-se usar também o nome de sua
propriedade)
- </para>
-
- <programlisting><![CDATA[from Cat as cat where cat.id = 123
-
-from Cat as cat where cat.mate.id = 69]]></programlisting>
-
- <para>
- A Segunda query é eficiente. Nenhuma união de tabelas é necessária!
- </para>
-
- <para>
- As propriedades de identificadores compostas também podem ser usadas. Suponha
que
- <literal>Person</literal> tenha um identificador composto que
consiste de
- <literal>country</literal> e
<literal>medicareNumber</literal>.
- </para>
-
- <programlisting><![CDATA[from bank.Person person
-where person.id.country = 'AU'
- and person.id.medicareNumber = 123456]]></programlisting>
-
- <programlisting><![CDATA[from bank.Account account
-where account.owner.id.country = 'AU'
- and account.owner.id.medicareNumber = 123456]]></programlisting>
-
- <para>
- Mais uma vez, a Segunda query não precisa de nenhum join de tabela.
- </para>
-
- <para>
- Assim mesmo, a propriedade especial <literal>class</literal>
acessa o valor discriminador da
- instancia, no caso de persistência polimórfica. O nome de uma classe Java
inclusa em uma
- clausula "where", será traduzida para seu valor descriminante.
- </para>
-
- <programlisting><![CDATA[from Cat cat where cat.class =
DomesticCat]]></programlisting>
-
- <para>
- Pode-se também especificar as propriedades dos components ou tipos de usuário
composto
- (e de componentes de componentes). Nunca tente usar uma expressão de filtro
que termine na propriedade
- de um tipo de componente (ao contrário de uma propriedade de um componente).
Por exemplo,
- se store.owner é uma entidade <literal>com</literal> um
componente <literal>address</literal>.
- </para>
-
- <programlisting><![CDATA[store.owner.address.city // okay
-store.owner.address // error!]]></programlisting>
-
- <para>
- Um tipo "any" tem as propriedades <literal>id</literal>
e <literal>class</literal> especiais,
- nôs permitindo expressar um join da seguinte forma (onde
<literal>AuditLog.item</literal> é
- uma propriedade mapeada <literal>com</literal>
<literal><any></literal>)
- </para>
-
- <programlisting><![CDATA[from AuditLog log, Payment payment
-where log.item.class = 'Payment' and log.item.id =
payment.id]]></programlisting>
-
- <para>
- Veja que <literal>log.item.class</literal> e
<literal>payment.class</literal> podem
- referir-se a valores de colunas de banco de dados completamente diferentes,
na query acima.
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-expressions">
- <title>Expressões</title>
-
- <para>
- As expressões permitidas na cláusula <literal>where</literal>
inclui a maioria
- das coisas que você poderia escrever no SQL:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- operadores matemáticos <literal>+, -, *, /</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- operadores de comparação binários <literal>=, >=,
<=, <>, !=, like</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- operadores lógicos <literal>and, or, not</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- parenteses <literal>( )</literal>, indicating grouping
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>in</literal>,
- <literal>not in</literal>,
- <literal>between</literal>,
- <literal>is null</literal>,
- <literal>is not null</literal>,
- <literal>is empty</literal>,
- <literal>is not empty</literal>,
- <literal>member of</literal> and
- <literal>not member of</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- case "simples" , <literal>case ... when ... then ...
else ... end</literal>, and
- "searched" case, <literal>case when ... then ... else
... end</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- concatenação de string <literal>...||...</literal> ou
<literal>concat(...,...)</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>current_date()</literal>,
<literal>current_time()</literal>,
- <literal>current_timestamp()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>second(...)</literal>,
<literal>minute(...)</literal>,
- <literal>hour(...)</literal>, <literal>day(...)</literal>,
- <literal>month(...)</literal>,
<literal>year(...)</literal>,
- </para>
- </listitem>
- <listitem>
- <para>
- qualquer funcao ou operador definida pela EJB-QL 3.0:
<literal>substring(), trim(),
- lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(),
mod()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>coalesce()</literal> and
<literal>nullif()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>str()</literal> para converter valores numericos
ou temporais para string
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>cast(... as ...)</literal>, onde o segundo
argumento é o nome do tipo
- hibernate, e<literal>extract(... from ...)</literal> se
ANSI
- <literal>cast()</literal> e
<literal>extract()</literal> é suportado pele
- banco de dados usado
- </para>
- </listitem>
- <listitem>
- <para>
- A função HQL <literal>index()</literal> , que se aplicam
a referencias de
- coleçôes associadas e indexadas
- </para>
- </listitem>
- <listitem>
- <para>
- As funções hql que retornam expressões de coleções de valores:
- <literal>size(), minelement(), maxelement(), minindex(),
maxindex()</literal>,
- <literal>junto</literal> com o elemento especial,
<literal>elements()</literal>,
- e funções de <literal>índice</literal> que podem ser
quantificadas usando
- <literal>some, all, exists, any, in</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Qualquer funçâo escalar pelo bando de dados como
<literal>sign()</literal>,
- <literal>trunc()</literal>,
<literal>rtrim()</literal>, <literal>sin()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- Parametros posicionais ao estilo JDBC
<literal>?</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- Parametros nomeados <literal>:name</literal>,
<literal>:start_date</literal>, <literal>:x1</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- Literais SQL <literal>'foo'</literal>,
<literal>69</literal>, <literal>6.66E+2</literal>,
- <literal>'1970-01-01 10:00:01.0'</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- Constantes Java <literal>public static final</literal>
<literal>ex: Color.TABBY</literal>
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- <literal>in</literal> e <literal>between</literal>
podem ser usadas da seguinte maneira:
- </para>
-
- <programlisting><![CDATA[from DomesticCat cat where cat.name between
'A' and 'B']]></programlisting>
-
- <programlisting><![CDATA[from DomesticCat cat where cat.name in (
'Foo', 'Bar', 'Baz' )]]></programlisting>
-
- <para>
- e as formas negativas podem ser escritas
- </para>
-
- <programlisting><![CDATA[from DomesticCat cat where cat.name not between
'A' and 'B']]></programlisting>
-
- <programlisting><![CDATA[from DomesticCat cat where cat.name not in (
'Foo', 'Bar', 'Baz' )]]></programlisting>
-
- <para>
- Likewise, <literal>is null</literal> and <literal>is not
null</literal> may be used to test
- for null values.
- Assim mesmo, , <literal>is null</literal> e <literal>is not
null</literal> podem ser usados
- para testar valores nulos.
- </para>
-
- <para>
- Booleanos podem ser facilmente usados em expressões, declarando as
substituições da HQL query,
- na configuração do Hibernate
- </para>
-
- <programlisting><![CDATA[<property
name="hibernate.query.substitutions">true 1, false
0</property>]]></programlisting>
-
- <para>
- Isso irá substituir as palavras chave <literal>true</literal> e
<literal>false</literal>
- <literal>pelos</literal> literais
<literal>1</literal> e <literal>0</literal> na tradução do HQL
para SQL.
- </para>
-
- <programlisting><![CDATA[from Cat cat where cat.alive =
true]]></programlisting>
-
- <para>
- Pode-se testar o tamanho de uma coleção <literal>com</literal> a
propriedade especial <literal>size</literal>,
- ou a função especial <literal>size()</literal>.
- </para>
-
- <programlisting><![CDATA[from Cat cat where cat.kittens.size >
0]]></programlisting>
-
- <programlisting><![CDATA[from Cat cat where size(cat.kittens) >
0]]></programlisting>
-
- <para>
- Para coleções indexadas, você pode se referir aos índices máximo e mínimo,
usando
- as funções <literal>minindex</literal> e
<literal>maxindex</literal>. Similarmente,
- pode-se referir aos elementos máximo e mínimo de uma coleção de tipos básicos
usando
- as funções <literal>minelement</literal> e
<literal>maxelement</literal>.
- </para>
-
- <programlisting><![CDATA[from Calendar cal where
maxelement(cal.holidays) > current_date]]></programlisting>
-
- <programlisting><![CDATA[from Order order where maxindex(order.items)
> 100]]></programlisting>
-
- <programlisting><![CDATA[from Order order where minelement(order.items)
> 10000]]></programlisting>
-
- <para>
- As funções SQL <literal>any, some, all, exists, in</literal> são
suportadas quando passado o
- elemento ou o conjunto de índices de uma coleção
(<literal>elements</literal> e
- <literal>indices</literal> de funções), ou o resultado de uma
subquery (veja abaixo).
- </para>
-
- <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
-where kit in elements(foo.kittens)]]></programlisting>
-
- <programlisting><![CDATA[select p from NameList list, Person p
-where p.name = some elements(list.names)]]></programlisting>
-
- <programlisting><![CDATA[from Cat cat where exists
elements(cat.kittens)]]></programlisting>
-
- <programlisting><![CDATA[from Player p where 3 > all
elements(p.scores)]]></programlisting>
-
- <programlisting><![CDATA[from Show show where 'fizard' in
indices(show.acts)]]></programlisting>
-
- <para>
- Note que essas construções - <literal>size</literal>,
<literal>elements</literal>,
- <literal>indices</literal>,
<literal>minindex</literal>, <literal>maxindex</literal>,
- <literal>minelement</literal>,
<literal>maxelement</literal>–
- só podem ser usados na clausula where do Hibernate3.
- </para>
-
- <para>
- Elementos de coleções com índice (arrays, lists, maps), podem ser
referenciadas
- pelo índice (apenas na clausula where):
- </para>
-
- <programlisting><![CDATA[from Order order where order.items[0].id =
1234]]></programlisting>
-
- <programlisting><![CDATA[select person from Person person, Calendar
calendar
-where calendar.holidays['national day'] = person.birthDay
- and person.nationality.calendar = calendar]]></programlisting>
-
- <programlisting><![CDATA[select item from Item item, Order order
-where order.items[ order.deliveredItemIndices[0] ] = item and order.id =
11]]></programlisting>
-
- <programlisting><![CDATA[select item from Item item, Order order
-where order.items[ maxindex(order.items) ] = item and order.id =
11]]></programlisting>
-
- <para>
- A expressão entre colchetes <literal>[]</literal>, pode ser até
uma expressão aritimética.
- </para>
-
- <programlisting><![CDATA[select item from Item item, Order order
-where order.items[ size(order.items) - 1 ] = item]]></programlisting>
-
- <para>
- O HQL também provê a função interna <literal>index()</literal>,
para elementos de
- associação um-pra-muitos ou coleção de valores.
- </para>
-
- <programlisting><![CDATA[select item, index(item) from Order order
- join order.items item
-where index(item) < 5]]></programlisting>
-
- <para>
- Funções escalares SQL, suportadas pelo banco de dados subjacente.
- </para>
-
- <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like
'FRI%']]></programlisting>
-
- <para>
- Se ainda ainda não está totalmente convencido, pense o quão maior e menos
legível poderia
- ser a query a seguir, em SQL:
- </para>
-
- <programlisting><![CDATA[select cust
-from Product prod,
- Store store
- inner join store.customers cust
-where prod.name = 'widget'
- and store.location.name in ( 'Melbourne', 'Sydney' )
- and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
-
- <para>
- <emphasis>Hint:</emphasis> something like
- </para>
-
- <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone,
cust.id, cust.current_order
-FROM customers cust,
- stores store,
- locations loc,
- store_customers sc,
- product prod
-WHERE prod.name = 'widget'
- AND store.loc_id = loc.id
- AND loc.name IN ( 'Melbourne', 'Sydney' )
- AND sc.store_id = store.id
- AND sc.cust_id = cust.id
- AND prod.id = ALL(
- SELECT item.prod_id
- FROM line_items item, orders o
- WHERE item.order_id = o.id
- AND cust.current_order = o.id
- )]]></programlisting>
-
- </sect1>
-
- <sect1 id="queryhql-ordering">
- <title>A clausula order by</title>
-
- <para>
- A lista retornada pela query pode ser ordenada por qualquer propriedade da
classe ou componente retornado:
- </para>
-
- <programlisting><![CDATA[from DomesticCat cat
-order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
-
- <para>
- As opções <literal>asc</literal> ou
<literal>desc</literal> indicam ordem crescente ou decrescente,
- respectivamente.
- </para>
- </sect1>
-
- <sect1 id="queryhql-grouping">
- <title>A clausula group by</title>
-
- <para>
- Uma query que retorne valores agregados, podem ser agrupados por qualquer
propriedade de uma classe
- ou componente retornado:
- </para>
-
- <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
-from Cat cat
-group by cat.color]]></programlisting>
-
- <programlisting><![CDATA[select foo.id, avg(name), max(name)
-from Foo foo join foo.names name
-group by foo.id]]></programlisting>
-
- <para>
- Uma clausula <literal>having</literal> também é permitida.
- </para>
-
- <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
-from Cat cat
-group by cat.color
-having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
-
- <para>
- Funções SQL e funções agregadas são permitidas nas clausulas
- <literal>having</literal> e <literal>order
by</literal>, se suportadas pelo banco
- de dados subjacente (ex: não no MySQL).
- </para>
-
- <programlisting><![CDATA[select cat
-from Cat cat
- join cat.kittens kitten
-group by cat
-having avg(kitten.weight) > 100
-order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
-
- <para>
- Note que, nem a clausula <literal>group by</literal> ou
- <literal>order by</literal>, podem conter expressões
aritiméticas.
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-subqueries" revision="2">
- <title>Subqueries</title>
-
- <para>
- Para bancos de dados que suportem subselects, o Hibernate suporta subqueries
dentro de queries.
- Uma subquery precisa estar entre parênteses (normalmente uma chamada de
função agregada SQL).
- Mesmo subqueries co-relacionadas (subqueries que fazem referência à alias de
outras queries),
- são aceitas.
- </para>
-
- <programlisting><![CDATA[from Cat as fatcat
-where fatcat.weight > (
- select avg(cat.weight) from DomesticCat cat
-)]]></programlisting>
-
- <programlisting><![CDATA[from DomesticCat as cat
-where cat.name = some (
- select name.nickName from Name as name
-)]]></programlisting>
-
- <programlisting><![CDATA[from Cat as cat
-where not exists (
- from Cat as mate where mate.mate = cat
-)]]></programlisting>
-
- <programlisting><![CDATA[from DomesticCat as cat
-where cat.name not in (
- select name.nickName from Name as name
-)]]></programlisting>
-
- <programlisting><![CDATA[select cat.id, (select max(kit.weight) from
cat.kitten kit)
-from Cat as cat]]></programlisting>
-
- <para>
- Note que HQL subqueries podem aparecer apenas dentro de clausulas select ou
where.
- </para>
-
- <para>
- Para subqueries <literal>com</literal> mais de uma expressão na
lista do select, pode-se usar um construtor
- de tuplas:
- </para>
-
- <programlisting><![CDATA[from Cat as cat
-where not ( cat.name, cat.color ) in (
- select cat.name, cat.color from DomesticCat cat
-)]]></programlisting>
-
- <para>
- Veja que em alguns bancos de dados (mas não o Oracle ou HSQL), pode-se usar
construtores
- de tuplas em outros contextos. Por exemplo quando buscando componentes ou
tipos de usuário composto.
- </para>
-
- <programlisting><![CDATA[from Person where name = ('Gavin',
'A', 'King')]]></programlisting>
-
- <para>
- Qual é equivalente ao mais verbalizado:
- </para>
-
- <programlisting><![CDATA[from Person where name.first = 'Gavin'
and name.initial = 'A' and name.last =
'King')]]></programlisting>
-
- <para>
- Há duas razões boas que você pode não querer fazer este tipo de coisa:
primeira, não
- é completamente portável entre plataformas de banco de dados; segunda, a
query agora é
- dependente da ordem de propriedades no documento de mapeamento.
- </para>
-
- </sect1>
-
- <sect1 id="queryhql-examples">
- <title>Exemplos de HQL</title>
-
- <para>
- As queries do Hibernate, podem ser muito poderosas e complexas. De fato, o
poder da linguagem de
- querie é um dos pontos principais na distribuição do Hibernate. Aqui temos
algumas queries de exemplo,
- muito similares a queries que usei em um projeto recente. Note que a maioria
das queries que você
- irá escrever, são mais simples que estas.
- </para>
-
- <para>
- A query a seguir retorna o id de order, numero de itens e o valor total do
order para todos os
- orders não pagos para um freguês particular e valor total mínimo dado,
ordenando os resultados por
- valor total. Ao determinar os preços, é usado o catalogo corrente. A query
SQL resultante,
- usando tabelas <literal>ORDER</literal>,
<literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
- <literal>CATALOG</literal> e
<literal>PRICE</literal>, tem quatro inner joins e um
- (não correlacionado) subselect.
- </para>
-
- <programlisting><![CDATA[select order.id, sum(price.amount),
count(item)
-from Order as order
- join order.lineItems as item
- join item.product as product,
- Catalog as catalog
- join catalog.prices as price
-where order.paid = false
- and order.customer = :customer
- and price.product = product
- and catalog.effectiveDate < sysdate
- and catalog.effectiveDate >= all (
- select cat.effectiveDate
- from Catalog as cat
- where cat.effectiveDate < sysdate
- )
-group by order
-having sum(price.amount) > :minAmount
-order by sum(price.amount) desc]]></programlisting>
-
- <para>
- Que monstro! Atualmente, na vida real, eu não sou muito afeiçoado a
subqueries, então
- minha query seria mais parecida com isto:
- </para>
-
- <programlisting><![CDATA[select order.id, sum(price.amount),
count(item)
-from Order as order
- join order.lineItems as item
- join item.product as product,
- Catalog as catalog
- join catalog.prices as price
-where order.paid = false
- and order.customer = :customer
- and price.product = product
- and catalog = :currentCatalog
-group by order
-having sum(price.amount) > :minAmount
-order by sum(price.amount) desc]]></programlisting>
-
- <para>
- A próxima query conta o número de pagamentos em cada status, tirando todos os
pagamentos com
- status <literal>AWAITING_APPROVAL</literal>, onde a mais recente
mudança de status foi feita
- pelo usuário corrente. Traduz-se para uma query SQL
<literal>com</literal> dois inner joins e
- um subselect correlacionado, nas tabelas
<literal>PAYMENT</literal>,
- <literal>PAYMENT_STATUS</literal> e
<literal>PAYMENT_STATUS_CHANGE</literal> .
- </para>
-
- <programlisting><![CDATA[select count(payment), status.name
-from Payment as payment
- join payment.currentStatus as status
- join payment.statusChanges as statusChange
-where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
- or (
- statusChange.timeStamp = (
- select max(change.timeStamp)
- from PaymentStatusChange change
- where change.payment = payment
- )
- and statusChange.user <> :currentUser
- )
-group by status.name, status.sortOrder
-order by status.sortOrder]]></programlisting>
-
- <para>
- Se eu tivesse mapeado a Collection
<literal>statusChanges</literal> como um List, ao invés de um
- Set, a query teria sido muito mais simples de escrever.
- </para>
-
- <programlisting><![CDATA[select count(payment), status.name
-from Payment as payment
- join payment.currentStatus as status
-where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
- or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <>
:currentUser
-group by status.name, status.sortOrder
-order by status.sortOrder]]></programlisting>
-
- <para>
- A próxima query usa a função <literal>isNull()</literal> do MS
SQL Server, para retornar
- todas as contas e pagamentos não pagos para a organização, para cada usuário
corrente
- pertencente. Traduz-se para uma query SQL <literal>com</literal>
três inner joins,
- um outer join e um subselect nas tabelas
<literal>ACCOUNT</literal>, <literal>PAYMENT</literal>,
-
<literal>PAYMENT_STATUS</literal>,<literal>ACCOUNT_TYPE</literal>,
- <literal>ORGANIZATION</literal> e
<literal>ORG_USER</literal> .
- </para>
-
- <programlisting><![CDATA[select account, payment
-from Account as account
- left outer join account.payments as payment
-where :currentUser in elements(account.holder.users)
- and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
-order by account.type.sortOrder, account.accountNumber,
payment.dueDate]]></programlisting>
-
- <para>
- Para alguns bancos de dados, precisaremos eleminar o subselect
(correlacionado).
- </para>
-
- <programlisting><![CDATA[select account, payment
-from Account as account
- join account.holder.users as user
- left outer join account.payments as payment
-where :currentUser = user
- and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
-order by account.type.sortOrder, account.accountNumber,
payment.dueDate]]></programlisting>
-
- </sect1>
-
- <sect1 id="queryhql-bulk" revision="2">
- <title>update e delete em lote</title>
-
- <para>
- Agora o HQL suporta declarações, <literal>update</literal>,
- <literal>delete</literal> e <literal>insert ... select
...</literal>
- Veja <xref linkend="batch-direct"/>, para mais detalhes.
- </para>
- </sect1>
-
- <sect1 id="queryhql-tipstricks">
- <title>Dicas e Truques</title>
-
- <para>
- Pode-se contar o número de resultados da query, sem realmente retorna-los.
- </para>
-
- <programlisting><![CDATA[( (Integer) session.createQuery("select
count(*) from ....").iterate().next() ).intValue()]]></programlisting>
-
- <para>
- Para ordenar um resultado pelo tamanho de uma Collection, use a query a
seguir.
- </para>
-
- <programlisting><![CDATA[select usr.id, usr.name
-from User as usr
- left join usr.messages as msg
-group by usr.id, usr.name
-order by count(msg)]]></programlisting>
-
- <para>
- Se seu banco de dados suporta subselects, pode-se colocar uma condição sobre
- tamanho de seleção na cláusula where da sua query:
- </para>
-
- <programlisting><![CDATA[from User usr where size(usr.messages) >=
1]]></programlisting>
-
- <para>
- Se seu banco de dados não suporta subselects, use a query a seguir:
- </para>
-
- <programlisting><![CDATA[select usr.id, usr.name
-from User usr.name
- join usr.messages msg
-group by usr.id, usr.name
-having count(msg) >= 1]]></programlisting>
-
- <para>
- Com essa solução não se pode retornar um <literal>User</literal>
<literal>com</literal> sem
- nenhuma menssagem, por causa do "inner join", a forma a seguir
também é útil.
- </para>
-
- <programlisting><![CDATA[select usr.id, usr.name
-from User as usr
- left join usr.messages as msg
-group by usr.id, usr.name
-having count(msg) = 0]]></programlisting>
-
- <para>
- As propriedades de um JavaBean podem ser limitadas à parâmetros nomeados da
query:
- </para>
-
- <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as
foo where foo.name=:name and foo.size=:size");
-q.setProperties(fooBean); // fooBean has getName() and getSize()
-List foos = q.list();]]></programlisting>
-
- <para>
- As Collections são paginaveis, usando a interface
<literal>Query</literal> <literal>com</literal> um filtro:
- </para>
-
- <programlisting><![CDATA[Query q = s.createFilter( collection,
"" ); // the trivial filter
-q.setMaxResults(PAGE_SIZE);
-q.setFirstResult(PAGE_SIZE * pageNumber);
-List page = q.list();]]></programlisting>
-
- <para>
- Os elementos da Collection podem ser ordenados ou agrupados
- usando um filtro de query:
- </para>
-
- <programlisting><![CDATA[Collection orderedCollection = s.filter(
collection, "order by this.amount" );
-Collection counts = s.filter( collection, "select this.type, count(this) group by
this.type" );]]></programlisting>
-
- <para>
- Pode-se achar o tamanho de uma Collection sem inicializa-la:
- </para>
-
- <programlisting><![CDATA[( (Integer) session.createQuery("select
count(*) from ....").iterate().next() ).intValue();]]></programlisting>
-
- </sect1>
-
-</chapter>
-
+<chapter id="queryhql">
+ <title>HQL: A linguagem de Queries do Hibernate</title>
+
+ <para>
+ O Hibernate vem com uma poderosa linguagem que é (intencionalmente) muito
parecida
+ com o SQL. Mas não seja enganado pela sintaxe; a HQL é totalmente orientada à
objetos,
+ requer conhecimentos de herança, polimorfismo e associações.
+ </para>
+
+ <sect1 id="queryhql-casesensitivity">
+ <title>Case Sensitíve</title>
+
+ <para>
+ As Queries não são case-sensitive, exceto pelo nomes das classes e
propriedades Java.
+ <literal>sELEct</literal> e o mesmo que
+ <literal>SELECT</literal> mas
+ <literal>org.hibernate.eg.FOO</literal> não é
+ <literal>org.hibernate.eg.Foo</literal> e
+ <literal>foo.barSet</literal> não é
+ <literal>foo.BARSET</literal>.
+
+ </para>
+
+ <para>
+ Esse manual usa as palavras chave HQL em letras minúsculas. Alguns usuários
acham que
+ com letras maiúsculas as queries ficam mais legíveis, mas nós achamos essa
convenção feia
+ dentro do código Java.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-from">
+ <title>A clausula from</title>
+
+ <para>
+ A mais simples query possível do Hibernate é a assim:
+ </para>
+
+ <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+ <para>
+ Ela irá retornar todas as instancias da classe
<literal>eg.Cat</literal>.
+ Necessariamente não precisamos qualificar o nome da classe, pois é realizado
+ <literal>auto-import</literal> por padrão. Por isso na maior
parte do tempos
+ nós simplesmente escrevemos:
+ </para>
+
+ <programlisting><![CDATA[from Cat]]></programlisting>
+
+ <para>
+ Na maior parte do tempo, você precisará atribuir um
<emphasis>alias</emphasis>,
+ desde que você queira se referia ao <literal>Cat</literal> em
outras partes da
+ query.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ Essa query atribui um alias a <literal>cat</literal> para as
instancias de
+ <literal>Cat</literal>, então nós podemos usar esse alias depois
na query.
+ A palavra chave as é opcional; poderíamos escrever assim:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+ <para>
+ Múltiplas classes pode ser envolvidas, resultando em um produto cartesiano ou
"cross" join.
+ </para>
+
+ <programlisting><![CDATA[from Formula,
Parameter]]></programlisting>
+ <programlisting><![CDATA[from Formula as form, Parameter as
param]]></programlisting>
+
+ <para>
+ É considerada uma boa prática os nomes dos aliases começarem com letra
minúscula,
+ aderente com os padrões Java para variáveis locais (ex:
<literal>domesticCat</literal>).
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins" revision="2">
+ <title>Associações e joins</title>
+
+ <para>
+ Nós também podemos querer atribuir aliases em uma entidade associada, ou
mesmo
+ em elementos de uma coleção de valores, usando um
<literal>join</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join cat.mate as mate
+ left outer join cat.kittens as kitten]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as
kittens]]></programlisting>
+
+ <programlisting><![CDATA[from Formula form full join form.parameter
param]]></programlisting>
+
+ <para>
+ Os tipos de joins suportados foram inspirados no SQL ANSI:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>inner join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>left outer join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>right outer join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>full join</literal> (geralmente não é útil)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The <literal>inner join</literal>, <literal>left outer
join</literal> and
+ <literal>right outer join</literal> constructs may be
abbreviated.
+ As construções <literal>inner join</literal>, <literal>left
outer join</literal> e
+ <literal>right outer join</literal> podem ser abreviadas.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ join cat.mate as mate
+ left join cat.kittens as kitten]]></programlisting>
+
+ <para>
+ Você pode fornecer condições extras de join usando a palavra
+ chave do HQL <literal>with</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ left join cat.kittens as kitten
+ <literal>with</literal> kitten.bodyWeight >
10.0]]></programlisting>
+
+ <para>
+ Adicionalmente, um "fetch" join permite que associações ou coleções
de valores
+ sejam inicializadas junto com o objeto pai, usando apenas um select. Isso é
+ muito útil no caso das coleções. Isso efetivamente sobre escreve as
declarações
+ outer join e lazy do arquivo mapeamento para associações e coleções.
+ Veja a seção <xref linkend="performance-fetching"/> para
mais informações.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join <literal>fetch</literal>cat.mate
+ left join
<literal>fetch</literal>cat.kittens]]></programlisting>
+
+ <para>
+ Usualmente, um <literal>fetch</literal>join não precisa atribuir
um alias, pois o objeto associado não
+ deve ser usado na clausula <literal>where</literal> (ou em
qualquer outra clausula).
+ Também, os objetos associados não são retornados diretamente nos resultados
da query.
+ Ao invés disso, eles devem ser acessados usando o objeto pai. A única razão
que nós
+ podemos necessitar de um alias é quando fazemos um fech join recursivamente
em uma
+ coleção adicional:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join <literal>fetch</literal>cat.mate
+ left join <literal>fetch</literal>cat.kittens child
+ left join
<literal>fetch</literal>child.kittens]]></programlisting>
+
+ <para>
+ Observe que a construção <literal>fetch</literal> não deve ser
usada em queries invocadas usando
+ <literal>iterate()</literal> (embora possa ser usado com
<literal>scroll()</literal>). O
+ <literal>fetch</literal> também não deve ser usado junto com o
<literal>setMaxResults()</literal> ou
+ <literal>setFirstResult()</literal> pois essas operações são
baseadas nas linhas retornadas, que
+ normalmente contem duplicidade devido ao fetching das coleções, então o
número de linhas pode não
+ ser o que você espera.
+
+ O <literal>fetch</literal> não deve ser usado junto com uma
condição <literal>with</literal> em
+ uma condição <literal>with</literal> ad hoc. É possível que seja
criado um produto cartesiano pelo
+ join fetching em mais do que uma coleção em uma query, então tome cuidado
nesses casos. Um join
+ fetching em varias coleções pode trazer resultados inesperados para
mapeamentos do tipo bag, tome
+ cuidado na hora de formular queries como essas. Finalmente, observe o
seguinte, o
+ <literal>full join fetch</literal> e <literal>right join
fetch</literal> não são significativos.
+ </para>
+
+ <para>
+
+ Se está usando o nível de propriedade lazy
(<literal>com</literal> instrumentação de bytecode), é possível
+ forçar o Hibernate a <literal>buscar</literal> as propriedades
lazy imediatamente (na primeira query),
+ usando <literal>fetch all properties </literal>.
+ </para>
+
+ <programlisting><![CDATA[from Document
<literal>fetch</literal>all properties order by
name]]></programlisting>
+ <programlisting><![CDATA[from Document doc
<literal>fetch</literal>all properties where lower(doc.name) like
'%cats%']]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins-forms">
+ <title>Formas e sintaxe de joins</title>
+
+ <para>
+ O HQL suporta duas formas de associação para união:
<literal>implícita</literal> e <literal>explicita</literal>.
+ </para>
+
+ <para>
+ As queries apresentadas na seção anterior usam a forma
<literal>explicita</literal>, onde a
+ palavra chave "join" é explicitamente usada na clausula "from".
Essa é a forma recomendada.
+ </para>
+
+ <para>
+ A forma <literal>implícita</literal> não usa a palavra chave
"join". Entretanto, as associações
+ são diferenciadas usando pontuação ("." - dotnation). Uniões implícitas
podem aparecer em
+ qualquer das clausulas HQL. A união <literal>implícita</literal>
resulta em declarações
+ SQL que contem inner joins.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.mate.name like
'%s%']]></programlisting>
+ </sect1>
+
+ <sect1 id="queryhql-identifier-property">
+ <title>Refering to identifier property</title>
+
+ <para>
+ There are, generally speaking, 2 ways to refer to an entity's identifier
property:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ The special property (lowercase) <literal>id</literal> may be used to
reference the identifier
+ property of an entity <emphasis>provided that entity does not define a
non-identifier property
+ named id</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the entity defines a named identifier property, you may use that property name.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ References to composite identifier properties follow the same naming rules. If the
+ entity has a non-identifier property named id, the composite identifier property can
only
+ be referenced by its defined named; otherwise, the special
<literal>id</literal> property
+ can be used to rerference the identifier property.
+ </para>
+
+ <para>
+ Note: this has changed significantly starting in version 3.2.2. In previous
versions,
+ <literal>id</literal> <emphasis>always</emphasis> referred to
the identifier property no
+ matter what its actual name. A ramification of that decision was that non-identifier
+ properties named <literal>id</literal> could never be referenced in
Hibernate queries.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-select">
+ <title>Clausula select</title>
+
+ <para>
+ A clausula <literal>select</literal> seleciona quais obetos e
propriedades retornam
+ no resultado da query. Considere:
+ </para>
+
+ <programlisting><![CDATA[select mate
+from Cat as cat
+ inner join cat.mate as mate]]></programlisting>
+
+ <para>
+ A query selecionará <literal>mate</literal>s (companheiros), de
outros <literal>Cat</literal>s.
+ Atualmente, podemos expressar a query de forma mais compacta como:
+ </para>
+
+ <programlisting><![CDATA[select cat.mate from Cat
cat]]></programlisting>
+
+ <para>
+ Queries podem retornar propriedades de qualquer tipo de valor, incluindo
propriedades de tipo de componente:
+
+ </para>
+
+ <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+ <programlisting><![CDATA[select cust.name.firstName from Customer as
cust]]></programlisting>
+
+ <para>
+ Queries podem retornar múltiplos objetos e/ou propriedades como um array do
+ tipo Object[],
+ </para>
+
+ <programlisting><![CDATA[select mother, offspr, mate.name
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ ou como um <literal>List</literal>,
+ </para>
+
+ <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ ou como um objeto Java typesafe,
+ </para>
+
+ <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+ join mother.mate as mate
+ left join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ assumindo que a classe <literal>Family</literal> tenha um
construtor apropriado.
+ </para>
+
+ <para>
+ Pode-se designar referencias a expressões selecionadas,
<literal>as</literal>:
+ </para>
+
+ <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight)
as min, count(*) as n
+from Cat cat]]></programlisting>
+
+ <para>
+ Isto é bem mais útil quando usado junto <literal>com</literal>
<literal>select new map</literal>:
+ </para>
+
+ <programlisting><![CDATA[select new map( max(bodyWeight) as max,
min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+ <para>
+ Esta query retorna um <literal>Map</literal> de referencias para
valores selecionados.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-aggregation">
+ <title>Funções de agregação</title>
+
+ <para>
+ As queries HQL podem retornar o resultado de funções agregadas nas
propriedades.
+ </para>
+
+ <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight),
max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+ <para>
+ Collections may also appear inside aggregate functions in the
<literal>select</literal>
+ clause.
+ </para>
+
+ <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+from Cat cat group by cat]]></programlisting>
+-->
+
+ <para>
+ As funções agregadas suportadas são:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>avg(...), sum(...), min(...),
max(...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(*)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(...), count(distinct ...),
count(all...)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Pode-se usar operadores aritiméticos, concatenação e funções SQL
+ reconhecidas na clausula select:
+ </para>
+
+ <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
+ join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+
+ <programlisting><![CDATA[select firstName||' '||initial||'
'||upper(lastName) from Person]]></programlisting>
+
+ <para>
+ As palavras <literal>distinct</literal> e
<literal>all</literal> podem ser usadas e têm
+ a mesma semântica como no SQL.
+ </para>
+
+ <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-polymorphism">
+ <title>Queries polimórficas</title>
+
+ <para>
+ A query:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ retorna instancias não só de <literal>Cat</literal>, mas também
de subclasses como
+ <literal>DomesticCat</literal>. As queries do Hibernate podem
nomear qualquer classe Java
+ ou interface na clausula <literal>from</literal>. A query
retornará instancias de toda classe
+ persistente que extenda a determinada classe ou implemente a determinada
interface. A query
+ , a seguir, pode retornar todo objeto persistente:
+ </para>
+
+ <programlisting><![CDATA[from java.lang.Object
o]]></programlisting>
+
+ <para>
+ A interface <literal>Named</literal> pode ser implementada por
várias classes persistentes:
+ </para>
+
+ <programlisting><![CDATA[from Named n, Named m where n.name =
m.name]]></programlisting>
+
+ <para>
+ Note que as duas últimas queries requerem mais de um SQL SELECT . Isto
significa que a clausula
+ <literal>order by</literal> não ordena corretamente todo o
resultado. (Isso também significa que
+ você não pode chamar essas queries usando
<literal>Query.scroll()</literal>.)
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-where">
+ <title>A clausula where</title>
+
+ <para>
+ A clausula <literal>where</literal> permite estreitar a lista de
instancias retornada.
+ Se não houver referencia alguma, pode-se referir a propriedades pelo nome:
+ </para>
+
+ <programlisting><![CDATA[from Cat where
name='Fritz']]></programlisting>
+
+ <para>
+ Se houver uma referência, use o nome da propriedade qualificada:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where
cat.name='Fritz']]></programlisting>
+
+ <para>
+ retorna instancias de <literal>Cat</literal> com nome ‘Fritz’.
+ </para>
+
+ <programlisting><![CDATA[select foo
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+ <para>
+ retornará todas as instancias de <literal>Foo</literal>, para
cada
+ um que tiver uma instancia de <literal>bar</literal> com a
propriedade
+ <literal>date</literal> igual a propriedade
+ <literal>startDate</literal> de
+ <literal>Foo</literal>. Expressões de filtro compostas fazem da
+ clausula <literal>where</literal>, extremamente poderosa.
Consideremos:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.mate.name is not
null]]></programlisting>
+
+ <para>
+ Esta query traduzida para uma query SQL <literal>com</literal>
uma tabela (inner) join. Se fosse
+ escrever algo como:
+ </para>
+
+ <programlisting><![CDATA[from Foo foo
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+ <para>
+ Poderia-se terminar <literal>com</literal> uma query que
necessitasse de join de quatro tabelas,
+ no SQL.
+ </para>
+
+ <para>
+ O operador <literal>=</literal> pode ser uasdo para comparar não
apenas propriedades,
+ mas também instancias:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate =
rival.mate]]></programlisting>
+
+ <programlisting><![CDATA[select cat, mate
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+ <para>
+ A propriedade especial (lowercase) <literal>id</literal> pode
ser usada para referenciar
+ o identificador único de um objeto. (Pode-se usar também o nome de sua
propriedade)
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+ <para>
+ A Segunda query é eficiente. Nenhuma união de tabelas é necessária!
+ </para>
+
+ <para>
+ As propriedades de identificadores compostas também podem ser usadas. Suponha
que
+ <literal>Person</literal> tenha um identificador composto que
consiste de
+ <literal>country</literal> e
<literal>medicareNumber</literal>.
+ </para>
+
+ <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+ and person.id.medicareNumber = 123456]]></programlisting>
+
+ <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+ and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+ <para>
+ Mais uma vez, a Segunda query não precisa de nenhum join de tabela.
+ </para>
+
+ <para>
+ Assim mesmo, a propriedade especial <literal>class</literal>
acessa o valor discriminador da
+ instancia, no caso de persistência polimórfica. O nome de uma classe Java
inclusa em uma
+ clausula "where", será traduzida para seu valor descriminante.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.class =
DomesticCat]]></programlisting>
+
+ <para>
+ Pode-se também especificar as propriedades dos components ou tipos de usuário
composto
+ (e de componentes de componentes). Nunca tente usar uma expressão de filtro
que termine na propriedade
+ de um tipo de componente (ao contrário de uma propriedade de um componente).
Por exemplo,
+ se store.owner é uma entidade <literal>com</literal> um
componente <literal>address</literal>.
+ </para>
+
+ <programlisting><![CDATA[store.owner.address.city // okay
+store.owner.address // error!]]></programlisting>
+
+ <para>
+ Um tipo "any" tem as propriedades <literal>id</literal>
e <literal>class</literal> especiais,
+ nôs permitindo expressar um join da seguinte forma (onde
<literal>AuditLog.item</literal> é
+ uma propriedade mapeada <literal>com</literal>
<literal><any></literal>)
+ </para>
+
+ <programlisting><![CDATA[from AuditLog log, Payment payment
+where log.item.class = 'Payment' and log.item.id =
payment.id]]></programlisting>
+
+ <para>
+ Veja que <literal>log.item.class</literal> e
<literal>payment.class</literal> podem
+ referir-se a valores de colunas de banco de dados completamente diferentes,
na query acima.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-expressions">
+ <title>Expressões</title>
+
+ <para>
+ As expressões permitidas na cláusula <literal>where</literal>
inclui a maioria
+ das coisas que você poderia escrever no SQL:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ operadores matemáticos <literal>+, -, *, /</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ operadores de comparação binários <literal>=, >=,
<=, <>, !=, like</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ operadores lógicos <literal>and, or, not</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ parenteses <literal>( )</literal>, indicating grouping
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>in</literal>,
+ <literal>not in</literal>,
+ <literal>between</literal>,
+ <literal>is null</literal>,
+ <literal>is not null</literal>,
+ <literal>is empty</literal>,
+ <literal>is not empty</literal>,
+ <literal>member of</literal> and
+ <literal>not member of</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ case "simples" , <literal>case ... when ... then ...
else ... end</literal>, and
+ "searched" case, <literal>case when ... then ... else
... end</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ concatenação de string <literal>...||...</literal> ou
<literal>concat(...,...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>current_date()</literal>,
<literal>current_time()</literal>,
+ <literal>current_timestamp()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>second(...)</literal>,
<literal>minute(...)</literal>,
+ <literal>hour(...)</literal>, <literal>day(...)</literal>,
+ <literal>month(...)</literal>,
<literal>year(...)</literal>,
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ qualquer funcao ou operador definida pela EJB-QL 3.0:
<literal>substring(), trim(),
+ lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(),
mod()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>coalesce()</literal> and
<literal>nullif()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>str()</literal> para converter valores numericos
ou temporais para string
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>cast(... as ...)</literal>, onde o segundo
argumento é o nome do tipo
+ hibernate, e<literal>extract(... from ...)</literal> se
ANSI
+ <literal>cast()</literal> e
<literal>extract()</literal> é suportado pele
+ banco de dados usado
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ A função HQL <literal>index()</literal> , que se aplicam
a referencias de
+ coleçôes associadas e indexadas
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ As funções hql que retornam expressões de coleções de valores:
+ <literal>size(), minelement(), maxelement(), minindex(),
maxindex()</literal>,
+ <literal>junto</literal> com o elemento especial,
<literal>elements()</literal>,
+ e funções de <literal>índice</literal> que podem ser
quantificadas usando
+ <literal>some, all, exists, any, in</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Qualquer funçâo escalar pelo bando de dados como
<literal>sign()</literal>,
+ <literal>trunc()</literal>,
<literal>rtrim()</literal>, <literal>sin()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Parametros posicionais ao estilo JDBC
<literal>?</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Parametros nomeados <literal>:name</literal>,
<literal>:start_date</literal>, <literal>:x1</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Literais SQL <literal>'foo'</literal>,
<literal>69</literal>, <literal>6.66E+2</literal>,
+ <literal>'1970-01-01 10:00:01.0'</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Constantes Java <literal>public static final</literal>
<literal>ex: Color.TABBY</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>in</literal> e <literal>between</literal>
podem ser usadas da seguinte maneira:
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name between
'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name in (
'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ e as formas negativas podem ser escritas
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not between
'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not in (
'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ Likewise, <literal>is null</literal> and <literal>is not
null</literal> may be used to test
+ for null values.
+ Assim mesmo, , <literal>is null</literal> e <literal>is not
null</literal> podem ser usados
+ para testar valores nulos.
+ </para>
+
+ <para>
+ Booleanos podem ser facilmente usados em expressões, declarando as
substituições da HQL query,
+ na configuração do Hibernate
+ </para>
+
+ <programlisting><![CDATA[<property
name="hibernate.query.substitutions">true 1, false
0</property>]]></programlisting>
+
+ <para>
+ Isso irá substituir as palavras chave <literal>true</literal> e
<literal>false</literal>
+ <literal>pelos</literal> literais
<literal>1</literal> e <literal>0</literal> na tradução do HQL
para SQL.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.alive =
true]]></programlisting>
+
+ <para>
+ Pode-se testar o tamanho de uma coleção <literal>com</literal> a
propriedade especial <literal>size</literal>,
+ ou a função especial <literal>size()</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.kittens.size >
0]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where size(cat.kittens) >
0]]></programlisting>
+
+ <para>
+ Para coleções indexadas, você pode se referir aos índices máximo e mínimo,
usando
+ as funções <literal>minindex</literal> e
<literal>maxindex</literal>. Similarmente,
+ pode-se referir aos elementos máximo e mínimo de uma coleção de tipos básicos
usando
+ as funções <literal>minelement</literal> e
<literal>maxelement</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Calendar cal where
maxelement(cal.holidays) > current_date]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where maxindex(order.items)
> 100]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where minelement(order.items)
> 10000]]></programlisting>
+
+ <para>
+ As funções SQL <literal>any, some, all, exists, in</literal> são
suportadas quando passado o
+ elemento ou o conjunto de índices de uma coleção
(<literal>elements</literal> e
+ <literal>indices</literal> de funções), ou o resultado de uma
subquery (veja abaixo).
+ </para>
+
+ <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where exists
elements(cat.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[from Player p where 3 > all
elements(p.scores)]]></programlisting>
+
+ <programlisting><![CDATA[from Show show where 'fizard' in
indices(show.acts)]]></programlisting>
+
+ <para>
+ Note que essas construções - <literal>size</literal>,
<literal>elements</literal>,
+ <literal>indices</literal>,
<literal>minindex</literal>, <literal>maxindex</literal>,
+ <literal>minelement</literal>,
<literal>maxelement</literal>–
+ só podem ser usados na clausula where do Hibernate3.
+ </para>
+
+ <para>
+ Elementos de coleções com índice (arrays, lists, maps), podem ser
referenciadas
+ pelo índice (apenas na clausula where):
+ </para>
+
+ <programlisting><![CDATA[from Order order where order.items[0].id =
1234]]></programlisting>
+
+ <programlisting><![CDATA[select person from Person person, Calendar
calendar
+where calendar.holidays['national day'] = person.birthDay
+ and person.nationality.calendar = calendar]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id =
11]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id =
11]]></programlisting>
+
+ <para>
+ A expressão entre colchetes <literal>[]</literal>, pode ser até
uma expressão aritimética.
+ </para>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+ <para>
+ O HQL também provê a função interna <literal>index()</literal>,
para elementos de
+ associação um-pra-muitos ou coleção de valores.
+ </para>
+
+ <programlisting><![CDATA[select item, index(item) from Order order
+ join order.items item
+where index(item) < 5]]></programlisting>
+
+ <para>
+ Funções escalares SQL, suportadas pelo banco de dados subjacente.
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like
'FRI%']]></programlisting>
+
+ <para>
+ Se ainda ainda não está totalmente convencido, pense o quão maior e menos
legível poderia
+ ser a query a seguir, em SQL:
+ </para>
+
+ <programlisting><![CDATA[select cust
+from Product prod,
+ Store store
+ inner join store.customers cust
+where prod.name = 'widget'
+ and store.location.name in ( 'Melbourne', 'Sydney' )
+ and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+ <para>
+ <emphasis>Hint:</emphasis> something like
+ </para>
+
+ <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone,
cust.id, cust.current_order
+FROM customers cust,
+ stores store,
+ locations loc,
+ store_customers sc,
+ product prod
+WHERE prod.name = 'widget'
+ AND store.loc_id = loc.id
+ AND loc.name IN ( 'Melbourne', 'Sydney' )
+ AND sc.store_id = store.id
+ AND sc.cust_id = cust.id
+ AND prod.id = ALL(
+ SELECT item.prod_id
+ FROM line_items item, orders o
+ WHERE item.order_id = o.id
+ AND cust.current_order = o.id
+ )]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-ordering">
+ <title>A clausula order by</title>
+
+ <para>
+ A lista retornada pela query pode ser ordenada por qualquer propriedade da
classe ou componente retornado:
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+ <para>
+ As opções <literal>asc</literal> ou
<literal>desc</literal> indicam ordem crescente ou decrescente,
+ respectivamente.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-grouping">
+ <title>A clausula group by</title>
+
+ <para>
+ Uma query que retorne valores agregados, podem ser agrupados por qualquer
propriedade de uma classe
+ ou componente retornado:
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color]]></programlisting>
+
+ <programlisting><![CDATA[select foo.id, avg(name), max(name)
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+ <para>
+ Uma clausula <literal>having</literal> também é permitida.
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+ <para>
+ Funções SQL e funções agregadas são permitidas nas clausulas
+ <literal>having</literal> e <literal>order
by</literal>, se suportadas pelo banco
+ de dados subjacente (ex: não no MySQL).
+ </para>
+
+ <programlisting><![CDATA[select cat
+from Cat cat
+ join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+ <para>
+ Note que, nem a clausula <literal>group by</literal> ou
+ <literal>order by</literal>, podem conter expressões
aritiméticas.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-subqueries" revision="2">
+ <title>Subqueries</title>
+
+ <para>
+ Para bancos de dados que suportem subselects, o Hibernate suporta subqueries
dentro de queries.
+ Uma subquery precisa estar entre parênteses (normalmente uma chamada de
função agregada SQL).
+ Mesmo subqueries co-relacionadas (subqueries que fazem referência à alias de
outras queries),
+ são aceitas.
+ </para>
+
+ <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+ select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat
+where not exists (
+ from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[select cat.id, (select max(kit.weight) from
cat.kitten kit)
+from Cat as cat]]></programlisting>
+
+ <para>
+ Note que HQL subqueries podem aparecer apenas dentro de clausulas select ou
where.
+ </para>
+
+ <para>
+ Note that subqueries can also utilize <literal>row value
constructor</literal> syntax. See
+ <xref linkend="queryhql-tuple"/> for more details.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-examples">
+ <title>Exemplos de HQL</title>
+
+ <para>
+ As queries do Hibernate, podem ser muito poderosas e complexas. De fato, o
poder da linguagem de
+ querie é um dos pontos principais na distribuição do Hibernate. Aqui temos
algumas queries de exemplo,
+ muito similares a queries que usei em um projeto recente. Note que a maioria
das queries que você
+ irá escrever, são mais simples que estas.
+ </para>
+
+ <para>
+ A query a seguir retorna o id de order, numero de itens e o valor total do
order para todos os
+ orders não pagos para um freguês particular e valor total mínimo dado,
ordenando os resultados por
+ valor total. Ao determinar os preços, é usado o catalogo corrente. A query
SQL resultante,
+ usando tabelas <literal>ORDER</literal>,
<literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+ <literal>CATALOG</literal> e
<literal>PRICE</literal>, tem quatro inner joins e um
+ (não correlacionado) subselect.
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount),
count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog.effectiveDate < sysdate
+ and catalog.effectiveDate >= all (
+ select cat.effectiveDate
+ from Catalog as cat
+ where cat.effectiveDate < sysdate
+ )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ Que monstro! Atualmente, na vida real, eu não sou muito afeiçoado a
subqueries, então
+ minha query seria mais parecida com isto:
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount),
count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ A próxima query conta o número de pagamentos em cada status, tirando todos os
pagamentos com
+ status <literal>AWAITING_APPROVAL</literal>, onde a mais recente
mudança de status foi feita
+ pelo usuário corrente. Traduz-se para uma query SQL
<literal>com</literal> dois inner joins e
+ um subselect correlacionado, nas tabelas
<literal>PAYMENT</literal>,
+ <literal>PAYMENT_STATUS</literal> e
<literal>PAYMENT_STATUS_CHANGE</literal> .
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+ join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or (
+ statusChange.timeStamp = (
+ select max(change.timeStamp)
+ from PaymentStatusChange change
+ where change.payment = payment
+ )
+ and statusChange.user <> :currentUser
+ )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ Se eu tivesse mapeado a Collection
<literal>statusChanges</literal> como um List, ao invés de um
+ Set, a query teria sido muito mais simples de escrever.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <>
:currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ A próxima query usa a função <literal>isNull()</literal> do MS
SQL Server, para retornar
+ todas as contas e pagamentos não pagos para a organização, para cada usuário
corrente
+ pertencente. Traduz-se para uma query SQL <literal>com</literal>
três inner joins,
+ um outer join e um subselect nas tabelas
<literal>ACCOUNT</literal>, <literal>PAYMENT</literal>,
+
<literal>PAYMENT_STATUS</literal>,<literal>ACCOUNT_TYPE</literal>,
+ <literal>ORGANIZATION</literal> e
<literal>ORG_USER</literal> .
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber,
payment.dueDate]]></programlisting>
+
+ <para>
+ Para alguns bancos de dados, precisaremos eleminar o subselect
(correlacionado).
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ join account.holder.users as user
+ left outer join account.payments as payment
+where :currentUser = user
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber,
payment.dueDate]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-bulk" revision="2">
+ <title>update e delete em lote</title>
+
+ <para>
+ Agora o HQL suporta declarações, <literal>update</literal>,
+ <literal>delete</literal> e <literal>insert ... select
...</literal>
+ Veja <xref linkend="batch-direct"/>, para mais detalhes.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tipstricks">
+ <title>Dicas e Truques</title>
+
+ <para>
+ Pode-se contar o número de resultados da query, sem realmente retorna-los.
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.createQuery("select
count(*) from ....").iterate().next() ).intValue()]]></programlisting>
+
+ <para>
+ Para ordenar um resultado pelo tamanho de uma Collection, use a query a
seguir.
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+ <para>
+ Se seu banco de dados suporta subselects, pode-se colocar uma condição sobre
+ tamanho de seleção na cláusula where da sua query:
+ </para>
+
+ <programlisting><![CDATA[from User usr where size(usr.messages) >=
1]]></programlisting>
+
+ <para>
+ Se seu banco de dados não suporta subselects, use a query a seguir:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+ join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+ <para>
+ Com essa solução não se pode retornar um <literal>User</literal>
<literal>com</literal> sem
+ nenhuma menssagem, por causa do "inner join", a forma a seguir
também é útil.
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+ <para>
+ As propriedades de um JavaBean podem ser limitadas à parâmetros nomeados da
query:
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as
foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+ <para>
+ As Collections são paginaveis, usando a interface
<literal>Query</literal> <literal>com</literal> um filtro:
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createFilter( collection,
"" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+ <para>
+ Os elementos da Collection podem ser ordenados ou agrupados
+ usando um filtro de query:
+ </para>
+
+ <programlisting><![CDATA[Collection orderedCollection = s.filter(
collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by
this.type" );]]></programlisting>
+
+ <para>
+ Pode-se achar o tamanho de uma Collection sem inicializa-la:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.createQuery("select
count(*) from ....").iterate().next() ).intValue();]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_sql.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_sql.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/query_sql.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="querysql" revision="2">
+<chapter id="querysql" revision="2">
<title>Native SQL</title>
<para>You may also express queries in the native SQL dialect of your
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/session_api.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/session_api.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/session_api.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,1248 +1,1270 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="objectstate">
- <title>Trabalhando com objetos</title>
-
- <para>
- O Hibernate é uma solução completa de mapeamento objeto/relacional que não apenas
- poupa o desenvolvedor dos detalhes de baixo nível do sistema de gerenciamento do
- banco de dados, mas também oferece um <emphasis>gerenciamento de estado
</emphasis>
- para objetos. Isto é, ao contrário do gerenciamento de <literal>instruções
</literal>
- SQL em camadas de persistência JDBC/SQL comuns, uma visão natural da persistência
- orientada a objetos em aplicações Java.
- </para>
-
- <para>
- Em outras palavras, desenvolvedores de aplicações Hibernate podem sempre pensar
em
- relação ao <emphasis>estado</emphasis> de seus objetos, e não
necessariamente em
- relação a execução de instruções SQL. Este parte é responsabilidade do Hibernate
e
- é relevante aos desenvolvedores de aplicações apenas quando estão ajustando
- a performance do sistema.
- </para>
-
- <sect1 id="objectstate-overview">
- <title>Estado dos objetos no Hibernate</title>
-
- <para>
- O Hibernate define e suporta os seguintes estados de um objetos:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Transient</emphasis> - um objeto é transiente
se ele foi instanciando
- usando apenas o operador <literal>new</literal>, e não
foi associado com uma
- <literal>Session</literal> do Hibernate. Ele não terá uma
representação
- persistente no banco de dados e nenhum identificador será atribuído
para ele.
- Instâncias transientes serão destruídas pelo coletor de lixo se a
aplicação
- não manter sua referência. Use uma
<literal>Session</literal> do Hibernate
- para tornar o objeto persistente ( e deixe o Hibernate gerenciar as
- instruções SQL que serão necessárias para executar esta transição).
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Persistent</emphasis> -– uma instância
persistente possui uma
- representação no banco de dados e um identificador. Ele pode ter sido
salvo
- ou carregado, assim, ele está por definição no escopo de uma
- <literal>Session</literal>. O Hibernate irá detectar
qualquer mudança feita a
- um objeto persistente e sincronizar o seu estado com o banco de dados
quando
- completar a unidade de trabalho. Desenvolvedores não executam
instruções manuais
- de <literal>UPDATE</literal>, ou instruções de
<literal>DELETE</literal>
- quando o objeto deve ser passado para transiente.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Detached</emphasis> – uma instância desaclopada
é um objeto que
- foi persistido, mas sua <literal>Session</literal> foi
fechada. A referência
- ao objeto continua válida, é claro, e a instância destacada
desaclopada pode
- ser acoplada a uma nova <literal>Session</literal> no
futuro, fazendo-o
- ( e todas as modificações sofridas) persistente novamente. Essa
característica
- possibilita um modelo de programação para unidades de trabalho que
rodam
- durante muito tempo que requer um pensamento por tempo do usuário.
Podemos
- chamar-las de <emphasis>transações da
aplicação</emphasis>, i.e. uma unidade
- de trabalho do ponto de vista do usuário.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Agora iremos discutir os estados e suas transições ( e os métodos do
Hibernate que
- disparam uma transição) em mais detalhes.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-makingpersistent" revision="1">
- <title>Tornando os objetos persistentes</title>
-
- <para>
- Instâncias recentemente instanciadas de uma classe persistente são
- consideradas <emphasis>transientes </emphasis> pelo Hibernate.
- Podemos tornar uma instância transiente em
<emphasis>persistente</emphasis>
- associando-a a uma sessão:
- </para>
-
- <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
-fritz.setColor(Color.GINGER);
-fritz.setSex('M');
-fritz.setName("Fritz");
-Long generatedId = (Long) sess.save(fritz);]]></programlisting>
-
- <para>
- Se <literal>Cat</literal> possui um identificador gerado, o
identificador
- é gerado e atribuído a <literal>cat</literal> quando
<literal>save()</literal>
- for chamada. Se <literal>Cat</literal> possuir um identificador
- <literal>Associado</literal>, ou uma chave composta, o
identificador deve ser
- atribuído à instância de <literal>cat</literal> antes que
<literal>save()</literal>
- seja chamado. Pode-se usar também <literal>persist()</literal>
ao invés de
- <literal>save()</literal>, com a semântica definada no novo
esboço do EJB3.
- </para>
-
- <para>
- Alternativamente, pode-se atribuir o identificador usando uma versão
- sobrecarregada de <literal>save()</literal>.
- </para>
-
-<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
-pk.setColor(Color.TABBY);
-pk.setSex('F');
-pk.setName("PK");
-pk.setKittens( new HashSet() );
-pk.addKitten(fritz);
-sess.save( pk, new Long(1234) );]]></programlisting>
-
- <para>
- Se o objeto persistido possuir objetos associados (e.g. a coleção
- <literal>kittens</literal> no exemplo anterior), esses objetos
podem ser
- tornar persistente em qualquer ordem que se queira ao menos que se tenha uma
- restrição <literal>NOT NULL</literal> em uma coluna de chave
estrangeira.
- Nunca há risco de violação de restrições de chave estrangeira. Assim,
- pode-se violar uma restrição <literal>NOT NULL</literal> se
- <literal>save()</literal> for usada nos objetos em uma ordem
errada.
- </para>
-
- <para>
- Geralmente você não deve se importar com esses detalhes, muito provavelmente
se
- usará a característica de <emphasis>persistência transitiva
</emphasis> do Hibernate
- para salvar os objetos associados automaticamente. Então, enquanto uma
restrição
- <literal>NOT NULL</literal> não ocorrer – Hibernate tomará conta
de tudo.
- Persistência transitiva será discutida futuramente nesse capítulo.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-loading">
- <title>Carregando o objetos</title>
-
- <para>
- O método <literal>load()</literal> de uma <literal>
Session</literal> nos
- fornece um meio para recuperar uma instância persistente se o identificador
- for conhecido. <literal>load()</literal> recebe uma classe do
objeto e carregará
- o estado em uma instância mais recente dessa classe, no estado persistente.
- </para>
-
- <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class,
generatedId);]]></programlisting>
-
-<programlisting><![CDATA[// you need to wrap primitive identifiers
-long id = 1234;
-DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id)
);]]></programlisting>
-
- <para>
- Alternatively, you can load state into a given instance:
-Alternativamente, pode-se carregar um estado em uma instância dada:
- </para>
-
-<programlisting><![CDATA[Cat cat = new DomesticCat();
-// load pk's state into cat
-sess.load( cat, new Long(pkId) );
-Set kittens = cat.getKittens();]]></programlisting>
-
- <para>
- Repare que <literal>load()</literal> irá lançar uma exceção
irrecuperável
- se não houver na tabela no banco de dados um registro que combine.
- Se a classe for mapeada com um proxy, <literal>load()</literal>
- simplesmente retorna um proxy não inicializado e realmente não chamará
- o banco de dados até que um método do proxy seja invocado.
- Esse comportamento é muito útil se deseja-se criar uma associação
- com um objeto sem que realmente o carregue do bando de dados.
- Isto também permite que sejam carregadas múltiplas instâncias como um
- grupo se <literal>batch-size</literal> estiver para o mapeamento
da
- classe.
- </para>
-
- <para>
- Se você não tiver certeza da existencia do registro no banco, você deve
- usar o metodo <literal>get()</literal>, que consulta o banco
- imediantamente e retorna um null se não existir o registro.
- </para>
-
- <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
-if (cat==null) {
- cat = new Cat();
- sess.save(cat, id);
-}
-return cat;]]></programlisting>
-
- <para>
- Também pode-se carregar um objeto usando <literal>SELECT ... FOR
UPDATE</literal>,
- usando um <literal>LockMode</literal>. Veja a documentação da API
para maiores
- informações.
- </para>
-
- <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id,
LockMode.UPGRADE);]]></programlisting>
-
- <para>
- Note that any associated instances or contained collections are
- <emphasis>not</emphasis> selected <literal>FOR
UPDATE</literal>, unless you decide
- to specify <literal>lock</literal> or
<literal>all</literal> as a
- cascade style for the association.
- </para>
-
- <para>
- O recarregamento de um objeto e todas as suas coleções é possível a qualquer
momento,
- usando o método <literal>refresh()</literal>. Util quando as
triggers do banco de
- dados são usados para inicializar algumas propriedades do objeto.
- </para>
-
- <programlisting><![CDATA[sess.save(cat);
-sess.flush(); //force the SQL INSERT
-sess.refresh(cat); //re-read the state (after the trigger
executes)]]></programlisting>
-
- <para>
- Uma importante questão geralmente aparece neste ponto: O quanto Hibernate
carrega
- do banco de dados e quantos SQL <literal>SELECT</literal> ele
irá usar? Isto
- depende da estratégia de <emphasis>recuperação</emphasis>usada e
explicada na
- <xref linkend="performance-fetching"/>.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-querying" revision="1">
- <title>Consultando</title>
-
- <para>
- Se o identificador do objeto que se está buscando não for conhecido,
- uma consulta será necessária. O Hibernate suporta uma linguagem de consulta
- (HQL) orientada a objetos fácil mas poderosa. Para criação via programação
- de consultas, o Hibernate suporta características sofisticadas de consulta
- por Critério e Exemplo (QBCe QBE). Pode-se também expressar a consulta
- por meio de SQL nativa do banco de dados, com suporte opcional do Hibernate
- para conversão do conjunto de reultados em objetos.
- </para>
-
- <sect2 id="objectstate-querying-executing"
revision="1">
- <title>Executando consultas</title>
-
- <para>
- Consultas HQL e SQL nativa são representadas por uma instância de
<literal>org.hibernate.Query</literal>.
- Esta interface oferece métodos para associação de parâmetros, tratamento
de conjunto de resultados,
- e para a execução de consultas reais. Você pode obter uma
<literal>Query</literal> usando a
- <literal>Session</literal> atual:
- </para>
-
- <programlisting><![CDATA[List cats = session.createQuery(
- "from Cat as cat where cat.birthdate < ?")
- .setDate(0, date)
- .list();
-
-List mothers = session.createQuery(
- "select mother from Cat as cat join cat.mother as mother where cat.name =
?")
- .setString(0, name)
- .list();
-
-List kittens = session.createQuery(
- "from Cat as cat where cat.mother = ?")
- .setEntity(0, pk)
- .list();
-
-Cat mother = (Cat) session.createQuery(
- "select cat.mother from Cat as cat where cat = ?")
- .setEntity(0, izi)
- .uniqueResult();]]
-
-Query mothersWithKittens = (Cat) session.createQuery(
- "select mother from Cat as mother left join fetch mother.kittens");
-Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
-
- <para>
- Geralmente uma consulta é executada ao invocar
<literal>list()</literal>,
- o resultado da consulta será carregado completamente em uma coleção na
memória.
- Instâncias de entidades recuperadas por uma consulta estão no estado
persistente.
- O <literal>uniqueResult()</literal> oferece um atalho se você
souber de
- previamente que a consulta retornará apenas um único objeto. Repare que
consultas
- que fazem uso de buscas de coleções de forma ansiosa (eager) geralmente
retornam
- duplicatas dos objetos raiz ( mas com suas coleções inicializadas ).
Pode-se
- filtrar estas duplicatas através de um simples
<literal>Set</literal>.
- </para>
-
- <sect3 id="objectstate-querying-executing-iterate">
- <title>Interagindo com resultados</title>
-
- <para>
- Ocasionalmente, deves-se ser capaz de atingir performances melhores
com
- a execução de consultas usando o método
<literal>iterate()</literal>.
- Geralmente isso será o caso esperado apenas se as instâncias dos
entidades
- reais retornadas pela consulta já estiverem na sessão ou no caché de
segundo
- nível. Caso elas ainda não tenham sido armazenadas,
<literal>iterate()</literal>
- será mais devagar do que <literal>list()</literal> e pode
ser necessário vários
- acessos ao banco de dados para um simples consulta, geralmente
<emphasis>1</emphasis>
- para a seleção inicial que retorna apenas identificadores, e
<emphasis>n</emphasis>
- consultas adicionais para inicializar as instâncias reais.
- </para>
-
- <programlisting><![CDATA[// fetch ids
-Iterator iter = sess.createQuery("from eg.Qux q order by
q.likeliness").iterate();
-while ( iter.hasNext() ) {
- Qux qux = (Qux) iter.next(); // fetch the object
- // something we couldnt express in the query
- if ( qux.calculateComplicatedAlgorithm() ) {
- // delete the current instance
- iter.remove();
- // dont need to process the rest
- break;
- }
-}]]></programlisting>
- </sect3>
-
- <sect3 id="objectstate-querying-executing-tuples">
- <title>Consultas que retornam tuplas</title>
-
- <para>
- Algumas vezes as consultas do Hibernate retornam tuplas de objetos,
nesse caso
- cada tupla é retornada como um array:
- </para>
-
- <programlisting><![CDATA[Iterator kittensAndMothers =
sess.createQuery(
- "select kitten, mother from Cat kitten join kitten.mother mother")
- .list()
- .iterator();
-
-while ( kittensAndMothers.hasNext() ) {
- Object[] tuple = (Object[]) kittensAndMothers.next();
- Cat kitten = (Cat) tuple[0];
- Cat mother = (Cat) tuple[1];
- ....
-}]]></programlisting>
-
- </sect3>
-
- <sect3 id="objectstate-querying-executing-scalar"
revision="1">
- <title>Resultados escalares</title>
-
- <para>
- Consultas devem especificar uma propriedade da classe na clausula
- <literal>select</literal>. Elas também podem chamar
funções SQL de agregaçãos.
- Propriedades ou agregações são considerados resultados agregados
- ( e não entidades no estado persistente).
- </para>
-
- <programlisting><![CDATA[Iterator results = sess.createQuery(
- "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
- "group by cat.color")
- .list()
- .iterator();
-
-while ( results.hasNext() ) {
- Object[] row = (Object[]) results.next();
- Color type = (Color) row[0];
- Date oldest = (Date) row[1];
- Integer count = (Integer) row[2];
- .....
-}]]></programlisting>
-
- </sect3>
-
- <sect3 id="objectstate-querying-executing-parameters">
- <title>Bind parameters</title>
-
- <para>
- Methods on <literal>Query</literal> are provided for
binding values to
- named parameters or JDBC-style <literal>?</literal>
parameters.
- <emphasis>Contrary to JDBC, Hibernate numbers parameters from
zero.</emphasis>
- Named parameters are identifiers of the form
<literal>:name</literal> in
- the query string. The advantages of named parameters are:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- named parameters are insensitive to the order they occur in
the
- query string
- </para>
- </listitem>
- <listitem>
- <para>
- they may occur multiple times in the same query
- </para>
- </listitem>
- <listitem>
- <para>
- they are self-documenting
- </para>
- </listitem>
- </itemizedlist>
-
- <programlisting><![CDATA[//named parameter (preferred)
-Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
-q.setString("name", "Fritz");
-Iterator cats = q.iterate();]]></programlisting>
-
- <programlisting><![CDATA[//positional parameter
-Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
-q.setString(0, "Izi");
-Iterator cats = q.iterate();]]></programlisting>
-
- <programlisting><![CDATA[//named parameter list
-List names = new ArrayList();
-names.add("Izi");
-names.add("Fritz");
-Query q = sess.createQuery("from DomesticCat cat where cat.name in
(:namesList)");
-q.setParameterList("namesList", names);
-List cats = q.list();]]></programlisting>
-
- </sect3>
-
- <sect3 id="objectstate-querying-executing-pagination">
- <title>Pagination</title>
-
- <para>
- If you need to specify bounds upon your result set (the maximum
number of rows
- you want to retrieve and / or the first row you want to retrieve) you
should
- use methods of the <literal>Query</literal> interface:
- </para>
-
- <programlisting><![CDATA[Query q = sess.createQuery("from
DomesticCat cat");
-q.setFirstResult(20);
-q.setMaxResults(10);
-List cats = q.list();]]></programlisting>
-
- <para>
- Hibernate knows how to translate this limit query into the native
- SQL of your DBMS.
- </para>
-
- </sect3>
-
- <sect3 id="objectstate-querying-executing-scrolling">
- <title>Scrollable iteration</title>
-
- <para>
- If your JDBC driver supports scrollable
<literal>ResultSet</literal>s, the
- <literal>Query</literal> interface may be used to obtain
a
- <literal>ScrollableResults</literal> object, which allows
flexible
- navigation of the query results.
- </para>
-
- <programlisting><![CDATA[Query q = sess.createQuery("select
cat.name, cat from DomesticCat cat " +
- "order by cat.name");
-ScrollableResults cats = q.scroll();
-if ( cats.first() ) {
-
- // find the first name on each page of an alphabetical list of cats by name
- firstNamesOfPages = new ArrayList();
- do {
- String name = cats.getString(0);
- firstNamesOfPages.add(name);
- }
- while ( cats.scroll(PAGE_SIZE) );
-
- // Now get the first page of cats
- pageOfCats = new ArrayList();
- cats.beforeFirst();
- int i=0;
- while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1)
);
-
-}
-cats.close()]]></programlisting>
-
- <para>
- Note that an open database connection (and cursor) is required for
this
- functionality, use
<literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
- if you need offline pagination functionality.
- </para>
-
- </sect3>
-
- <sect3 id="objectstate-querying-executing-named"
revision="1">
- <title>Externalizing named queries</title>
-
- <para>
- You may also define named queries in the mapping document. (Remember
to use a
- <literal>CDATA</literal> section if your query contains
characters that could
- be interpreted as markup.)
- </para>
-
- <programlisting><![CDATA[<query
name="ByNameAndMaximumWeight"><![CDATA[
- from eg.DomesticCat as cat
- where cat.name = ?
- and cat.weight > ?
-] ]></query>]]></programlisting>
-
- <para>
- Parameter binding and executing is done programatically:
- </para>
-
- <programlisting><![CDATA[Query q =
sess.getNamedQuery("ByNameAndMaximumWeight");
-q.setString(0, name);
-q.setInt(1, minWeight);
-List cats = q.list();]]></programlisting>
-
- <para>
- Note that the actual program code is independent of the query
language that
- is used, you may also define native SQL queries in metadata, or
migrate
- existing queries to Hibernate by placing them in mapping files.
- </para>
-
- <para>
- Also note that a query declaration inside a
<literal><hibernate-mapping></literal>
- element requires a global unique name for the query, while a query
declaration inside a
- <literal><class></literal> element is made
unique automatically by prepending the
- fully qualified name of the class, for example
- <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
- </para>
-
- </sect3>
-
- </sect2>
-
- <sect2 id="objectstate-filtering" revision="1">
- <title>Filtering collections</title>
- <para>
- A collection <emphasis>filter</emphasis> is a special type of
query that may be applied to
- a persistent collection or array. The query string may refer to
<literal>this</literal>,
- meaning the current collection element.
- </para>
-
- <programlisting><![CDATA[Collection blackKittens =
session.createFilter(
- pk.getKittens(),
- "where this.color = ?")
- .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
- .list()
-);]]></programlisting>
-
- <para>
- The returned collection is considered a bag, and it's a copy of the
given
- collection. The original collection is not modified (this is contrary to
- the implication of the name "filter", but consistent with
expected behavior).
- </para>
-
- <para>
- Observe that filters do not require a <literal>from</literal>
clause (though they may have
- one if required). Filters are not limited to returning the collection
elements themselves.
- </para>
-
- <programlisting><![CDATA[Collection blackKittenMates =
session.createFilter(
- pk.getKittens(),
- "select this.mate where this.color = eg.Color.BLACK.intValue")
- .list();]]></programlisting>
-
- <para>
- Even an empty filter query is useful, e.g. to load a subset of elements
in a
- huge collection:
- </para>
-
- <programlisting><![CDATA[Collection tenKittens =
session.createFilter(
- mother.getKittens(), "")
- .setFirstResult(0).setMaxResults(10)
- .list();]]></programlisting>
-
- </sect2>
-
- <sect2 id="objecstate-querying-criteria" revision="1">
- <title>Criteria queries</title>
-
- <para>
- HQL is extremely powerful but some developers prefer to build queries
dynamically,
- using an object-oriented API, rather than building query strings.
Hibernate provides
- an intuitive <literal>Criteria</literal> query API for these
cases:
- </para>
-
- <programlisting><![CDATA[Criteria crit =
session.createCriteria(Cat.class);
-crit.add( Restrictions.eq( "color", eg.Color.BLACK ) );
-crit.setMaxResults(10);
-List cats = crit.list();]]></programlisting>
-
- <para>
- The <literal>Criteria</literal> and the associated
<literal>Example</literal>
- API are discussed in more detail in <xref
linkend="querycriteria"/>.
- </para>
-
- </sect2>
-
- <sect2 id="objectstate-querying-nativesql"
revision="2">
- <title>Queries in native SQL</title>
-
- <para>
- You may express a query in SQL, using
<literal>createSQLQuery()</literal> and
- let Hibernate take care of the mapping from result sets to objects. Note
- that you may at any time call
<literal>session.connection()</literal> and
- use the JDBC <literal>Connection</literal> directly. If you
chose to use the
- Hibernate API, you must enclose SQL aliases in braces:
- </para>
-
- <programlisting><![CDATA[List cats =
session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
- .addEntity("cat", Cat.class)
-.list();]]></programlisting>
-
- <programlisting><![CDATA[List cats = session.createSQLQuery(
- "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
- "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
- "FROM CAT {cat} WHERE ROWNUM<10")
- .addEntity("cat", Cat.class)
-.list()]]></programlisting>
-
- <para>
- SQL queries may contain named and positional parameters, just like
Hibernate queries.
- More information about native SQL queries in Hibernate can be found in
- <xref linkend="querysql"/>.
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="objectstate-modifying" revision="1">
- <title>Modifying persistent objects</title>
-
- <para>
- <emphasis>Transactional persistent instances</emphasis> (ie.
objects loaded, saved, created or
- queried by the <literal>Session</literal>) may be manipulated by
the application
- and any changes to persistent state will be persisted when the
<literal>Session</literal>
- is <emphasis>flushed</emphasis> (discussed later in this
chapter). There is no need
- to call a particular method (like <literal>update()</literal>,
which has a different
- purpose) to make your modifications persistent. So the most straightforward
way to update
- the state of an object is to <literal>load()</literal> it,
- and then manipulate it directly, while the
<literal>Session</literal> is open:
- </para>
-
- <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load(
Cat.class, new Long(69) );
-cat.setName("PK");
-sess.flush(); // changes to cat are automatically detected and
persisted]]></programlisting>
-
- <para>
- Sometimes this programming model is inefficient since it would require both
an SQL
- <literal>SELECT</literal> (to load an object) and an SQL
<literal>UPDATE</literal>
- (to persist its updated state) in the same session. Therefore Hibernate
offers an
- alternate approach, using detached instances.
- </para>
-
- <para>
- <emphasis>Note that Hibernate does not offer its own API for direct
execution of
- <literal>UPDATE</literal> or
<literal>DELETE</literal> statements. Hibernate is a
- <emphasis>state management</emphasis> service, you don't have
to think in
- <emphasis>statements</emphasis> to use it. JDBC is a perfect API
for executing
- SQL statements, you can get a JDBC <literal>Connection</literal>
at any time
- by calling <literal>session.connection()</literal>. Furthermore,
the notion
- of mass operations conflicts with object/relational mapping for online
- transaction processing-oriented applications. Future versions of Hibernate
- may however provide special mass operation functions. See <xref
linkend="batch"/>
- for some possible batch operation tricks.</emphasis>
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-detached" revision="2">
- <title>Modifying detached objects</title>
-
- <para>
- Many applications need to retrieve an object in one transaction, send it to
the
- UI layer for manipulation, then save the changes in a new transaction.
- Applications that use this kind of approach in a high-concurrency
environment
- usually use versioned data to ensure isolation for the "long" unit
of work.
- </para>
-
- <para>
- Hibernate supports this model by providing for reattachment of detached
instances
- using the <literal>Session.update()</literal> or
<literal>Session.merge()</literal>
- methods:
- </para>
-
- <programlisting><![CDATA[// in the first session
-Cat cat = (Cat) firstSession.load(Cat.class, catId);
-Cat potentialMate = new Cat();
-firstSession.save(potentialMate);
-
-// in a higher layer of the application
-cat.setMate(potentialMate);
-
-// later, in a new session
-secondSession.update(cat); // update cat
-secondSession.update(mate); // update mate]]></programlisting>
-
- <para>
- If the <literal>Cat</literal> with identifier
<literal>catId</literal> had already
- been loaded by <literal>secondSession</literal> when the
application tried to
- reattach it, an exception would have been thrown.
- </para>
-
- <para>
- Use <literal>update()</literal> if you are sure that the session
does
- not contain an already persistent instance with the same identifier, and
- <literal>merge()</literal> if you want to merge your
modifications at any time
- without consideration of the state of the session. In other words,
<literal>update()</literal>
- is usually the first method you would call in a fresh session, ensuring that
- reattachment of your detached instances is the first operation that is
executed.
- </para>
-
- <para>
- The application should individually <literal>update()</literal>
detached instances
- reachable from the given detached instance if and
<emphasis>only</emphasis> if it wants
- their state also updated. This can be automated of course, using
<emphasis>transitive
- persistence</emphasis>, see <xref
linkend="objectstate-transitive"/>.
- </para>
-
- <para>
- The <literal>lock()</literal> method also allows an application
to reassociate
- an object with a new session. However, the detached instance has to be
unmodified!
- </para>
-
- <programlisting><![CDATA[//just reassociate:
-sess.lock(fritz, LockMode.NONE);
-//do a version check, then reassociate:
-sess.lock(izi, LockMode.READ);
-//do a version check, using SELECT ... FOR UPDATE, then reassociate:
-sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
-
- <para>
- Note that <literal>lock()</literal> can be used with various
- <literal>LockMode</literal>s, see the API documentation and the
- chapter on transaction handling for more information. Reattachment is not
- the only usecase for <literal>lock()</literal>.
- </para>
-
- <para>
- Other models for long units of work are discussed in <xref
linkend="transactions-optimistic"/>.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-saveorupdate">
- <title>Automatic state detection</title>
-
- <para>
- Hibernate users have requested a general purpose method that either saves a
- transient instance by generating a new identifier or updates/reattaches
- the detached instances associated with its current identifier.
- The <literal>saveOrUpdate()</literal> method implements this
functionality.
- </para>
-
- <programlisting><![CDATA[// in the first session
-Cat cat = (Cat) firstSession.load(Cat.class, catID);
-
-// in a higher tier of the application
-Cat mate = new Cat();
-cat.setMate(mate);
-
-// later, in a new session
-secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)
-secondSession.saveOrUpdate(mate); // save the new instance (mate has a null
id)]]></programlisting>
-
- <para>
- The usage and semantics of <literal>saveOrUpdate()</literal>
seems to be confusing
- for new users. Firstly, so long as you are not trying to use instances from
one session
- in another new session, you should not need to use
<literal>update()</literal>,
- <literal>saveOrUpdate()</literal>, or
<literal>merge()</literal>. Some whole
- applications will never use either of these methods.
- </para>
-
- <para>
- Usually <literal>update()</literal> or
<literal>saveOrUpdate()</literal> are used in
- the following scenario:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- the application loads an object in the first session
- </para>
- </listitem>
- <listitem>
- <para>
- the object is passed up to the UI tier
- </para>
- </listitem>
- <listitem>
- <para>
- some modifications are made to the object
- </para>
- </listitem>
- <listitem>
- <para>
- the object is passed back down to the business logic tier
- </para>
- </listitem>
- <listitem>
- <para>
- the application persists these modifications by calling
- <literal>update()</literal> in a second session
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- <literal>saveOrUpdate()</literal> does the following:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- if the object is already persistent in this session, do nothing
- </para>
- </listitem>
- <listitem>
- <para>
- if another object associated with the session has the same
identifier,
- throw an exception
- </para>
- </listitem>
- <listitem>
- <para>
- if the object has no identifier property,
<literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- if the object's identifier has the value assigned to a newly
instantiated
- object, <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- if the object is versioned (by a
<literal><version></literal> or
- <literal><timestamp></literal>), and the
version property value
- is the same value assigned to a newly instantiated object,
- <literal>save()</literal> it
- </para>
- </listitem>
- <listitem>
- <para>
- otherwise <literal>update()</literal> the object
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- and <literal>merge()</literal> is very different:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- if there is a persistent instance with the same identifier currently
- associated with the session, copy the state of the given object onto
- the persistent instance
- </para>
- </listitem>
- <listitem>
- <para>
- if there is no persistent instance currently associated with the
session,
- try to load it from the database, or create a new persistent
instance
- </para>
- </listitem>
- <listitem>
- <para>
- the persistent instance is returned
- </para>
- </listitem>
- <listitem>
- <para>
- the given instance does not become associated with the session, it
- remains detached
- </para>
- </listitem>
- </itemizedlist>
-
- </sect1>
-
- <sect1 id="objectstate-deleting" revision="1">
- <title>Deleting persistent objects</title>
-
- <para>
- <literal>Session.delete()</literal> will remove an object's
state from the database.
- Of course, your application might still hold a reference to a deleted
object.
- It's best to think of <literal>delete()</literal> as making a
persistent instance
- transient.
- </para>
-
- <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
-
- <para>
- You may delete objects in any order you like, without risk of foreign key
- constraint violations. It is still possible to violate a <literal>NOT
- NULL</literal> constraint on a foreign key column by deleting objects
in
- the wrong order, e.g. if you delete the parent, but forget to delete the
- children.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-replicating" revision="1">
- <title>Replicating object between two different datastores</title>
-
- <para>
- It is occasionally useful to be able to take a graph of persistent instances
- and make them persistent in a different datastore, without regenerating
identifier
- values.
- </para>
-
- <programlisting><![CDATA[//retrieve a cat from one database
-Session session1 = factory1.openSession();
-Transaction tx1 = session1.beginTransaction();
-Cat cat = session1.get(Cat.class, catId);
-tx1.commit();
-session1.close();
-
-//reconcile with a second database
-Session session2 = factory2.openSession();
-Transaction tx2 = session2.beginTransaction();
-session2.replicate(cat, ReplicationMode.LATEST_VERSION);
-tx2.commit();
-session2.close();]]></programlisting>
-
- <para>
- The <literal>ReplicationMode</literal> determines how
<literal>replicate()</literal>
- will deal with conflicts with existing rows in the database.
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>ReplicationMode.IGNORE</literal> - ignore the
object when there is
- an existing database row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.OVERWRITE</literal> - overwrite
any existing database
- row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.EXCEPTION</literal> - throw an
exception if there is
- an existing database row with the same identifier
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ReplicationMode.LATEST_VERSION</literal> -
overwrite the row if its
- version number is earlier than the version number of the object, or
ignore
- the object otherwise
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Usecases for this feature include reconciling data entered into different
database
- instances, upgrading system configuration information during product
upgrades,
- rolling back changes made during non-ACID transactions and more.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-flushing">
- <title>Flushing the Session</title>
-
- <para>
- From time to time the <literal>Session</literal> will execute the
SQL statements
- needed to synchronize the JDBC connection's state with the state of
objects held in
- memory. This process, <emphasis>flush</emphasis>, occurs by
default at the following
- points
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- before some query executions
- </para>
- </listitem>
- <listitem>
- <para>
- from
<literal>org.hibernate.Transaction.commit()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- from <literal>Session.flush()</literal>
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- The SQL statements are issued in the following order
- </para>
-
- <orderedlist spacing="compact">
- <listitem>
- <para>
- all entity insertions, in the same order the corresponding objects
- were saved using <literal>Session.save()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- all entity updates
- </para>
- </listitem>
- <listitem>
- <para>
- all collection deletions
- </para>
- </listitem>
- <listitem>
- <para>
- all collection element deletions, updates and insertions
- </para>
- </listitem>
- <listitem>
- <para>
- all collection insertions
- </para>
- </listitem>
- <listitem>
- <para>
- all entity deletions, in the same order the corresponding objects
- were deleted using <literal>Session.delete()</literal>
- </para>
- </listitem>
- </orderedlist>
-
- <para>
- (An exception is that objects using <literal>native</literal> ID
generation are
- inserted when they are saved.)
- </para>
-
- <para>
- Except when you explicity <literal>flush()</literal>, there are
absolutely no
- guarantees about <emphasis>when</emphasis> the
<literal>Session</literal> executes
- the JDBC calls, only the <emphasis>order</emphasis> in which they
are executed.
- However, Hibernate does guarantee that the
<literal>Query.list(..)</literal>
- will never return stale data; nor will they return the wrong data.
- </para>
-
- <para>
- It is possible to change the default behavior so that flush occurs less
frequently.
- The <literal>FlushMode</literal> class defines three different
modes: only flush
- at commit time (and only when the Hibernate
<literal>Transaction</literal> API
- is used), flush automatically using the explained routine, or never flush
unless
- <literal>flush()</literal> is called explicitly. The last mode is
useful for long running
- units of work, where a <literal>Session</literal> is kept open
and disconnected for
- a long time (see <xref
linkend="transactions-optimistic-longsession"/>).
- </para>
-
- <programlisting><![CDATA[sess = sf.openSession();
-Transaction tx = sess.beginTransaction();
-sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
-
-Cat izi = (Cat) sess.load(Cat.class, id);
-izi.setName(iznizi);
-
-// might return stale data
-sess.find("from Cat as cat left outer join cat.kittens kitten");
-
-// change to izi is not flushed!
-...
-tx.commit(); // flush occurs
-sess.close();]]></programlisting>
-
- <para>
- During flush, an exception might occur (e.g. if a DML operation violates a
constraint).
- Since handling exceptions involves some understanding of Hibernate's
transactional
- behavior, we discuss it in <xref linkend="transactions"/>.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-transitive" revision="1">
- <title>Transitive persistence</title>
-
- <para>
- It is quite cumbersome to save, delete, or reattach individual objects,
- especially if you deal with a graph of associated objects. A common case is
- a parent/child relationship. Consider the following example:
- </para>
-
- <para>
- If the children in a parent/child relationship would be value typed (e.g. a
collection
- of addresses or strings), their life cycle would depend on the parent and no
- further action would be required for convenient "cascading" of
state changes.
- When the parent is saved, the value-typed child objects are saved as
- well, when the parent is deleted, the children will be deleted, etc. This
- even works for operations such as the removal of a child from the
collection;
- Hibernate will detect this and, since value-typed objects can't have
shared
- references, delete the child from the database.
- </para>
-
- <para>
- Now consider the same scenario with parent and child objects being entities,
- not value-types (e.g. categories and items, or parent and child cats).
Entities
- have their own life cycle, support shared references (so removing an entity
from
- the collection does not mean it can be deleted), and there is by default no
- cascading of state from one entity to any other associated entities.
Hibernate
- does not implement <emphasis>persistence by
reachability</emphasis> by default.
- </para>
-
- <para>
- For each basic operation of the Hibernate session - including
<literal>persist(), merge(),
- saveOrUpdate(), delete(), lock(), refresh(), evict(),
replicate()</literal> - there is a
- corresponding cascade style. Respectively, the cascade styles are named
<literal>create,
- merge, save-update, delete, lock, refresh, evict, replicate</literal>.
If you want an
- operation to be cascaded along an association, you must indicate that in the
mapping
- document. For example:
- </para>
-
- <programlisting><![CDATA[<one-to-one name="person"
cascade="persist"/>]]></programlisting>
-
- <para>
- Cascade styles my be combined:
- </para>
-
- <programlisting><![CDATA[<one-to-one name="person"
cascade="persist,delete,lock"/>]]></programlisting>
-
- <para>
- You may even use <literal>cascade="all"</literal> to
specify that <emphasis>all</emphasis>
- operations should be cascaded along the association. The default
<literal>cascade="none"</literal>
- specifies that no operations are to be cascaded.
- </para>
-
- <para>
- A special cascade style, <literal>delete-orphan</literal>,
applies only to one-to-many
- associations, and indicates that the <literal>delete()</literal>
operation should
- be applied to any child object that is removed from the association.
- </para>
-
-
- <para>
- Recommendations:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- It doesn't usually make sense to enable cascade on a
<literal><many-to-one></literal>
- or <literal><many-to-many></literal>
association. Cascade is often useful for
- <literal><one-to-one></literal> and
<literal><one-to-many></literal>
- associations.
- </para>
- </listitem>
- <listitem>
- <para>
- If the child object's lifespan is bounded by the lifespan of the
parent
- object, make it a <emphasis>life cycle object</emphasis>
by specifying
-
<literal>cascade="all,delete-orphan"</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Otherwise, you might not need cascade at all. But if you think that
you will often be
- working with the parent and children together in the same
transaction, and you want to save
- yourself some typing, consider using
<literal>cascade="persist,merge,save-update"</literal>.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Mapping an association (either a single valued association, or a collection)
with
- <literal>cascade="all"</literal> marks the association
as a
- <emphasis>parent/child</emphasis> style relationship where
save/update/delete of the
- parent results in save/update/delete of the child or children.
- </para>
- <para>
- Futhermore, a mere reference to a child from a persistent parent will result
in
- save/update of the child. This metaphor is incomplete, however. A child which
becomes
- unreferenced by its parent is <emphasis>not</emphasis>
automatically deleted, except
- in the case of a <literal><one-to-many></literal>
association mapped with
- <literal>cascade="delete-orphan"</literal>. The precise
semantics of cascading
- operations for a parent/child relationship are as follows:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- If a parent is passed to <literal>persist()</literal>,
all children are passed to
- <literal>persist()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is passed to <literal>merge()</literal>, all
children are passed to
- <literal>merge()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is passed to <literal>save()</literal>,
<literal>update()</literal> or
- <literal>saveOrUpdate()</literal>, all children are
passed to <literal>saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a transient or detached child becomes referenced by a persistent
parent,
- it is passed to <literal>saveOrUpdate()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a parent is deleted, all children are passed to
<literal>delete()</literal>
- </para>
- </listitem>
- <listitem>
- <para>
- If a child is dereferenced by a persistent parent,
<emphasis>nothing
- special happens</emphasis> - the application should explicitly
delete
- the child if necessary - unless
<literal>cascade="delete-orphan"</literal>,
- in which case the "orphaned" child is deleted.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Finally, note that cascading of operations can be applied to an object graph
at
- <emphasis>call time</emphasis> or at <emphasis>flush
time</emphasis>. All operations,
- if enabled, are cascaded to associated entities reachable when the operation
is
- executed. However, <literal>save-upate</literal> and
<literal>delete-orphan</literal>
- are transitive for all associated entities reachable during flush of the
- <literal>Session</literal>.
- </para>
-
- </sect1>
-
- <sect1 id="objectstate-metadata">
- <title>Usando metadados</title>
-
- <para>
- O Hibernate requer um modelo muito rico a nível de metadados de todas as
entidades e tipos de
- valores. De tempos em tempos, este modelo é muito útil à própria aplicação.
Por exemplo, a
- aplicação pode usar o metadados do Hibernate que executa um algoritmo
"inteligente" que
- compreende quais objetos podem ser copiados (por exemplo, tipos de valores
mutáveis) ou
- não (por exemplo, tipos de valores imutáveis e, possivelmente, entidades
associadas).
- </para>
- <para>
- O Hibernate expõe o metadados via interfaces
<literal>ClassMetadata</literal>
- e <literal>CollectionMetadata</literal> e pela hierarquia
<literal>Type</literal>.
- Instâncias das interfaces de metadados podem ser obtidas a partir do
- <literal>SessionFactory</literal>.
- </para>
-
- <programlisting><![CDATA[Cat fritz = ......;
-ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
-
-Object[] propertyValues = catMeta.getPropertyValues(fritz);
-String[] propertyNames = catMeta.getPropertyNames();
-Type[] propertyTypes = catMeta.getPropertyTypes();
-
-// get a Map of all properties which are not collections or associations
-Map namedValues = new HashMap();
-for ( int i=0; i<propertyNames.length; i++ ) {
- if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType()
) {
- namedValues.put( propertyNames[i], propertyValues[i] );
- }
-}]]></programlisting>
-
- </sect1>
-
-</chapter>
-
+<chapter id="objectstate">
+ <title>Trabalhando com objetos</title>
+
+ <para>
+ O Hibernate é uma solução completa de mapeamento objeto/relacional que não apenas
+ poupa o desenvolvedor dos detalhes de baixo nível do sistema de gerenciamento do
+ banco de dados, mas também oferece um <emphasis>gerenciamento de estado
</emphasis>
+ para objetos. Isto é, ao contrário do gerenciamento de <literal>instruções
</literal>
+ SQL em camadas de persistência JDBC/SQL comuns, uma visão natural da persistência
+ orientada a objetos em aplicações Java.
+ </para>
+
+ <para>
+ Em outras palavras, desenvolvedores de aplicações Hibernate podem sempre pensar
em
+ relação ao <emphasis>estado</emphasis> de seus objetos, e não
necessariamente em
+ relação a execução de instruções SQL. Este parte é responsabilidade do Hibernate
e
+ é relevante aos desenvolvedores de aplicações apenas quando estão ajustando
+ a performance do sistema.
+ </para>
+
+ <sect1 id="objectstate-overview">
+ <title>Estado dos objetos no Hibernate</title>
+
+ <para>
+ O Hibernate define e suporta os seguintes estados de um objetos:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Transient</emphasis> - um objeto é transiente
se ele foi instanciando
+ usando apenas o operador <literal>new</literal>, e não
foi associado com uma
+ <literal>Session</literal> do Hibernate. Ele não terá uma
representação
+ persistente no banco de dados e nenhum identificador será atribuído
para ele.
+ Instâncias transientes serão destruídas pelo coletor de lixo se a
aplicação
+ não manter sua referência. Use uma
<literal>Session</literal> do Hibernate
+ para tornar o objeto persistente ( e deixe o Hibernate gerenciar as
+ instruções SQL que serão necessárias para executar esta transição).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Persistent</emphasis> -– uma instância
persistente possui uma
+ representação no banco de dados e um identificador. Ele pode ter sido
salvo
+ ou carregado, assim, ele está por definição no escopo de uma
+ <literal>Session</literal>. O Hibernate irá detectar
qualquer mudança feita a
+ um objeto persistente e sincronizar o seu estado com o banco de dados
quando
+ completar a unidade de trabalho. Desenvolvedores não executam
instruções manuais
+ de <literal>UPDATE</literal>, ou instruções de
<literal>DELETE</literal>
+ quando o objeto deve ser passado para transiente.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Detached</emphasis> – uma instância desaclopada
é um objeto que
+ foi persistido, mas sua <literal>Session</literal> foi
fechada. A referência
+ ao objeto continua válida, é claro, e a instância destacada
desaclopada pode
+ ser acoplada a uma nova <literal>Session</literal> no
futuro, fazendo-o
+ ( e todas as modificações sofridas) persistente novamente. Essa
característica
+ possibilita um modelo de programação para unidades de trabalho que
rodam
+ durante muito tempo que requer um pensamento por tempo do usuário.
Podemos
+ chamar-las de <emphasis>transações da
aplicação</emphasis>, i.e. uma unidade
+ de trabalho do ponto de vista do usuário.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Agora iremos discutir os estados e suas transições ( e os métodos do
Hibernate que
+ disparam uma transição) em mais detalhes.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-makingpersistent" revision="1">
+ <title>Tornando os objetos persistentes</title>
+
+ <para>
+ Instâncias recentemente instanciadas de uma classe persistente são
+ consideradas <emphasis>transientes </emphasis> pelo Hibernate.
+ Podemos tornar uma instância transiente em
<emphasis>persistente</emphasis>
+ associando-a a uma sessão:
+ </para>
+
+ <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+ <para>
+ Se <literal>Cat</literal> possui um identificador gerado, o
identificador
+ é gerado e atribuído a <literal>cat</literal> quando
<literal>save()</literal>
+ for chamada. Se <literal>Cat</literal> possuir um identificador
+ <literal>Associado</literal>, ou uma chave composta, o
identificador deve ser
+ atribuído à instância de <literal>cat</literal> antes que
<literal>save()</literal>
+ seja chamado. Pode-se usar também <literal>persist()</literal>
ao invés de
+ <literal>save()</literal>, com a semântica definada no novo
esboço do EJB3.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>persist()</literal> makes a transient instance persistent.
+ However, it doesn't guarantee that the identifier value will be assigned to
+ the persistent instance immediately, the assignment might happen at flush time.
+ <literal>persist()</literal> also guarantees that it will not execute an
+ <literal>INSERT</literal> statement if it is called outside of
transaction
+ boundaries. This is useful in long-running conversations with an extended
+ Session/persistence context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>save()</literal> does guarantee to return an identifier. If an
INSERT
+ has to be executed to get the identifier ( e.g. "identity" generator, not
+ "sequence"), this INSERT happens immediately, no matter if you are inside
or
+ outside of a transaction. This is problematic in a long-running conversation
+ with an extended Session/persistence context.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Alternativamente, pode-se atribuir o identificador usando uma versão
+ sobrecarregada de <literal>save()</literal>.
+ </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+
+ <para>
+ Se o objeto persistido possuir objetos associados (e.g. a coleção
+ <literal>kittens</literal> no exemplo anterior), esses objetos
podem ser
+ tornar persistente em qualquer ordem que se queira ao menos que se tenha uma
+ restrição <literal>NOT NULL</literal> em uma coluna de chave
estrangeira.
+ Nunca há risco de violação de restrições de chave estrangeira. Assim,
+ pode-se violar uma restrição <literal>NOT NULL</literal> se
+ <literal>save()</literal> for usada nos objetos em uma ordem
errada.
+ </para>
+
+ <para>
+ Geralmente você não deve se importar com esses detalhes, muito provavelmente
se
+ usará a característica de <emphasis>persistência transitiva
</emphasis> do Hibernate
+ para salvar os objetos associados automaticamente. Então, enquanto uma
restrição
+ <literal>NOT NULL</literal> não ocorrer – Hibernate tomará conta
de tudo.
+ Persistência transitiva será discutida futuramente nesse capítulo.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-loading">
+ <title>Carregando o objetos</title>
+
+ <para>
+ O método <literal>load()</literal> de uma <literal>
Session</literal> nos
+ fornece um meio para recuperar uma instância persistente se o identificador
+ for conhecido. <literal>load()</literal> recebe uma classe do
objeto e carregará
+ o estado em uma instância mais recente dessa classe, no estado persistente.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class,
generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id)
);]]></programlisting>
+
+ <para>
+ Alternatively, you can load state into a given instance:
+Alternativamente, pode-se carregar um estado em uma instância dada:
+ </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+ <para>
+ Repare que <literal>load()</literal> irá lançar uma exceção
irrecuperável
+ se não houver na tabela no banco de dados um registro que combine.
+ Se a classe for mapeada com um proxy, <literal>load()</literal>
+ simplesmente retorna um proxy não inicializado e realmente não chamará
+ o banco de dados até que um método do proxy seja invocado.
+ Esse comportamento é muito útil se deseja-se criar uma associação
+ com um objeto sem que realmente o carregue do bando de dados.
+ Isto também permite que sejam carregadas múltiplas instâncias como um
+ grupo se <literal>batch-size</literal> estiver para o mapeamento
da
+ classe.
+ </para>
+
+ <para>
+ Se você não tiver certeza da existencia do registro no banco, você deve
+ usar o metodo <literal>get()</literal>, que consulta o banco
+ imediantamente e retorna um null se não existir o registro.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+ cat = new Cat();
+ sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+ <para>
+ Também pode-se carregar um objeto usando <literal>SELECT ... FOR
UPDATE</literal>,
+ usando um <literal>LockMode</literal>. Veja a documentação da API
para maiores
+ informações.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id,
LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Note that any associated instances or contained collections are
+ <emphasis>not</emphasis> selected <literal>FOR
UPDATE</literal>, unless you decide
+ to specify <literal>lock</literal> or
<literal>all</literal> as a
+ cascade style for the association.
+ </para>
+
+ <para>
+ O recarregamento de um objeto e todas as suas coleções é possível a qualquer
momento,
+ usando o método <literal>refresh()</literal>. Util quando as
triggers do banco de
+ dados são usados para inicializar algumas propriedades do objeto.
+ </para>
+
+ <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger
executes)]]></programlisting>
+
+ <para>
+ Uma importante questão geralmente aparece neste ponto: O quanto Hibernate
carrega
+ do banco de dados e quantos SQL <literal>SELECT</literal> ele
irá usar? Isto
+ depende da estratégia de <emphasis>recuperação</emphasis>usada e
explicada na
+ <xref linkend="performance-fetching"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-querying" revision="1">
+ <title>Consultando</title>
+
+ <para>
+ Se o identificador do objeto que se está buscando não for conhecido,
+ uma consulta será necessária. O Hibernate suporta uma linguagem de consulta
+ (HQL) orientada a objetos fácil mas poderosa. Para criação via programação
+ de consultas, o Hibernate suporta características sofisticadas de consulta
+ por Critério e Exemplo (QBCe QBE). Pode-se também expressar a consulta
+ por meio de SQL nativa do banco de dados, com suporte opcional do Hibernate
+ para conversão do conjunto de reultados em objetos.
+ </para>
+
+ <sect2 id="objectstate-querying-executing"
revision="1">
+ <title>Executando consultas</title>
+
+ <para>
+ Consultas HQL e SQL nativa são representadas por uma instância de
<literal>org.hibernate.Query</literal>.
+ Esta interface oferece métodos para associação de parâmetros, tratamento
de conjunto de resultados,
+ e para a execução de consultas reais. Você pode obter uma
<literal>Query</literal> usando a
+ <literal>Session</literal> atual:
+ </para>
+
+ <programlisting><![CDATA[List cats = session.createQuery(
+ "from Cat as cat where cat.birthdate < ?")
+ .setDate(0, date)
+ .list();
+
+List mothers = session.createQuery(
+ "select mother from Cat as cat join cat.mother as mother where cat.name =
?")
+ .setString(0, name)
+ .list();
+
+List kittens = session.createQuery(
+ "from Cat as cat where cat.mother = ?")
+ .setEntity(0, pk)
+ .list();
+
+Cat mother = (Cat) session.createQuery(
+ "select cat.mother from Cat as cat where cat = ?")
+ .setEntity(0, izi)
+ .uniqueResult();]]
+
+Query mothersWithKittens = (Cat) session.createQuery(
+ "select mother from Cat as mother left join fetch mother.kittens");
+Set uniqueMothers = new HashSet(mothersWithKittens.list());]]></programlisting>
+
+ <para>
+ Geralmente uma consulta é executada ao invocar
<literal>list()</literal>,
+ o resultado da consulta será carregado completamente em uma coleção na
memória.
+ Instâncias de entidades recuperadas por uma consulta estão no estado
persistente.
+ O <literal>uniqueResult()</literal> oferece um atalho se você
souber de
+ previamente que a consulta retornará apenas um único objeto. Repare que
consultas
+ que fazem uso de buscas de coleções de forma ansiosa (eager) geralmente
retornam
+ duplicatas dos objetos raiz ( mas com suas coleções inicializadas ).
Pode-se
+ filtrar estas duplicatas através de um simples
<literal>Set</literal>.
+ </para>
+
+ <sect3 id="objectstate-querying-executing-iterate">
+ <title>Interagindo com resultados</title>
+
+ <para>
+ Ocasionalmente, deves-se ser capaz de atingir performances melhores
com
+ a execução de consultas usando o método
<literal>iterate()</literal>.
+ Geralmente isso será o caso esperado apenas se as instâncias dos
entidades
+ reais retornadas pela consulta já estiverem na sessão ou no caché de
segundo
+ nível. Caso elas ainda não tenham sido armazenadas,
<literal>iterate()</literal>
+ será mais devagar do que <literal>list()</literal> e pode
ser necessário vários
+ acessos ao banco de dados para um simples consulta, geralmente
<emphasis>1</emphasis>
+ para a seleção inicial que retorna apenas identificadores, e
<emphasis>n</emphasis>
+ consultas adicionais para inicializar as instâncias reais.
+ </para>
+
+ <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by
q.likeliness").iterate();
+while ( iter.hasNext() ) {
+ Qux qux = (Qux) iter.next(); // fetch the object
+ // something we couldnt express in the query
+ if ( qux.calculateComplicatedAlgorithm() ) {
+ // delete the current instance
+ iter.remove();
+ // dont need to process the rest
+ break;
+ }
+}]]></programlisting>
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-tuples">
+ <title>Consultas que retornam tuplas</title>
+
+ <para>
+ Algumas vezes as consultas do Hibernate retornam tuplas de objetos,
nesse caso
+ cada tupla é retornada como um array:
+ </para>
+
+ <programlisting><![CDATA[Iterator kittensAndMothers =
sess.createQuery(
+ "select kitten, mother from Cat kitten join kitten.mother mother")
+ .list()
+ .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+ Object[] tuple = (Object[]) kittensAndMothers.next();
+ Cat kitten = (Cat) tuple[0];
+ Cat mother = (Cat) tuple[1];
+ ....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scalar"
revision="1">
+ <title>Resultados escalares</title>
+
+ <para>
+ Consultas devem especificar uma propriedade da classe na clausula
+ <literal>select</literal>. Elas também podem chamar
funções SQL de agregaçãos.
+ Propriedades ou agregações são considerados resultados agregados
+ ( e não entidades no estado persistente).
+ </para>
+
+ <programlisting><![CDATA[Iterator results = sess.createQuery(
+ "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+ "group by cat.color")
+ .list()
+ .iterator();
+
+while ( results.hasNext() ) {
+ Object[] row = (Object[]) results.next();
+ Color type = (Color) row[0];
+ Date oldest = (Date) row[1];
+ Integer count = (Integer) row[2];
+ .....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-parameters">
+ <title>Bind parameters</title>
+
+ <para>
+ Methods on <literal>Query</literal> are provided for
binding values to
+ named parameters or JDBC-style <literal>?</literal>
parameters.
+ <emphasis>Contrary to JDBC, Hibernate numbers parameters from
zero.</emphasis>
+ Named parameters are identifiers of the form
<literal>:name</literal> in
+ the query string. The advantages of named parameters are:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ named parameters are insensitive to the order they occur in
the
+ query string
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ they may occur multiple times in the same query
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ they are self-documenting
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in
(:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-pagination">
+ <title>Pagination</title>
+
+ <para>
+ If you need to specify bounds upon your result set (the maximum
number of rows
+ you want to retrieve and / or the first row you want to retrieve) you
should
+ use methods of the <literal>Query</literal> interface:
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("from
DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Hibernate knows how to translate this limit query into the native
+ SQL of your DBMS.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scrolling">
+ <title>Scrollable iteration</title>
+
+ <para>
+ If your JDBC driver supports scrollable
<literal>ResultSet</literal>s, the
+ <literal>Query</literal> interface may be used to obtain
a
+ <literal>ScrollableResults</literal> object, which allows
flexible
+ navigation of the query results.
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("select
cat.name, cat from DomesticCat cat " +
+ "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+ // find the first name on each page of an alphabetical list of cats by name
+ firstNamesOfPages = new ArrayList();
+ do {
+ String name = cats.getString(0);
+ firstNamesOfPages.add(name);
+ }
+ while ( cats.scroll(PAGE_SIZE) );
+
+ // Now get the first page of cats
+ pageOfCats = new ArrayList();
+ cats.beforeFirst();
+ int i=0;
+ while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1)
);
+
+}
+cats.close()]]></programlisting>
+
+ <para>
+ Note that an open database connection (and cursor) is required for
this
+ functionality, use
<literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+ if you need offline pagination functionality.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-named"
revision="1">
+ <title>Externalizing named queries</title>
+
+ <para>
+ You may also define named queries in the mapping document. (Remember
to use a
+ <literal>CDATA</literal> section if your query contains
characters that could
+ be interpreted as markup.)
+ </para>
+
+ <programlisting><![CDATA[<query
name="ByNameAndMaximumWeight"><![CDATA[
+ from eg.DomesticCat as cat
+ where cat.name = ?
+ and cat.weight > ?
+] ]></query>]]></programlisting>
+
+ <para>
+ Parameter binding and executing is done programatically:
+ </para>
+
+ <programlisting><![CDATA[Query q =
sess.getNamedQuery("ByNameAndMaximumWeight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Note that the actual program code is independent of the query
language that
+ is used, you may also define native SQL queries in metadata, or
migrate
+ existing queries to Hibernate by placing them in mapping files.
+ </para>
+
+ <para>
+ Also note that a query declaration inside a
<literal><hibernate-mapping></literal>
+ element requires a global unique name for the query, while a query
declaration inside a
+ <literal><class></literal> element is made
unique automatically by prepending the
+ fully qualified name of the class, for example
+ <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
+ </para>
+
+ </sect3>
+
+ </sect2>
+
+ <sect2 id="objectstate-filtering" revision="1">
+ <title>Filtering collections</title>
+ <para>
+ A collection <emphasis>filter</emphasis> is a special type of
query that may be applied to
+ a persistent collection or array. The query string may refer to
<literal>this</literal>,
+ meaning the current collection element.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittens =
session.createFilter(
+ pk.getKittens(),
+ "where this.color = ?")
+ .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+ .list()
+);]]></programlisting>
+
+ <para>
+ The returned collection is considered a bag, and it's a copy of the
given
+ collection. The original collection is not modified (this is contrary to
+ the implication of the name "filter", but consistent with
expected behavior).
+ </para>
+
+ <para>
+ Observe that filters do not require a <literal>from</literal>
clause (though they may have
+ one if required). Filters are not limited to returning the collection
elements themselves.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittenMates =
session.createFilter(
+ pk.getKittens(),
+ "select this.mate where this.color = eg.Color.BLACK.intValue")
+ .list();]]></programlisting>
+
+ <para>
+ Even an empty filter query is useful, e.g. to load a subset of elements
in a
+ huge collection:
+ </para>
+
+ <programlisting><![CDATA[Collection tenKittens =
session.createFilter(
+ mother.getKittens(), "")
+ .setFirstResult(0).setMaxResults(10)
+ .list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="objecstate-querying-criteria" revision="1">
+ <title>Criteria queries</title>
+
+ <para>
+ HQL is extremely powerful but some developers prefer to build queries
dynamically,
+ using an object-oriented API, rather than building query strings.
Hibernate provides
+ an intuitive <literal>Criteria</literal> query API for these
cases:
+ </para>
+
+ <programlisting><![CDATA[Criteria crit =
session.createCriteria(Cat.class);
+crit.add( Restrictions.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+
+ <para>
+ The <literal>Criteria</literal> and the associated
<literal>Example</literal>
+ API are discussed in more detail in <xref
linkend="querycriteria"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="objectstate-querying-nativesql"
revision="2">
+ <title>Queries in native SQL</title>
+
+ <para>
+ You may express a query in SQL, using
<literal>createSQLQuery()</literal> and
+ let Hibernate take care of the mapping from result sets to objects. Note
+ that you may at any time call
<literal>session.connection()</literal> and
+ use the JDBC <literal>Connection</literal> directly. If you
chose to use the
+ Hibernate API, you must enclose SQL aliases in braces:
+ </para>
+
+ <programlisting><![CDATA[List cats =
session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
+ .addEntity("cat", Cat.class)
+.list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = session.createSQLQuery(
+ "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+ "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+ "FROM CAT {cat} WHERE ROWNUM<10")
+ .addEntity("cat", Cat.class)
+.list()]]></programlisting>
+
+ <para>
+ SQL queries may contain named and positional parameters, just like
Hibernate queries.
+ More information about native SQL queries in Hibernate can be found in
+ <xref linkend="querysql"/>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="objectstate-modifying" revision="1">
+ <title>Modifying persistent objects</title>
+
+ <para>
+ <emphasis>Transactional persistent instances</emphasis> (ie.
objects loaded, saved, created or
+ queried by the <literal>Session</literal>) may be manipulated by
the application
+ and any changes to persistent state will be persisted when the
<literal>Session</literal>
+ is <emphasis>flushed</emphasis> (discussed later in this
chapter). There is no need
+ to call a particular method (like <literal>update()</literal>,
which has a different
+ purpose) to make your modifications persistent. So the most straightforward
way to update
+ the state of an object is to <literal>load()</literal> it,
+ and then manipulate it directly, while the
<literal>Session</literal> is open:
+ </para>
+
+ <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load(
Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush(); // changes to cat are automatically detected and
persisted]]></programlisting>
+
+ <para>
+ Sometimes this programming model is inefficient since it would require both
an SQL
+ <literal>SELECT</literal> (to load an object) and an SQL
<literal>UPDATE</literal>
+ (to persist its updated state) in the same session. Therefore Hibernate
offers an
+ alternate approach, using detached instances.
+ </para>
+
+ <para>
+ <emphasis>Note that Hibernate does not offer its own API for direct
execution of
+ <literal>UPDATE</literal> or
<literal>DELETE</literal> statements. Hibernate is a
+ <emphasis>state management</emphasis> service, you don't have
to think in
+ <emphasis>statements</emphasis> to use it. JDBC is a perfect API
for executing
+ SQL statements, you can get a JDBC <literal>Connection</literal>
at any time
+ by calling <literal>session.connection()</literal>. Furthermore,
the notion
+ of mass operations conflicts with object/relational mapping for online
+ transaction processing-oriented applications. Future versions of Hibernate
+ may however provide special mass operation functions. See <xref
linkend="batch"/>
+ for some possible batch operation tricks.</emphasis>
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-detached" revision="2">
+ <title>Modifying detached objects</title>
+
+ <para>
+ Many applications need to retrieve an object in one transaction, send it to
the
+ UI layer for manipulation, then save the changes in a new transaction.
+ Applications that use this kind of approach in a high-concurrency
environment
+ usually use versioned data to ensure isolation for the "long" unit
of work.
+ </para>
+
+ <para>
+ Hibernate supports this model by providing for reattachment of detached
instances
+ using the <literal>Session.update()</literal> or
<literal>Session.merge()</literal>
+ methods:
+ </para>
+
+ <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat); // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+ <para>
+ If the <literal>Cat</literal> with identifier
<literal>catId</literal> had already
+ been loaded by <literal>secondSession</literal> when the
application tried to
+ reattach it, an exception would have been thrown.
+ </para>
+
+ <para>
+ Use <literal>update()</literal> if you are sure that the session
does
+ not contain an already persistent instance with the same identifier, and
+ <literal>merge()</literal> if you want to merge your
modifications at any time
+ without consideration of the state of the session. In other words,
<literal>update()</literal>
+ is usually the first method you would call in a fresh session, ensuring that
+ reattachment of your detached instances is the first operation that is
executed.
+ </para>
+
+ <para>
+ The application should individually <literal>update()</literal>
detached instances
+ reachable from the given detached instance if and
<emphasis>only</emphasis> if it wants
+ their state also updated. This can be automated of course, using
<emphasis>transitive
+ persistence</emphasis>, see <xref
linkend="objectstate-transitive"/>.
+ </para>
+
+ <para>
+ The <literal>lock()</literal> method also allows an application
to reassociate
+ an object with a new session. However, the detached instance has to be
unmodified!
+ </para>
+
+ <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Note that <literal>lock()</literal> can be used with various
+ <literal>LockMode</literal>s, see the API documentation and the
+ chapter on transaction handling for more information. Reattachment is not
+ the only usecase for <literal>lock()</literal>.
+ </para>
+
+ <para>
+ Other models for long units of work are discussed in <xref
linkend="transactions-optimistic"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-saveorupdate">
+ <title>Automatic state detection</title>
+
+ <para>
+ Hibernate users have requested a general purpose method that either saves a
+ transient instance by generating a new identifier or updates/reattaches
+ the detached instances associated with its current identifier.
+ The <literal>saveOrUpdate()</literal> method implements this
functionality.
+ </para>
+
+ <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate); // save the new instance (mate has a null
id)]]></programlisting>
+
+ <para>
+ The usage and semantics of <literal>saveOrUpdate()</literal>
seems to be confusing
+ for new users. Firstly, so long as you are not trying to use instances from
one session
+ in another new session, you should not need to use
<literal>update()</literal>,
+ <literal>saveOrUpdate()</literal>, or
<literal>merge()</literal>. Some whole
+ applications will never use either of these methods.
+ </para>
+
+ <para>
+ Usually <literal>update()</literal> or
<literal>saveOrUpdate()</literal> are used in
+ the following scenario:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ the application loads an object in the first session
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the object is passed up to the UI tier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ some modifications are made to the object
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the object is passed back down to the business logic tier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the application persists these modifications by calling
+ <literal>update()</literal> in a second session
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>saveOrUpdate()</literal> does the following:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ if the object is already persistent in this session, do nothing
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if another object associated with the session has the same
identifier,
+ throw an exception
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if the object has no identifier property,
<literal>save()</literal> it
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if the object's identifier has the value assigned to a newly
instantiated
+ object, <literal>save()</literal> it
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if the object is versioned (by a
<literal><version></literal> or
+ <literal><timestamp></literal>), and the
version property value
+ is the same value assigned to a newly instantiated object,
+ <literal>save()</literal> it
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ otherwise <literal>update()</literal> the object
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ and <literal>merge()</literal> is very different:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ if there is a persistent instance with the same identifier currently
+ associated with the session, copy the state of the given object onto
+ the persistent instance
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ if there is no persistent instance currently associated with the
session,
+ try to load it from the database, or create a new persistent
instance
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the persistent instance is returned
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ the given instance does not become associated with the session, it
+ remains detached
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1 id="objectstate-deleting" revision="1">
+ <title>Deleting persistent objects</title>
+
+ <para>
+ <literal>Session.delete()</literal> will remove an object's
state from the database.
+ Of course, your application might still hold a reference to a deleted
object.
+ It's best to think of <literal>delete()</literal> as making a
persistent instance
+ transient.
+ </para>
+
+ <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+ <para>
+ You may delete objects in any order you like, without risk of foreign key
+ constraint violations. It is still possible to violate a <literal>NOT
+ NULL</literal> constraint on a foreign key column by deleting objects
in
+ the wrong order, e.g. if you delete the parent, but forget to delete the
+ children.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-replicating" revision="1">
+ <title>Replicating object between two different datastores</title>
+
+ <para>
+ It is occasionally useful to be able to take a graph of persistent instances
+ and make them persistent in a different datastore, without regenerating
identifier
+ values.
+ </para>
+
+ <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+ <para>
+ The <literal>ReplicationMode</literal> determines how
<literal>replicate()</literal>
+ will deal with conflicts with existing rows in the database.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ReplicationMode.IGNORE</literal> - ignore the
object when there is
+ an existing database row with the same identifier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.OVERWRITE</literal> - overwrite
any existing database
+ row with the same identifier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.EXCEPTION</literal> - throw an
exception if there is
+ an existing database row with the same identifier
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.LATEST_VERSION</literal> -
overwrite the row if its
+ version number is earlier than the version number of the object, or
ignore
+ the object otherwise
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Usecases for this feature include reconciling data entered into different
database
+ instances, upgrading system configuration information during product
upgrades,
+ rolling back changes made during non-ACID transactions and more.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-flushing">
+ <title>Flushing the Session</title>
+
+ <para>
+ From time to time the <literal>Session</literal> will execute the
SQL statements
+ needed to synchronize the JDBC connection's state with the state of
objects held in
+ memory. This process, <emphasis>flush</emphasis>, occurs by
default at the following
+ points
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ before some query executions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ from
<literal>org.hibernate.Transaction.commit()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ from <literal>Session.flush()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The SQL statements are issued in the following order
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ all entity insertions, in the same order the corresponding objects
+ were saved using <literal>Session.save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all entity updates
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all collection deletions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all collection element deletions, updates and insertions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all collection insertions
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ all entity deletions, in the same order the corresponding objects
+ were deleted using <literal>Session.delete()</literal>
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ (An exception is that objects using <literal>native</literal> ID
generation are
+ inserted when they are saved.)
+ </para>
+
+ <para>
+ Except when you explicity <literal>flush()</literal>, there are
absolutely no
+ guarantees about <emphasis>when</emphasis> the
<literal>Session</literal> executes
+ the JDBC calls, only the <emphasis>order</emphasis> in which they
are executed.
+ However, Hibernate does guarantee that the
<literal>Query.list(..)</literal>
+ will never return stale data; nor will they return the wrong data.
+ </para>
+
+ <para>
+ It is possible to change the default behavior so that flush occurs less
frequently.
+ The <literal>FlushMode</literal> class defines three different
modes: only flush
+ at commit time (and only when the Hibernate
<literal>Transaction</literal> API
+ is used), flush automatically using the explained routine, or never flush
unless
+ <literal>flush()</literal> is called explicitly. The last mode is
useful for long running
+ units of work, where a <literal>Session</literal> is kept open
and disconnected for
+ a long time (see <xref
linkend="transactions-optimistic-longsession"/>).
+ </para>
+
+ <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs
+sess.close();]]></programlisting>
+
+ <para>
+ During flush, an exception might occur (e.g. if a DML operation violates a
constraint).
+ Since handling exceptions involves some understanding of Hibernate's
transactional
+ behavior, we discuss it in <xref linkend="transactions"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-transitive" revision="1">
+ <title>Transitive persistence</title>
+
+ <para>
+ It is quite cumbersome to save, delete, or reattach individual objects,
+ especially if you deal with a graph of associated objects. A common case is
+ a parent/child relationship. Consider the following example:
+ </para>
+
+ <para>
+ If the children in a parent/child relationship would be value typed (e.g. a
collection
+ of addresses or strings), their life cycle would depend on the parent and no
+ further action would be required for convenient "cascading" of
state changes.
+ When the parent is saved, the value-typed child objects are saved as
+ well, when the parent is deleted, the children will be deleted, etc. This
+ even works for operations such as the removal of a child from the
collection;
+ Hibernate will detect this and, since value-typed objects can't have
shared
+ references, delete the child from the database.
+ </para>
+
+ <para>
+ Now consider the same scenario with parent and child objects being entities,
+ not value-types (e.g. categories and items, or parent and child cats).
Entities
+ have their own life cycle, support shared references (so removing an entity
from
+ the collection does not mean it can be deleted), and there is by default no
+ cascading of state from one entity to any other associated entities.
Hibernate
+ does not implement <emphasis>persistence by
reachability</emphasis> by default.
+ </para>
+
+ <para>
+ For each basic operation of the Hibernate session - including
<literal>persist(), merge(),
+ saveOrUpdate(), delete(), lock(), refresh(), evict(),
replicate()</literal> - there is a
+ corresponding cascade style. Respectively, the cascade styles are named
<literal>create,
+ merge, save-update, delete, lock, refresh, evict, replicate</literal>.
If you want an
+ operation to be cascaded along an association, you must indicate that in the
mapping
+ document. For example:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person"
cascade="persist"/>]]></programlisting>
+
+ <para>
+ Cascade styles my be combined:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person"
cascade="persist,delete,lock"/>]]></programlisting>
+
+ <para>
+ You may even use <literal>cascade="all"</literal> to
specify that <emphasis>all</emphasis>
+ operations should be cascaded along the association. The default
<literal>cascade="none"</literal>
+ specifies that no operations are to be cascaded.
+ </para>
+
+ <para>
+ A special cascade style, <literal>delete-orphan</literal>,
applies only to one-to-many
+ associations, and indicates that the <literal>delete()</literal>
operation should
+ be applied to any child object that is removed from the association.
+ </para>
+
+
+ <para>
+ Recommendations:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ It doesn't usually make sense to enable cascade on a
<literal><many-to-one></literal>
+ or <literal><many-to-many></literal>
association. Cascade is often useful for
+ <literal><one-to-one></literal> and
<literal><one-to-many></literal>
+ associations.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the child object's lifespan is bounded by the lifespan of the
parent
+ object, make it a <emphasis>life cycle object</emphasis>
by specifying
+
<literal>cascade="all,delete-orphan"</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Otherwise, you might not need cascade at all. But if you think that
you will often be
+ working with the parent and children together in the same
transaction, and you want to save
+ yourself some typing, consider using
<literal>cascade="persist,merge,save-update"</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Mapping an association (either a single valued association, or a collection)
with
+ <literal>cascade="all"</literal> marks the association
as a
+ <emphasis>parent/child</emphasis> style relationship where
save/update/delete of the
+ parent results in save/update/delete of the child or children.
+ </para>
+ <para>
+ Futhermore, a mere reference to a child from a persistent parent will result
in
+ save/update of the child. This metaphor is incomplete, however. A child which
becomes
+ unreferenced by its parent is <emphasis>not</emphasis>
automatically deleted, except
+ in the case of a <literal><one-to-many></literal>
association mapped with
+ <literal>cascade="delete-orphan"</literal>. The precise
semantics of cascading
+ operations for a parent/child relationship are as follows:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ If a parent is passed to <literal>persist()</literal>,
all children are passed to
+ <literal>persist()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent is passed to <literal>merge()</literal>, all
children are passed to
+ <literal>merge()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent is passed to <literal>save()</literal>,
<literal>update()</literal> or
+ <literal>saveOrUpdate()</literal>, all children are
passed to <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a transient or detached child becomes referenced by a persistent
parent,
+ it is passed to <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a parent is deleted, all children are passed to
<literal>delete()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If a child is dereferenced by a persistent parent,
<emphasis>nothing
+ special happens</emphasis> - the application should explicitly
delete
+ the child if necessary - unless
<literal>cascade="delete-orphan"</literal>,
+ in which case the "orphaned" child is deleted.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Finally, note that cascading of operations can be applied to an object graph
at
+ <emphasis>call time</emphasis> or at <emphasis>flush
time</emphasis>. All operations,
+ if enabled, are cascaded to associated entities reachable when the operation
is
+ executed. However, <literal>save-upate</literal> and
<literal>delete-orphan</literal>
+ are transitive for all associated entities reachable during flush of the
+ <literal>Session</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-metadata">
+ <title>Usando metadados</title>
+
+ <para>
+ O Hibernate requer um modelo muito rico a nível de metadados de todas as
entidades e tipos de
+ valores. De tempos em tempos, este modelo é muito útil à própria aplicação.
Por exemplo, a
+ aplicação pode usar o metadados do Hibernate que executa um algoritmo
"inteligente" que
+ compreende quais objetos podem ser copiados (por exemplo, tipos de valores
mutáveis) ou
+ não (por exemplo, tipos de valores imutáveis e, possivelmente, entidades
associadas).
+ </para>
+ <para>
+ O Hibernate expõe o metadados via interfaces
<literal>ClassMetadata</literal>
+ e <literal>CollectionMetadata</literal> e pela hierarquia
<literal>Type</literal>.
+ Instâncias das interfaces de metadados podem ser obtidas a partir do
+ <literal>SessionFactory</literal>.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType()
) {
+ namedValues.put( propertyNames[i], propertyValues[i] );
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Modified:
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/toolset_guide.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/toolset_guide.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/toolset_guide.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="toolsetguide" revision="2">
+<chapter id="toolsetguide" revision="2">
<title>Toolset Guide</title>
<para>
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/transactions.xml
===================================================================
---
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/transactions.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++
core/trunk/documentation/manual/pt-BR/src/main/docbook/content/transactions.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,1150 +1,1148 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="transactions" revision="2">
- <title>Transações e Concorrência</title>
-
- <para>
- O ponto o mais importante sobre o Hibernate e o controle de concorrência é que é
muito
- fácil de ser compreendido. O Hibernate usa diretamente conexões de JDBC e
recursos de
- JTA sem adicionar nenhum comportamento de bloqueio a mais. Nós altamente
recomendamos
- que você gaste algum tempo com o JDBC, o ANSI e a especificação de isolamento de
transação
- de seu sistema de gerência da base de dados.
- </para>
-
- <para>
- O Hibernate não bloqueia objetos na memória. Sua aplicação pode esperar o
comportamento
- tal qual definido pelo nível de isolamento de suas transações de banco de dados.
- Note que graças ao <literal>Session</literal>, que também é um cache
de escopo de
- transação, o Hibernate fornece leituras repetíveis para procurar por
identificadores
- e consultas de entidade (não pesquisas de relatórios que retornam valores
escalares).
- </para>
-
- <para>
- Além do versionamento para o controle automático de concorrência otimista, o
Hibernate
- oferece também uma API (menor) para bloqueio pessimista de linhas usando a
sintaxe
- <literal>SELECT FOR UPDATE</literal>. O controle de concorrência
otimista e esta
- API são discutidos mais tarde neste capítulo.
- </para>
-
- <para>
- Nós começamos a discussão do controle de concorrência no Hibernate com a
granularidade
- do <literal>Configuration</literal>,
<literal>SessionFactory</literal>, e
- <literal>Session</literal>, além de transações de base de dados e
conversações longas.
- </para>
-
- <sect1 id="transactions-basics" revision="1">
- <title>Session e escopos de transações</title>
-
- <para>
- Um <literal>SessionFactory</literal> é objeto threadsafe
compartilhado por
- todas as threads da aplicação que consome muitos recursos na sua criação.
- É criado uma unica vez no inicio da execução da aplicação a partir da
- instância de uma <literal>Configuration</literal>.
- </para>
-
- <para>
- Uma <literal>Session</literal> é um objeto de baixo custo de
criação, não é threadsafe,
- deve ser usado uma vez, para uma única requisição, uma conversação, uma única
unidade
- do trabalho e então deve ser descartado. Um
<literal>Session</literal> não obterá um
- JDBC <literal>Connection</literal> (ou um
<literal>Datasource</literal>) a menos que
- necessite, conseqüentemente não consome nenhum recurso até ser usado.
- </para>
-
- <para>
- Para completar, você também tem que pensar sobre as transações de base de
dados.
- Uma transação tem que ser tão curta quanto possível, para reduzir a disputa
pelo
- bloqueio na base de dados. Transações longas impedirão que sua aplicação
escale a
- carga altamente concorrente. Por isso, em um projeto raramente é para manter
- uma transação de base de dados aberta durante o tempo que o usuário pensa,
- até que a unidade do trabalho esteja completa.
- </para>
-
- <para>
- Qual é o escopo de uma unidade de trabalho? Pode uma únicoa
<literal>Session</literal>
- do Hibernate gerenciar diversas transações ou é esta um o relacionamento
um-para-um dos
- escopos? Quando deve você abrir e fechar uma
<literal>Session</literal> e como você
- demarca os limites da transação?
- </para>
-
- <sect2 id="transactions-basics-uow" revision="1">
- <title>Unidade de trabalho</title>
-
- <para>
- Primeiro, não use o antipattern
<emphasis>sessão-por-operação</emphasis>,
- isto é, não abra e não feche uma <literal>Session</literal>
para cada simples chamada
- ao banco de de dados em uma única thread! Naturalmente, o mesmo é
verdadeiro para
- transações. As chamadas a banco de dados em uma aplicação são feitas
usando uma
- seqüência planejada, elas são agrupadas em unidades de trabalho atômicas.
- (Veja que isso também significa que um auto-commit depois de cada
sentença SQL é
- inútil em uma aplicação, esta modalidade é ideal para o trabalho ad hoc
do console
- do SQL. O Hibernate impede, ou espera que o servidor de aplicação impessa
isso,
- o uso da modalidade de auto-commit.) As transações nunca são opcionais,
toda a
- comunicação com um banco de dados tem que ocorrer dentro de uma
transação, não
- importa se você vai ler ou escrever dados. Como explicado, o
comportamento auto-commit
- para leitura de dados deve ser evitado, como muitas transações pequenas
são
- improváveis de executar melhor do que uma unidade claramente definida do
trabalho. A
- última opção também muito mais manutenível e extensível.
- </para>
-
- <para>
- O pattern mais comum em uma aplicação multi-usuário cliente/servidor é
- <emphasis>sessão-por-requisição</emphasis>. Neste modelo, uma
requisição do cliente é
- enviada ao servidor (onde a camada de persistência do Hibernate roda),
uma
- <literal>Session</literal> nova do Hibernate é aberta, e
todas as operações da base de
- dados são executadas nesta unidade do trabalho. Logo que o trabalho for
completado
- (e a resposta para o cliente for preparada), a sessão é descarregad e
fechada.
- Você usaria também uma única transação de base de dados para servir às
requisições
- dos clientes, começando e commitando-o quando você abre e fecha a
<literal>Session</literal>.
- O relacionamento entre os dois é um-para-um e este modelo é um ajuste
perfeito para muitas
- aplicações.
- </para>
-
- <para>
- O desafio encontra-se na implementação. O Hibernate fornece gerência
integrada da "sessão atual"
- para simplificar este pattern. Tudo que você tem que fazer é iniciar uma
transação quando uma
- requisição tem que ser processada e termina a transação antes que a
resposta seja enviada ao
- cliente. Você pode fazer onde quiser, soluções comuns são
<literal>ServletFilter</literal>,
- interceptador AOP com um pointcut (ponto de corte) nos métodos de serviço
ou em um
- container de proxy/interceptação. Um container de EJB é uma maneira
padronizada para
- implementar aspectos cross-cutting tais como a demarcação da transação em
EJB session beans,
- declarativamente com CMT. Se você se decidir usar demarcação programática
de transação,
- de preferencia a API <literal>Transaction</literal> do
Hibernate mostrada mais adiante neste
- capítulo, para fácilidade no uso e portabilidade de código.
- </para>
-
- <para>
- Seu código de aplicação pode acessar a "sessão atual" para
processar a requisição
- fazendo uma chamada simples a
<literal>sessionFactory.getCurrentSession()</literal> em
- qualquer lugar e com a frequencia necessária. Você sempre conseguirá uma
- <literal>Session</literal> limitada a transação atual. Isto
tem que ser configurado
- para recurso local ou os ambientes JTA. Veja <xref
linkend="architecture-current-session"/>.
- </para>
-
- <para>
- Às vezes é conveniente estender o escopo de uma
<literal>Session</literal> e de
- uma transação do banco de dados até que a "visão esteja
renderizada". É especialmente
- útil em aplicações servlet que utilizam uma fase de rendenderização
separada depois
- que a requisição ter sido processada. Estendendo a transação até que
renderização da
- visão esteja completa é fácil de fazer se você implementar seu próprio
interceptador.
- Entretanto, não se pode fazer facilmente se você confiar em EJBs com
transações
- gerenciadas por contêiner, porque uma transação será terminada quando um
método de
- EJB retornar, antes da renderização de toda visão puder começar.
- Veja o website e o fórum do Hibernate para dicas e exemplos em torno
deste
- pattern <emphasis>Open Session in View</emphasis>.
-
- </para>
-
- </sect2>
-
- <sect2 id="transactions-basics-apptx" revision="1">
- <title>Longas conversações</title>
-
- <para>
- O pattern sessão-por-requisição não é o único conceito útil que você pode
usar ao projetar
- unidades de trabalho. Muitos processos de negócio requerem uma totalidade
de séries de
- interações com o usuário intercaladas com acessos a uma base de dados. Em
aplicações web
- e corporativas não é aceitável para uma transação atrapalhe uma interação
do usuário.
- Considere o seguinte exemplo:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- A primeira tela de um diálogo abre os dados carregado pelo
usuário em através de
- <literal>Session</literal> e transação particulares.
O usuário está livre
- modificar os objetos.
- </para>
- </listitem>
- <listitem>
- <para>
- O usuário clica em "Salvar" após 5 minutos e espera
suas modificações serem persistidas;
- espera também que ele era a única pessoa que edita esta
informação e que nenhuma
- modificação conflitante possa ocorrer.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Nós chamamos esta unidade de trabalho, do ponto da visão do usuário,
executando uma
- longa <emphasis>conversação</emphasis> (ou
<emphasis>transação da aplicação</emphasis>).
- Há muitas maneiras de você pode implementar em sua aplicação.
-
- </para>
-
- <para>
- Uma primeira implementação simples pode manter
a<literal>Session</literal> e a transação
- aberta durante o tempo de interação do usuário, com bloqueios na base de
dados para impedir
- a modificação concorrente e para garantir o isolamento e a atomicidade.
Esse é naturalmente
- um anti-pattern, desde que a disputa do bloqueio não permitiria o
escalonameneto da
- aplicação com o número de usuários concorrentes.
- </para>
-
- <para>
- Claramente, nós temos que usar diversas transações para implementar a
conversação.
- Neste caso, Manter o isolamento dos processos de negócio torna-se
responsabilidade
- parcial da camada da aplicação. Uma única conversação geralmente usa
diversas transações.
- Ela será atômica se somente uma destas transações (a última) armazenar
os
- dados atualizados, todas as outras simplesmente leram os dados (por
exemplo em um
- diálogo do estilo wizard que mede diversos ciclos de
requisição/resposta). Isto é mais
- fácil de implementar do que pode parecer, especialmente se você usar as
- características do Hibernate:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>Versionamento automático</emphasis> - O
Hibernate pode fazer o
- controle automático de concorrência otimista para você, ele pode
- automaticamente detectar se uma modificação concorrente
- ocorreu durante o tempo de interação do usuário. Geralmente nós
verificamos
- somente no fim da conversação.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Detached Objects</emphasis>- se você se
decidir usar o já discutido
- pattern <emphasis>session-per-request</emphasis>,
todas as instâncias carregadas
- estarão no estado destacado durante o tempo em que o usuário
estiver pensando.
- O Hibernate permite que você reatache os objetos e persita as
modificações,
- esse pattern é chamado
-
<emphasis>session-per-request-with-detached-objects</emphasis>.
- É usado versionamento automatico para isolar as modificações
concorrentes.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>Extended (or Long) Session</emphasis> A
<literal>Session</literal>
- do Hibernate pode ser desligada da conexão básica do JDBC depois
que a
- transação foi commitada e ser reconectado quando uma nova
requisição do
- cliente ocorrer. Este pattern é conhecido como
- <emphasis>session-per-conversation</emphasis> e faz o
reatamento uniforme
- desnecessário. Versionamento automático é usado para isolar
modificações
- concorrentes e a
<emphasis>session-per-conversation</emphasis> usualmente
- não é permitido para ser nivelado automaticamente, e sim
explicitamente.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Ambos
<emphasis>session-per-request-with-detached-objects</emphasis> e
- <emphasis>session-per-conversation</emphasis> possuem
vantagens e desvantagens,
- nos discutiremos mais tarde neste capítulo no contexto do controle de
- concorrência otimista.
- </para>
-
- </sect2>
-
- <sect2 id="transactions-basics-identity">
- <title>Considerando a identidade do objeto</title>
-
- <para>
- Uma aplicação pode acessar concorrentemente o mesmo estado persistente em
duas
- <literal>Session</literal>s diferentes. Entretanto, uma
instância de uma classe
- persistente nunca é compartilhada entre duas instâncias
<literal>Session</literal>.
- Por tanto, há duas noções diferentes da identidade:
- </para>
-
- <variablelist spacing="compact">
- <varlistentry>
- <term>Identidade da base de dados</term>
- <listitem>
- <para>
- <literal>foo.getId().equals( bar.getId()
)</literal>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Identidade da JVM</term>
- <listitem>
- <para>
- <literal>foo==bar</literal>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>
- Então para os objetos acoplados a um
<literal>Session</literal> em <literal>particular </literal>
- (isto é no escopo de um <literal>Session</literal>), as duas
noções são equivalentes e a
- identidade da JVM para a identidade da base de dados é garantida pelo
Hibernate. Entretanto,
- quando a aplicação pode acessar concorrentemente o "mesmo"
objeto do negócio (identidade
- persistente) em duas sessões diferentes, as duas instâncias serão
realmente "diferentes"
- (identidade de JVM). Os conflitos são resolvidos usando (versionamento
automático) no
- flush/commit, usando abordagem otimista.
-
- </para>
-
- <para>
- Este caminho deixa o Hibernate e o banco dedados se preocuparem com a
concorrência; também
- fornece uma escalabilidade melhor, garantindo que a identidade em
unidades de trabalho
- único-encadeadas não necessite de bloqueio dispendioso ou de outros meios
de sincronização.
- A aplicação nunca necessita sincronizar qualquer objeto de negócio tão
longo que transpasse
- uma única thread por <literal>Session</literal>. Dentro de
uma <literal>Session</literal> a
- aplicação pode usar com segurança o <literal>==</literal>
para comparar objetos.
- </para>
-
- <para>
- Com tudo, uma aplicação que usa <literal>==</literal> fora de
uma <literal>Session</literal>,
- pode ver resultados inesperados. Isto pode ocorrer mesmo em alguns
lugares inesperados, por
- exemplo, se você colocar duas instâncias desacopladas em um mesmo
<literal>Set</literal>.
- Ambos podem ter a mesma identidade na base de dados (isto é eles
representam a mesma linha
- em uma tabela), mas a identidade da JVM pela definição não garantida para
instâncias em estado
- desacoplado. O desenvolvedor tem que sobrescrever os métodos
<literal>equals()</literal> e
- <literal>hashCode()</literal> em classes persistentes e
implementar sua própria noção da
- igualdade do objeto. Advertência: nunca use o identificador da base de
dados para implementar
- a igualdade, use atributos de negócio, uma combinação única, geralmente
imutável. O
- identificador da base de dados mudará se um objeto transiente passar para
o estado persistente.
- Se a instância transiente (geralmente junto com instâncias desacopladas)
for inserida em um
- <literal>Set</literal>, mudar o hashcode quebra o contrato do
<literal>Set</literal>.
- Atributos para chaves de negócio não têm que ser tão estável quanto às
chaves primárias
- da base de dados, você somente tem que garantir a estabilidade durante o
tempo que
- os objetos estiverem no mesmo Set. Veja o website do Hibernate para uma
discussão mais
- completa sobre o assunto. Note também que esta não é uma caracteristica
do Hibernate,
- mas simplesmente como a identidade e a igualdade do objeto de Java têm
que ser implementadas.
- </para>
-
- </sect2>
-
- <sect2 id="transactions-basics-issues">
- <title>Edições comuns</title>
-
- <para>
- Nunca use o anti-patterns
<emphasis>session-per-user-session</emphasis> ou
- <emphasis>session-per-application</emphasis> (naturalmente,
há umas exceções raras a
- essa regra). Note que algumas das seguintes edições podem também
aparecer com patterns
- recomendados, certifique-se que tenha compreendido as implicações antes
de fazer
- uma decisão de projeto:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- Uma <literal>Session</literal> não é threadsafe. As
coisas que são supostas para trabalhar
- concorrentemente, como requisições HTTP, session beans, ou Swing,
causarão condições de
- disputa se uma instância <literal>Session</literal>
for compartilhada. Se você mantiver
- sua <literal>Session</literal> do Hibernate em seu
<literal>HttpSession</literal>
- (discutido mais tarde), você deve considerar sincronizar o acesso
a sua sessão do HTTP.
- Caso contrário, um usuário que clica em reload várias muito
rapidamente pode usar o
- mesmo <literal>Session</literal> em duas threads
executando concorrentemente.
- </para>
- </listitem>
- <listitem>
- <para>
- Uma exceção lançada pelo Hibernate significa que você tem que dar
rollback na sua
- transação no banco de dados e fechar a
<literal>Session</literal> imediatamente
- (discutido mais tarde em maiores detalhes). Se sua
<literal>Session</literal> é
- limitado pela aplicação, você tem que parar a aplicação. Dando
rollback na
- transação no banco de dados não põe seus objetos do negócio em um
estado anterior
- que estavam no início da transação. Isto significa que o estado
da base de dados
- e os objetos de negócio perdem a sincronização. Geralmente não é
um problema
- porque as exceções não são recuperáveis e você tem que iniciar
após o
- rollback de qualquer maneira.
- </para>
- </listitem>
- <listitem>
- <para>
- O <literal>Session</literal> guarda em cache cada
objeto que está no estado persistente
- (guardado e checado para estado "sujo" pelo Hibernate).
Isto significa que ele cresce
- infinitamente até que você obtenha uma OutOfMemoryException, se
você o mantiver aberto
- por muito tempo ou simplesmente carregar dados demais. Uma
solução é chamar
- <literal>clear()</literal> e
<literal>evict()</literal> para controlar o cache
- da <literal>Session</literal>, mas você deve
considerar uma Store Procedure
- se precisar de operações que envolvam grande volume de dados.
Algumas soluções são
- mostradas no <xref linkend="batch"/>. Manter uma
<literal>Session</literal> aberta
- durante uma sessão do usuário significa também uma probabilidade
elevada de se acabar
- com dados velhos.
- </para>
- </listitem>
- </itemizedlist>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="transactions-demarcation">
- <title>Demarcação de transações de bancos de dados</title>
-
- <para>
- Os limites de uma transação de banco de dados (ou sistema) são sempre
necessários. Nenhuma
- comunicação com o banco de dados pode ocorrer fora de uma transação de banco
de dados (isto
- parece confundir muitos desenvolvedores que estão usados modo auto-commit).
Sempre use os
- limites desobstruídos da transação, até mesmo para operações somente leitura.
Dependendo
- de seu nível de isolamento e capacidade da base de dados isto pode não ser
requerido,
- mas não há nenhum aspecto negativo se você demarca sempre transações
explicitamente.
- Certamente, uma única transação será melhor executada do que muitas
transações pequenas,
- até mesmo para dados de leitura.
- </para>
-
- <para>
- Uma aplicação do Hibernate pode funcionar em ambientes não gerenciados (isto
é aplicações standalone, Web
- simples ou Swing) e ambientes gerenciados J2EE. Em um ambiente não
gerenciado, o Hibernate é geralmente
- responsável pelo seu próprio pool de conexões. O desenvolvedor tem que
manualmente ajustar limites das
- transaçãos, ou seja, começar, commitar, ou dar rollback nas transações ele
mesmo. Um ambiente gerenciado
- fornece transações gerenciadas por contêiner (CMT - container-managed
transactions), com um conjunto
- da transações definido declarativamente em descritores de deployment de EJB
session beans, por exemplo.
- A demarcação programática é então já não é necessário.
- </para>
-
- <para>
- Entretanto, é freqüentemente desejável manter sua camada de persistência
portável entre ambientes
- de recurso locais não gerenciados e sistemas que podem confiar em JTA, mas
usar BMT em vez de CMT.
- Em ambos os casos você usaria demarcação de transação programática. O
Hibernate oferece uma API
- chamada Transaction que traduz dentro do sistema de transação nativa de seu
ambiente de deployment.
- Esta API é realmente opcional, mas nós encorajamos fortemente seu uso a menos
que você estiver
- em um CMT session bean.
- </para>
-
- <para>
- Geralmente, finalizar um <literal>Session</literal>envolve quatro
fases distintas:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- flush da sessão
- </para>
- </listitem>
- <listitem>
- <para>
- commitar a transação
- </para>
- </listitem>
- <listitem>
- <para>
- fechar a sessão
- </para>
- </listitem>
- <listitem>
- <para>
- tratar as exceções
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- A limpeza da sessão já foi bem discutida, agora nós daremos uma olhada na
demarcação da
- transação e na manipulação de exceção em ambientes controlados e não
controlados.
- </para>
-
-
- <sect2 id="transactions-demarcation-nonmanaged"
revision="2">
- <title>Ambiente não gerenciado</title>
-
- <para>
- Se uma camada de persistência do Hibernate roda em um ambiente não
gerenciado, as conexões
- do banco de dados são geralmente tratadas pelos pools de conexões simples
- (isto é, não baseados em DataSource) dos quais o Hibernate obtém as
conexões assim
- que necessita. A maneira de se manipular uma sessão/transação é mais ou
menos assim:
- </para>
-
- <programlisting><![CDATA[// Non-managed environment idiom
-Session sess = factory.openSession();
-Transaction tx = null;
-try {
- tx = sess.beginTransaction();
-
- // do some work
- ...
-
- tx.commit();
-}
-catch (RuntimeException e) {
- if (tx != null) tx.rollback();
- throw e; // or display error message
-}
-finally {
- sess.close();
-}]]></programlisting>
-
- <para>
- Você não pode chamar <literal>flush()</literal> do
<literal>Session()</literal>
- explicitamente - a chamada ao <literal>commit()</literal>
dispara automaticamente
- a sincronização para a sessão (dependendo do <xref
linkend="objectstate-flushing">
- FlushMode</xref>). Uma chamada ao
<literal>close()</literal> marca o fim de uma sessão.
- A principal implicação do <literal>close()</literal> é que a
conexão JDBC será abandonada
- pela sessão. Este código Java é portável e funciona em ambientes não
gerenciado e de JTA.
- </para>
-
- <para>
- Uma solução muito mais flexível é gerência integrada de contexto da
"sessão atual"
- do Hibernate, como descrito anteriormente:
- </para>
-
- <programlisting><![CDATA[// Non-managed environment idiom with
getCurrentSession()
-try {
- factory.getCurrentSession().beginTransaction();
-
- // do some work
- ...
-
- factory.getCurrentSession().getTransaction().commit();
-}
-catch (RuntimeException e) {
- factory.getCurrentSession().getTransaction().rollback();
- throw e; // or display error message
-}]]></programlisting>
-
- <para>
- Você muito provavelmente nunca verá estes fragmentos de código em uma
aplicação
- regular; as exceções fatais (do sistema) devem sempre ser pegas no
"alto".
- Ou seja, o código que executa chamadas do Hibernate (na camada de
persistência)
- e o código que trata <literal>RuntimeException</literal> (e
geralmente pode
- somente limpar acima e na saída) estão em camadas diferentes. O
gerenciamento do
- contexto atual feito pelo Hibernate pode significativamente simplificar
este
- projeto, como tudo que você necessita é do acesso a um
<literal>SessionFactory</literal>.
- A manipulação de exceção é discutida mais tarde neste capítulo.
- </para>
-
- <para>
- Note que você deve selecionar
<literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
- (que é o padrão) e para o segundo exemplo
<literal>"thread"</literal> como seu
- <literal>hibernate.current_session_context_class</literal>.
- </para>
-
- </sect2>
-
- <sect2 id="transactions-demarcation-jta" revision="3">
- <title>Usando JTA</title>
-
- <para>
- Se sua camada de persistência funcionar em um servidor de aplicação (por
exemplo,
- dentro dos EJB session beans), cada conexão do datasource obtida pelo
Hibernate
- automaticamente fará parte da transação global de JTA. Você pode também
instalar uma
- implementação standalone de JTA e usá-la sem EJB. O Hibernate oferece
duas estratégias
- para a integração de JTA.
- </para>
-
- <para>
- Se você usar bean-managed transactions (BMT - transações gerenciadas por
bean) o Hibernate dirá
- ao servidor de aplicação para começar e para terminar uma transação de
BMT se você usar a API
- Transaction. Assim, o código de gerência de transação é idêntico ao
ambiente não gerenciado.
- </para>
-
- <programlisting><![CDATA[// BMT idiom
-Session sess = factory.openSession();
-Transaction tx = null;
-try {
- tx = sess.beginTransaction();
-
- // do some work
- ...
-
- tx.commit();
-}
-catch (RuntimeException e) {
- if (tx != null) tx.rollback();
- throw e; // or display error message
-}
-finally {
- sess.close();
-}]]></programlisting>
-
- <para>
- Se você quiser usar um <literal>Session</literal> limitada
por transação, isto é,
- a funcionalidade do <literal>getCurrentSession()</literal>
para a propagação fácil
- do contexto, você terá que usar diretamente a API JTA
<literal>UserTransaction</literal>:
- </para>
-
- <programlisting><![CDATA[// BMT idiom with getCurrentSession()
-try {
- UserTransaction tx = (UserTransaction)new InitialContext()
- .lookup("java:comp/UserTransaction");
-
- tx.begin();
-
- // Do some work on Session bound to transaction
- factory.getCurrentSession().load(...);
- factory.getCurrentSession().persist(...);
-
- tx.commit();
-}
-catch (RuntimeException e) {
- tx.rollback();
- throw e; // or display error message
-}]]></programlisting>
-
- <para>
- Com CMT, a demarcação da transação é feita em descritores de deployment
do session beans,
- não programaticamente, conseqüentemente, o código é reduzido a:
- </para>
-
- <programlisting><![CDATA[// CMT idiom
- Session sess = factory.getCurrentSession();
-
- // do some work
- ...
-]]></programlisting>
-
- <para>
- Em um CMT/EJB mesmo um rollback acontece automaticamente, desde que uma
exeção <literal>RuntimeException</literal>
- não tratável seja lançada por um método de um session bean que informa ao
contêiner ajustar a
- transação global ao rollback. <emphasis>Isto significa que você não
necessita usar a API
- <literal>Transaction</literal> do Hibernate em tudo com BMT
ou CMT e você obtém a propagação
- automática do Session "atual" limitada à
transação.</emphasis>
- </para>
-
- <para>
- Veja que você deverá escolher
<literal>org.hibernate.transaction.JTATransactionFactory</literal>
- se você usar o JTA diretamente (BMT) e
<literal>org.hibernate.transaction.CMTTransactionFactory</literal>
- em um CMT session bean, quando você configura a fábrica de transação do
Hibernate. Lembre-se também de
- configurar o
<literal>hibernate.transaction.manager_lookup_class</literal>. Além disso,
certifique-se
- que seu
<literal>hibernate.current_session_context_class</literal> ou não é
configurado (compatibilidade
- com o legado) ou é definido para
<literal>"jta"</literal>.
-
- </para>
-
- <para>
- A operação <literal>getCurrentSession()</literal> tem um
aspecto negativo em um ambiente JTA.
- Há uma advertência para o uso do método liberado de conexão
<literal>after_statement</literal>,
- o qual é usado então por padrão. Devido a uma limitação simples da
especificação JTA, não é
- possível para o Hibernate automaticamente limpar quaisquer instâncias
<literal>ScrollableResults</literal>
- ou <literal>Iterator</literal> abertas retornadas pelo
<literal>scroll()</literal> ou
- <literal>iterate()</literal>. Você
<emphasis>deve</emphasis> liberar o cursor subjacente da
- base de dados chamando
<literal>ScrollableResults.close()</literal> ou
- <literal>Hibernate.close(Iterator)</literal> explicitamente
de um bloco <literal>finally</literal>.
- (Claro que a maioria de aplicações podem facilmente evitar o uso do
<literal>scroll()</literal> ou
- do <literal>iterate()</literal> em todo código provindo do
JTA ou do CMT.)
-
- </para>
-
- </sect2>
-
- <sect2 id="transactions-demarcation-exceptions">
- <title>Tratamento de Exceção</title>
-
- <para>
- Se a <literal>Session</literal> levantar uma exceção
(incluindo qualquer
- <literal>SQLException</literal>), você deve imediatamente dar
um rollback
- na transação do banco, chamando
<literal>Session.close()</literal> e descartando
- a instância da <literal>Session</literal>. Certos métodos da
<literal>Session</literal>
- <literal>não</literal> deixarão a sessão em um estado
inconsistente. Nenhuma exceção
- lançada pelo Hibernate pode ser recuperada. Certifique-se que a
<literal>Session</literal>
- será fechada chamando <literal>close()</literal> no bloco
<literal>finally</literal>.
- </para>
-
- <para>
- A exceção <literal>HibernateException</literal>, a qual
envolve a maioria dos erros
- que podem ocorrer em uma camada de persistência do Hibernate, é uma
exceção unchecked (
- não estava em umas versões mais antigas de Hibernate). Em nossa opinião,
nós não devemos
- forçar o desenvolvedor a tratar uma exceção irrecuperável em uma camada
mais baixa.
- Na maioria dos sistemas, as exceções unchecked e fatais são tratadas em
um dos primeiros
- frames da pilha da chamada do método (isto é, em umas camadas mais
elevadas) e uma mensagem
- de erro é apresentada ao usuário da aplicação (ou a alguma outra ação
apropriada é feita).
- Note que Hibernate pode também lançar outras exceções unchecked que não
são um
- <literal>HibernateException</literal>. Estas, também são,
irrecuperáveis e uma ação
- apropriada deve ser tomada.
- </para>
-
- <para>
- O Hibernate envolve <literal>SQLException</literal>s lançadas
ao interagir com a base de dados
- em um <literal>JDBCException</literal>. Na realidade, o
Hibernate tentará converter a exceção em
- em uma sub classe mais significativa da
<literal>JDBCException</literal>. A
- <literal>SQLException</literal> subjacente está sempre
disponível através de
- <literal>JDBCException.getCause()</literal>.
- </para>
-
- <para>
- O Hibernate converte a <literal>SQLException</literal> em uma
sub classe
- <literal>JDBCException</literal> apropriada usando
<literal>SQLExceptionConverter</literal>
- associado ao SessionFactory. Por padrão, o
<literal>SQLExceptionConverter</literal> é definido
- pelo dialeto configurado; entretanto, é também possível conectar em uma
implementação customizada
- (veja o javadoc para mais detalhes da classe
<literal>SQLExceptionConverterFactory</literal>).
- Os subtipos padrão de <literal>JDBCException</literal> são:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>JDBCConnectionException</literal> - indica
um erro com a comunicação subjacente de JDBC.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>SQLGrammarException</literal> - indica um
problema da gramática ou da sintaxe com o SQL emitido.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>ConstraintViolationException</literal> -
indica algum forma de violação de confinamento de integridade.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockAcquisitionException</literal> - indica
um erro ao adquirir um nível de bloqueio necessário para realizar a operação de
requisição.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>GenericJDBCException</literal> - uma exceção
genérica que não cai em algumas das outras categorias.
- </para>
- </listitem>
- </itemizedlist>
-
- </sect2>
-
- <sect2 id="transactions-demarcation-timeout">
- <title>Timeout de Transação</title>
-
- <para>
- Uma característica extremamente importante fornecida por um ambiente
- gerenciado como EJB e que nunca é fornecido pelo código não gerenciado é
o timeout
- de transação. Timeouts de transação asseguram que nenhuma transação possa
- reter indefinidamente recursos enquanto não retorna nenhuma resposta ao
usuário.
- Fora de um ambiente controlado (JTA), o Hibernate não pode fornecer
inteiramente
- esta funcionalidade. Entretanto, o Hibernate pode afinal controlar as
operações
- do acesso a dados, assegurando que o nível de deadlocks e queries do
banco de
- dados com imensos resultados definidos sejam limitados pelo timeout. Em
um ambiente
- gerenciado, o Hibernate pode delegar o timeout da transação ao JTA. Esta
funcionalidade
- é abstraída pelo objeto <literal>Transaction</literal> do
Hibernate.
- </para>
-
- <programlisting><![CDATA[
-Session sess = factory.openSession();
-try {
- //set transaction timeout to 3 seconds
- sess.getTransaction().setTimeout(3);
- sess.getTransaction().begin();
-
- // do some work
- ...
-
- sess.getTransaction().commit()
-}
-catch (RuntimeException e) {
- sess.getTransaction().rollback();
- throw e; // or display error message
-}
-finally {
- sess.close();
-}]]></programlisting>
-
- <para>
- Veja que <literal>setTimeout()</literal> não pode ser chamado
em um CMT bean,
- onde os timeouts das transações devem ser definidos declarativamente.
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="transactions-optimistic">
- <title>Controle de concorrência otimista</title>
-
- <para>
- O único caminho que é consistente com a elevada concorrência e escalabilidade
- é controle de concorrência otimista com versionamento. Checagem de versão usa
- número de versão, ou timestamps, para detectar conflitos de atualizações (e
para
- impedir atualizações perdidas). O Hibernate fornece três caminhos possíveis
para
- escrever aplicações que usam concorrência otimista. Os casos de uso que nós
mostramos
- estão no contexto de conversações longas, mas a checagem de versão também tem
o
- benefício de impedir atualizações perdidas em únicas transações.
- </para>
-
- <sect2 id="transactions-optimistic-manual">
- <title>Checagem de versão da aplicação</title>
-
- <para>
- Em uma implementação sem muita ajuda do Hibernate, cada interação com o
banco de dados
- ocorre em uma nova <literal>Session</literal> e o
desenvolvedor é responsável para
- recarregar todas as instâncias persistentes da base de dados antes de
manipulá-las.
- Este caminho força a aplicação a realizar sua própria checagem de versão
para assegurar
- a conversação do isolamento da transação. Este caminho é menos eficiente
em termos de
- acesso ao banco de dados. É a caminho mais similar a EJBs entity.
- </para>
-
- <programlisting><![CDATA[// foo is an instance loaded by a previous
Session
-session = factory.openSession();
-Transaction t = session.beginTransaction();
-
-int oldVersion = foo.getVersion();
-session.load( foo, foo.getKey() ); // load the current state
-if ( oldVersion != foo.getVersion() ) throw new StaleObjectStateException();
-foo.setProperty("bar");
-
-t.commit();
-session.close();]]></programlisting>
-
- <para>
- A propriedade <literal>version</literal> é mapeada usando
<literal><version></literal>,
- e o Hibernate vai incrementá-lo-á automaticamente durante o flush se a
entidade
- estiver alterada.
- </para>
-
- <para>
- Claro, se você se estiver operando em um ambiente de baixa concorrência
de dados
- e não requerer a checagem de versão, você pode usar este caminho e apenas
saltar a
- checagem de versão. Nesse caso, o <emphasis>ultimo commit realizdo
</emphasis> é
- a estratégia padrão para suas conversações longas. Mantenha em mente que
isto pode
- confundir os usuários da aplicação, assim como eles podem experimentar
atualizações
- perdidas sem mensagens de erro ou uma possibilidade ajustar mudanças de
conflito.
-
- </para>
-
- <para>
- Claro que, checagem manual da versão é somente praticável em
circunstâncias triviais
- e não para a maioria de aplicações. Freqüentemente, os grafos completos
de objetos
- modificados têm que ser verificados, não somente únicas instâncias. O
Hibernate oferece
- checagem de versão automática com uma
<literal>Session</literal> estendida ou instâncias
- desatachadas como o paradigma do projeto.
- </para>
-
- </sect2>
-
- <sect2 id="transactions-optimistic-longsession">
- <title>Sessão estendida e versionamento automático</title>
-
- <para>
- Uma única instância de <literal>Session</literal> e suas
instâncias persistentes
- são usadas para a conversação inteira, isto é conhecido como
- <emphasis>session-per-conversation</emphasis>. O Hibernate
verifica versões da instância
- no momento dio flush, lançando uma exceção se a modificação concorrente
for detectada.
- Até o desenvolvedor pegar e tratar essa exceção (as opções comuns são a
oportunidade
- para que o usuário intercale as mudanças ou reinicie a conversação do
negócio com
- dados não antigos).
- </para>
-
- <para>
- The <literal>Session</literal> is disconnected from any
underlying JDBC connection
- when waiting for user interaction. This approach is the most efficient in
terms
- of database access. The application need not concern itself with version
checking or
- with reattaching detached instances, nor does it have to reload instances
in every
- database transaction.
- A <literal>Session</literal> é desconectada de toda a conexão
JDBC subjacente
- enquanto espera a interação do usuário. Este caminho é a mais eficiente
em termos
- de acesso a bancos de dados. A aplicação não necessita concernir-se com a
checagem
- de versão ou com as instâncias destacadas reatadas, nem tem que
recarregar instâncias
- em cada transação.
- </para>
-
- <programlisting><![CDATA[// foo is an instance loaded earlier by the
old session
-Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start
transaction
-
-foo.setProperty("bar");
-
-session.flush(); // Only for last transaction in conversation
-t.commit(); // Also return JDBC connection
-session.close(); // Only for last transaction in
conversation]]></programlisting>
- <para>
- O objeto <literal>foo</literal> sabe que
<literal>Session</literal> já foi carregada. Começando
- uma nova transação em uma sessão velha obtém uma conexão nova e recomeça
a sessão. Commitando
- uma transação desconecta uma sessão da conexão JDBC e retorna a conexão
ao pool. Após a reconexão,
- forçar uma checagem de versão em dados que você não está atualizando,
você pode chamar
- <literal>Session.lock()</literal> com o
<literal>LockMode.READ</literal> em todos os objetos
- que possam ter sido atualizados por uma outra transação. Você não
necessita bloquear nenhum
- dado para atualizar. Geralmente você configuraria
<literal>FlushMode.MANUAL</literal> em uma
- <literal>Session</literal> estendida, de modo que somente o
último ciclo da transação tenha
- permissão de persistir todas as modificações feitas nesta conversação.
Disso, somente esta última
- transação incluiria a operação <literal>flush()</literal> e
então chamar também <literal>close()</literal>
- da sessão para terminar a conversação.
- </para>
-
- <para>
- Este pattern é problemático se a <literal>Session</literal>
for demasiadamente grande para
- ser armazenado durante o tempo que usuário pensar, por exemplo um
<literal>HttpSession</literal>
- estiver mantido tão pequeno quanto possível. Como o
<literal>Session</literal> é também cache
- de primeiro nível (imperativo) e contém todos os objetos carregados, nós
podemos provavelmente
- usar esta estratégia somente para alguns ciclos de requisição/resposta.
Você deve usar a
- <literal>Session</literal> somente para uma única
conversação, porque ela logo também
- estará com dados velhos.
- </para>
-
- <para>
- (Note que versões mais atuais de Hibernate requerem a desconexão e o
reconexão explícitas de
- uma <literal>Session</literal>. Estes métodos são
desatualizados, como o início e término de
- uma transação tem o mesmo efeito.)
- </para>
-
- <para>
- Note também que você deve manter a <literal>Session</literal>
desconectada fechada
- para a camada de persistência. Ou seja, use um EJB stateful session bean
para
- prender a <literal>Session</literal> em um ambiente do três
camadas e não o
- transferir à camada web (ou até serializá-lo para uma camada separada)
- para armazená-lo no <literal>HttpSession</literal>.
-
- </para>
-
- <para>
- O pattern sessão estendida, ou
<emphasis>session-per-conversation</emphasis>, é mais
- difícil de implementar com gerenciamento automático de sessão atual. Você
precisa fornecer
- sua própria implementação do
<literal>CurrentSessionContext</literal> para isto
- (veja o Hibernate Wiki para exemplos).
- </para>
-
- </sect2>
-
- <sect2 id="transactions-optimistic-detached">
- <title>Objetos destacados e versionamento automático</title>
-
- <para>
- Cada interação com o armazenamento persistente ocorre em uma
<literal>Session</literal> nova.
- Entretanto, as mesmas instâncias persistentes são reusadas para cada
interação com o banco de dados.
- A aplicação manipula o estado das instâncias desatachadas originalmente
carregadas em um outro
- <literal>Session</literal> e reata-os então usando
<literal>Session.update()</literal>,
- <literal>Session.saveOrUpdate()</literal> ou
<literal>Session.merge()</literal>.
- </para>
-
- <programlisting><![CDATA[// foo is an instance loaded by a previous
Session
-foo.setProperty("bar");
-session = factory.openSession();
-Transaction t = session.beginTransaction();
-session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded
already
-t.commit();
-session.close();]]></programlisting>
-
- <para>
- Outra vez, o Hibernate verificará versões da instância durante o flush,
- lançando uma exceção se ocorrer conflitos de atualizações.
- </para>
-
- <para>
- Você pode também chamar o <literal>lock()</literal> em vez de
<literal>update()</literal>
- e usar <literal>LockMode.READ</literal> (executando uma
checagem de versão, ignorando
- todos os caches) se você estiver certo de que o objeto não foi
modificado.
- </para>
-
- </sect2>
-
- <sect2 id="transactions-optimistic-customizing">
- <title>Versionamento automático customizado</title>
-
- <para>
- Você pode desabilitar o incremento da versão automática de Hibernate para
propriedades
- e coleções particulares configurando o mapeamento do atributo
<literal>optimistic-lock</literal>
- para false. O Hibernate então não irá incrementa versões se a propriedade
estiver
- modificada.
- </para>
-
- <para>
- Os esquemas da base de dados legada são freqüentemente estáticos e não
podem ser modificados.
- Ou outras aplicações puderam também acessar a mesma base de dados e não
sabem tratar a
- versão dos números ou timestamps. Em ambos os casos, o versionamento não
pode confiar em uma
- coluna particular em uma tabela. Para forçar uma checagem de versão sem
uma versão ou mapeamento
- da propriedade do timestamp com uma comparação do estado de todos os
campos em uma linha,
- configure <literal>optimistic-lock="all"</literal>
no mapeamento <literal><class></literal>.
- Note que isto conceitualmente é somente feito em trabalhos se Hibernate
puder comparar o estado
- velho e novo, isto é, se você usa um único
<literal>Session</literal> longo e não
- session-per-request-with-detached-objects.
- </para>
-
- <para>
- Às vezes a modificação concorrente pode ser permitida tão longa quanto às
mudanças que
- tiveram sido feitas que não sobrepuseram. Se você configurar
<literal>optimistic-lock="dirty"</literal>
- ao mapear o <literal><class></literal>, o
Hibernate comparará somente campos
- modificados durante o flush.
- </para>
-
- <para>
- Em ambos os casos, com as colunas dedicadas da versão/timestamp ou com
comparação do
- campo cheio/modificados, o Hibernate usa uma única declaração UPDATE (com
uma cláusula
- WHERE apropriada ) por entidade para executar a checagem da versão e
atualizar a informação.
- Se você usa a persistência transitiva para cascatear o reatamento das
entidades associadas,
- o Hibernate pode executar atualizações desnecessárias. Isso não é
geralmente um problema,
- mas triggers <emphasis>on update</emphasis> em um banco de
dados podem ser executados
- mesmo quando nenhuma mudança foi feita nas instâncias destacadas. Você
pode customizar
- este comportamento configurando
<literal>select-before-update="true"</literal> no
- mapeamento <literal><class></literal>,
forçando o Hibernate a dá um SELECT nas
- instâncias para assegurar-se esse as mudanças ocorreram realmente, antes
de atualizar
- a linha.
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="transactions-locking">
- <title>Locking pessimista</title>
-
- <para>
- Não se pretende que os usuários gastam muitas horas se preocupando com suas
estratégias de
- locking. Geralmente é o bastante para especificar um nível de isolamento para
as conexões
- JDBC e então deixar simplesmente o banco de dados fazer todo o trabalho.
Entretanto, os
- usuários avançados podem às vezes desejar obter locks pessimistas exclusivos,
ou re-obter
- locks no início de uma nova transação.
- </para>
-
- <para>
- O Hibernate usará sempre o mecanismo de lock da base de dados, nunca trava
objetos
- na memória!
- </para>
-
- <para>
- A classe <literal>LockMode</literal> define os diferentes níveis
de lock que o Hibernate
- pode adquirir. Um lock é obtido pelos seguintes mecanismos:
-
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>LockMode.WRITE</literal> é adquirido
automaticamente quando o Hibernate atualiza
- ou insere uma linha.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.UPGRADE</literal> pode ser adquirido
explicitamente pelo usuário
- usando <literal>SELECT ... FOR UPDATE</literal> em um
banco de dados que suporte
- esse sintaxe.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.UPGRADE_NOWAIT</literal> pode ser
adquirido explicitamente pelo usuário
- usando <literal>SELECT ... FOR UPDATE NOWAIT</literal> no
Oracle.
-
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.READ</literal> é adquirido
automaticamente quando o Hibernate lê
- dados em um nível Repeatable Read ou Serializable isolation. Pode ser
readquirido
- explicitamente pelo usuário.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>LockMode.NONE</literal> representa a ausência do lock.
Todos os objetos mudam para
- esse estado de lock no final da <literal>Transaction</literal>.
Objetos associados com a sessão
- através do método <literal>update()</literal> ou
<literal>saveOrUpdate()</literal> também são
- inicializados com esse lock mode.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- O lock obtido "explicitamente pelo usuário" se dá em uma das
seguintes maneiras:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- Uma chamada a <literal>Session.load()</literal>,
especificando
- o <literal>LockMode</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Uma chamada a <literal>Session.lock()</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Uma chamada a <literal>Query.setLockMode()</literal>.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Se uma <literal>Session.load()</literal> é invocada com
<literal>UPGRADE</literal> ou
- <literal>UPGRADE_NOWAIT</literal>, e o objeto requisitado ainda
não foi carregado
- pela sessão, o objeto é carregado usando <literal>SELECT ... FOR
UPDATE</literal>.
- Se <literal>load()</literal> for chamado para um objeto que já
foi carregado
- com um lock menos restritivo que o novo lock solicitado, o Hibernate invoca o
- método <literal>lock()</literal> para aquele objeto.
- </para>
-
- <para>
- O método <literal>Session.lock()</literal> executa uma
verificação no número da versão
- se o modo de lock especificado for <literal>READ</literal>,
<literal>UPGRADE</literal> ou
- <literal>UPGRADE_NOWAIT</literal>.. (No caso do
<literal>UPGRADE</literal> ou
- <literal>UPGRADE_NOWAIT</literal>, é usado <literal>SELECT
... FOR UPDATE</literal>.)
- </para>
-
- <para>
- Se o banco de dados não suportar o lock mode solicitado, o Hibernate vai usar
um modo
- alternativo apropriado (ao invés de lançar uma exceção). Isso garante que a
aplicação
- vai ser portável.
- </para>
-
- </sect1>
-
- <sect1 id="transactions-connection-release">
- <title>Modos de liberar a Connection</title>
-
- <para>
- O comportamento legado do Hibernate (2.x) em consideração ao gerenciamento da
conexão
- via JDBC fez com que a <literal>Session</literal> precisasse
obter uma conexão
- quando ela precisasse pela primeira vez e depois manter a conexão enquanto
- a sessão não fosse fechada. O Hibernate 3.x introduz a idéia de modos de
liberar a
- sessão, para informar a sessão a forma como deve manusear a sua conexão JDBC.
- Veja que essa discussão só é pertinente para conexões fornecidas com um
- <literal>ConnectionProvider</literal> configurado; conexões
fornecidas pelo usuário
- estão fora do escopo dessa discussão. Os diferentes modos de liberação estão
definidos
- pelos valores da enumeração
- <literal>org.hibernate.ConnectionReleaseMode</literal>:
-
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>ON_CLOSE</literal> - essencialmente é o modo
legado descrito acima. A sessão
- do Hibernate obtêm a conexão quando precisar executar alguma operação
JDBC pela
- primeira vez e mantem enquanto a conexão não for fechada.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>AFTER_TRANSACTION</literal> – informa que a
conexão deve ser
- liberada após a conclusão de uma
<literal>org.hibernate.Transaction</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>AFTER_STATEMENT</literal> (também conhecida com
liberação agressiva) – informa
- que a conexão deve ser liberada após a execução de cada statement. A
liberação agressiva
- não ocorre se o statement deixa pra trás algum recurso aberto
associado com a sessão
- obtida; atualmente, a única situação em que isso é possível é com o
uso de
- <literal>org.hibernate.ScrollableResults</literal>.
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- O parâmetro de configuração
<literal>hibernate.connection.release_mode</literal> é usado
- para especificar qual modo de liberação deve ser usado. Opções disponíveis:
- </para>
-
- <itemizedlist spacing="compact">
- <listitem>
- <para>
- <literal>auto</literal> (padrão) – essa opção delega ao
modo de liberação retornado pelo
- método
<literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>.
- Para JTATransactionFactory, ele retorna
ConnectionReleaseMode.AFTER_STATEMENT; para
- JDBCTransactionFactory, ele retorna
ConnectionReleaseMode.AFTER_TRANSACTION.
- Raramente é uma boa idéia alterar padrão, como frequencia ao se fazer
isso temos falhas
- que parecem bugs e/ou suposições inválidas no código do usuário.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>on_close</literal> - indica o uso da
ConnectionReleaseMode.ON_CLOSE. Essa opção
- foi deixada para manter a compatibilidade, mas seu uso é fortemente
desencorajado.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>after_transaction</literal> – indica o uso da
ConnectionReleaseMode.AFTER_TRANSACTION.
- Essa opção nada deve ser usada com ambientes JTA. Também note que no
caso da
- ConnectionReleaseMode.AFTER_TRANSACTION, se a sessão foi colocada no
modo auto-commit a
- conexão vai ser liberada de forma similar ao modo AFTER_STATEMENT.
- </para>
- </listitem>
- <listitem>
- <para>
- <literal>after_statement</literal> – indica o uso
ConnectionReleaseMode.AFTER_STATEMENT.
- Adicionalmente, o <literal>ConnectionProvider</literal>
configurado é consultado para
- verificar se suporta essa configuração
((<literal>supportsAggressiveRelease()</literal>).
- Se não suportar, o modo de liberação é redefinido como
ConnectionRelease-Mode.AFTER_TRANSACTION.
- Essa configuração só é segura em ambientes onde podemos readquirir a
mesma conexão JDBC
- toda vez que o método
<literal>ConnectionProvider.getConnection()</literal> for chamado ou
- em um ambiente auto-commit onde não importa se nós recuperamos a
mesma conexão.
- </para>
- </listitem>
- </itemizedlist>
-
- </sect1>
-
-</chapter>
-
+<chapter id="transactions" revision="2">
+ <title>Transações e Concorrência</title>
+
+ <para>
+ O ponto o mais importante sobre o Hibernate e o controle de concorrência é que é
muito
+ fácil de ser compreendido. O Hibernate usa diretamente conexões de JDBC e
recursos de
+ JTA sem adicionar nenhum comportamento de bloqueio a mais. Nós altamente
recomendamos
+ que você gaste algum tempo com o JDBC, o ANSI e a especificação de isolamento de
transação
+ de seu sistema de gerência da base de dados.
+ </para>
+
+ <para>
+ O Hibernate não bloqueia objetos na memória. Sua aplicação pode esperar o
comportamento
+ tal qual definido pelo nível de isolamento de suas transações de banco de dados.
+ Note que graças ao <literal>Session</literal>, que também é um cache
de escopo de
+ transação, o Hibernate fornece leituras repetíveis para procurar por
identificadores
+ e consultas de entidade (não pesquisas de relatórios que retornam valores
escalares).
+ </para>
+
+ <para>
+ Além do versionamento para o controle automático de concorrência otimista, o
Hibernate
+ oferece também uma API (menor) para bloqueio pessimista de linhas usando a
sintaxe
+ <literal>SELECT FOR UPDATE</literal>. O controle de concorrência
otimista e esta
+ API são discutidos mais tarde neste capítulo.
+ </para>
+
+ <para>
+ Nós começamos a discussão do controle de concorrência no Hibernate com a
granularidade
+ do <literal>Configuration</literal>,
<literal>SessionFactory</literal>, e
+ <literal>Session</literal>, além de transações de base de dados e
conversações longas.
+ </para>
+
+ <sect1 id="transactions-basics" revision="1">
+ <title>Session e escopos de transações</title>
+
+ <para>
+ Um <literal>SessionFactory</literal> é objeto threadsafe
compartilhado por
+ todas as threads da aplicação que consome muitos recursos na sua criação.
+ É criado uma unica vez no inicio da execução da aplicação a partir da
+ instância de uma <literal>Configuration</literal>.
+ </para>
+
+ <para>
+ Uma <literal>Session</literal> é um objeto de baixo custo de
criação, não é threadsafe,
+ deve ser usado uma vez, para uma única requisição, uma conversação, uma única
unidade
+ do trabalho e então deve ser descartado. Um
<literal>Session</literal> não obterá um
+ JDBC <literal>Connection</literal> (ou um
<literal>Datasource</literal>) a menos que
+ necessite, conseqüentemente não consome nenhum recurso até ser usado.
+ </para>
+
+ <para>
+ Para completar, você também tem que pensar sobre as transações de base de
dados.
+ Uma transação tem que ser tão curta quanto possível, para reduzir a disputa
pelo
+ bloqueio na base de dados. Transações longas impedirão que sua aplicação
escale a
+ carga altamente concorrente. Por isso, em um projeto raramente é para manter
+ uma transação de base de dados aberta durante o tempo que o usuário pensa,
+ até que a unidade do trabalho esteja completa.
+ </para>
+
+ <para>
+ Qual é o escopo de uma unidade de trabalho? Pode uma únicoa
<literal>Session</literal>
+ do Hibernate gerenciar diversas transações ou é esta um o relacionamento
um-para-um dos
+ escopos? Quando deve você abrir e fechar uma
<literal>Session</literal> e como você
+ demarca os limites da transação?
+ </para>
+
+ <sect2 id="transactions-basics-uow" revision="1">
+ <title>Unidade de trabalho</title>
+
+ <para>
+ Primeiro, não use o antipattern
<emphasis>sessão-por-operação</emphasis>,
+ isto é, não abra e não feche uma <literal>Session</literal>
para cada simples chamada
+ ao banco de de dados em uma única thread! Naturalmente, o mesmo é
verdadeiro para
+ transações. As chamadas a banco de dados em uma aplicação são feitas
usando uma
+ seqüência planejada, elas são agrupadas em unidades de trabalho atômicas.
+ (Veja que isso também significa que um auto-commit depois de cada
sentença SQL é
+ inútil em uma aplicação, esta modalidade é ideal para o trabalho ad hoc
do console
+ do SQL. O Hibernate impede, ou espera que o servidor de aplicação impessa
isso,
+ o uso da modalidade de auto-commit.) As transações nunca são opcionais,
toda a
+ comunicação com um banco de dados tem que ocorrer dentro de uma
transação, não
+ importa se você vai ler ou escrever dados. Como explicado, o
comportamento auto-commit
+ para leitura de dados deve ser evitado, como muitas transações pequenas
são
+ improváveis de executar melhor do que uma unidade claramente definida do
trabalho. A
+ última opção também muito mais manutenível e extensível.
+ </para>
+
+ <para>
+ O pattern mais comum em uma aplicação multi-usuário cliente/servidor é
+ <emphasis>sessão-por-requisição</emphasis>. Neste modelo, uma
requisição do cliente é
+ enviada ao servidor (onde a camada de persistência do Hibernate roda),
uma
+ <literal>Session</literal> nova do Hibernate é aberta, e
todas as operações da base de
+ dados são executadas nesta unidade do trabalho. Logo que o trabalho for
completado
+ (e a resposta para o cliente for preparada), a sessão é descarregad e
fechada.
+ Você usaria também uma única transação de base de dados para servir às
requisições
+ dos clientes, começando e commitando-o quando você abre e fecha a
<literal>Session</literal>.
+ O relacionamento entre os dois é um-para-um e este modelo é um ajuste
perfeito para muitas
+ aplicações.
+ </para>
+
+ <para>
+ O desafio encontra-se na implementação. O Hibernate fornece gerência
integrada da "sessão atual"
+ para simplificar este pattern. Tudo que você tem que fazer é iniciar uma
transação quando uma
+ requisição tem que ser processada e termina a transação antes que a
resposta seja enviada ao
+ cliente. Você pode fazer onde quiser, soluções comuns são
<literal>ServletFilter</literal>,
+ interceptador AOP com um pointcut (ponto de corte) nos métodos de serviço
ou em um
+ container de proxy/interceptação. Um container de EJB é uma maneira
padronizada para
+ implementar aspectos cross-cutting tais como a demarcação da transação em
EJB session beans,
+ declarativamente com CMT. Se você se decidir usar demarcação programática
de transação,
+ de preferencia a API <literal>Transaction</literal> do
Hibernate mostrada mais adiante neste
+ capítulo, para fácilidade no uso e portabilidade de código.
+ </para>
+
+ <para>
+ Seu código de aplicação pode acessar a "sessão atual" para
processar a requisição
+ fazendo uma chamada simples a
<literal>sessionFactory.getCurrentSession()</literal> em
+ qualquer lugar e com a frequencia necessária. Você sempre conseguirá uma
+ <literal>Session</literal> limitada a transação atual. Isto
tem que ser configurado
+ para recurso local ou os ambientes JTA. Veja <xref
linkend="architecture-current-session"/>.
+ </para>
+
+ <para>
+ Às vezes é conveniente estender o escopo de uma
<literal>Session</literal> e de
+ uma transação do banco de dados até que a "visão esteja
renderizada". É especialmente
+ útil em aplicações servlet que utilizam uma fase de rendenderização
separada depois
+ que a requisição ter sido processada. Estendendo a transação até que
renderização da
+ visão esteja completa é fácil de fazer se você implementar seu próprio
interceptador.
+ Entretanto, não se pode fazer facilmente se você confiar em EJBs com
transações
+ gerenciadas por contêiner, porque uma transação será terminada quando um
método de
+ EJB retornar, antes da renderização de toda visão puder começar.
+ Veja o website e o fórum do Hibernate para dicas e exemplos em torno
deste
+ pattern <emphasis>Open Session in View</emphasis>.
+
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-apptx" revision="1">
+ <title>Longas conversações</title>
+
+ <para>
+ O pattern sessão-por-requisição não é o único conceito útil que você pode
usar ao projetar
+ unidades de trabalho. Muitos processos de negócio requerem uma totalidade
de séries de
+ interações com o usuário intercaladas com acessos a uma base de dados. Em
aplicações web
+ e corporativas não é aceitável para uma transação atrapalhe uma interação
do usuário.
+ Considere o seguinte exemplo:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ A primeira tela de um diálogo abre os dados carregado pelo
usuário em através de
+ <literal>Session</literal> e transação particulares.
O usuário está livre
+ modificar os objetos.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ O usuário clica em "Salvar" após 5 minutos e espera
suas modificações serem persistidas;
+ espera também que ele era a única pessoa que edita esta
informação e que nenhuma
+ modificação conflitante possa ocorrer.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Nós chamamos esta unidade de trabalho, do ponto da visão do usuário,
executando uma
+ longa <emphasis>conversação</emphasis> (ou
<emphasis>transação da aplicação</emphasis>).
+ Há muitas maneiras de você pode implementar em sua aplicação.
+
+ </para>
+
+ <para>
+ Uma primeira implementação simples pode manter
a<literal>Session</literal> e a transação
+ aberta durante o tempo de interação do usuário, com bloqueios na base de
dados para impedir
+ a modificação concorrente e para garantir o isolamento e a atomicidade.
Esse é naturalmente
+ um anti-pattern, desde que a disputa do bloqueio não permitiria o
escalonameneto da
+ aplicação com o número de usuários concorrentes.
+ </para>
+
+ <para>
+ Claramente, nós temos que usar diversas transações para implementar a
conversação.
+ Neste caso, Manter o isolamento dos processos de negócio torna-se
responsabilidade
+ parcial da camada da aplicação. Uma única conversação geralmente usa
diversas transações.
+ Ela será atômica se somente uma destas transações (a última) armazenar
os
+ dados atualizados, todas as outras simplesmente leram os dados (por
exemplo em um
+ diálogo do estilo wizard que mede diversos ciclos de
requisição/resposta). Isto é mais
+ fácil de implementar do que pode parecer, especialmente se você usar as
+ características do Hibernate:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Versionamento automático</emphasis> - O
Hibernate pode fazer o
+ controle automático de concorrência otimista para você, ele pode
+ automaticamente detectar se uma modificação concorrente
+ ocorreu durante o tempo de interação do usuário. Geralmente nós
verificamos
+ somente no fim da conversação.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Detached Objects</emphasis>- se você se
decidir usar o já discutido
+ pattern <emphasis>session-per-request</emphasis>,
todas as instâncias carregadas
+ estarão no estado destacado durante o tempo em que o usuário
estiver pensando.
+ O Hibernate permite que você reatache os objetos e persita as
modificações,
+ esse pattern é chamado
+
<emphasis>session-per-request-with-detached-objects</emphasis>.
+ É usado versionamento automatico para isolar as modificações
concorrentes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Extended (or Long) Session</emphasis> A
<literal>Session</literal>
+ do Hibernate pode ser desligada da conexão básica do JDBC depois
que a
+ transação foi commitada e ser reconectado quando uma nova
requisição do
+ cliente ocorrer. Este pattern é conhecido como
+ <emphasis>session-per-conversation</emphasis> e faz o
reatamento uniforme
+ desnecessário. Versionamento automático é usado para isolar
modificações
+ concorrentes e a
<emphasis>session-per-conversation</emphasis> usualmente
+ não é permitido para ser nivelado automaticamente, e sim
explicitamente.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Ambos
<emphasis>session-per-request-with-detached-objects</emphasis> e
+ <emphasis>session-per-conversation</emphasis> possuem
vantagens e desvantagens,
+ nos discutiremos mais tarde neste capítulo no contexto do controle de
+ concorrência otimista.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-identity">
+ <title>Considerando a identidade do objeto</title>
+
+ <para>
+ Uma aplicação pode acessar concorrentemente o mesmo estado persistente em
duas
+ <literal>Session</literal>s diferentes. Entretanto, uma
instância de uma classe
+ persistente nunca é compartilhada entre duas instâncias
<literal>Session</literal>.
+ Por tanto, há duas noções diferentes da identidade:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Identidade da base de dados</term>
+ <listitem>
+ <para>
+ <literal>foo.getId().equals( bar.getId()
)</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Identidade da JVM</term>
+ <listitem>
+ <para>
+ <literal>foo==bar</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Então para os objetos acoplados a um
<literal>Session</literal> em <literal>particular </literal>
+ (isto é no escopo de um <literal>Session</literal>), as duas
noções são equivalentes e a
+ identidade da JVM para a identidade da base de dados é garantida pelo
Hibernate. Entretanto,
+ quando a aplicação pode acessar concorrentemente o "mesmo"
objeto do negócio (identidade
+ persistente) em duas sessões diferentes, as duas instâncias serão
realmente "diferentes"
+ (identidade de JVM). Os conflitos são resolvidos usando (versionamento
automático) no
+ flush/commit, usando abordagem otimista.
+
+ </para>
+
+ <para>
+ Este caminho deixa o Hibernate e o banco dedados se preocuparem com a
concorrência; também
+ fornece uma escalabilidade melhor, garantindo que a identidade em
unidades de trabalho
+ único-encadeadas não necessite de bloqueio dispendioso ou de outros meios
de sincronização.
+ A aplicação nunca necessita sincronizar qualquer objeto de negócio tão
longo que transpasse
+ uma única thread por <literal>Session</literal>. Dentro de
uma <literal>Session</literal> a
+ aplicação pode usar com segurança o <literal>==</literal>
para comparar objetos.
+ </para>
+
+ <para>
+ Com tudo, uma aplicação que usa <literal>==</literal> fora de
uma <literal>Session</literal>,
+ pode ver resultados inesperados. Isto pode ocorrer mesmo em alguns
lugares inesperados, por
+ exemplo, se você colocar duas instâncias desacopladas em um mesmo
<literal>Set</literal>.
+ Ambos podem ter a mesma identidade na base de dados (isto é eles
representam a mesma linha
+ em uma tabela), mas a identidade da JVM pela definição não garantida para
instâncias em estado
+ desacoplado. O desenvolvedor tem que sobrescrever os métodos
<literal>equals()</literal> e
+ <literal>hashCode()</literal> em classes persistentes e
implementar sua própria noção da
+ igualdade do objeto. Advertência: nunca use o identificador da base de
dados para implementar
+ a igualdade, use atributos de negócio, uma combinação única, geralmente
imutável. O
+ identificador da base de dados mudará se um objeto transiente passar para
o estado persistente.
+ Se a instância transiente (geralmente junto com instâncias desacopladas)
for inserida em um
+ <literal>Set</literal>, mudar o hashcode quebra o contrato do
<literal>Set</literal>.
+ Atributos para chaves de negócio não têm que ser tão estável quanto às
chaves primárias
+ da base de dados, você somente tem que garantir a estabilidade durante o
tempo que
+ os objetos estiverem no mesmo Set. Veja o website do Hibernate para uma
discussão mais
+ completa sobre o assunto. Note também que esta não é uma caracteristica
do Hibernate,
+ mas simplesmente como a identidade e a igualdade do objeto de Java têm
que ser implementadas.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-issues">
+ <title>Edições comuns</title>
+
+ <para>
+ Nunca use o anti-patterns
<emphasis>session-per-user-session</emphasis> ou
+ <emphasis>session-per-application</emphasis> (naturalmente,
há umas exceções raras a
+ essa regra). Note que algumas das seguintes edições podem também
aparecer com patterns
+ recomendados, certifique-se que tenha compreendido as implicações antes
de fazer
+ uma decisão de projeto:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Uma <literal>Session</literal> não é threadsafe. As
coisas que são supostas para trabalhar
+ concorrentemente, como requisições HTTP, session beans, ou Swing,
causarão condições de
+ disputa se uma instância <literal>Session</literal>
for compartilhada. Se você mantiver
+ sua <literal>Session</literal> do Hibernate em seu
<literal>HttpSession</literal>
+ (discutido mais tarde), você deve considerar sincronizar o acesso
a sua sessão do HTTP.
+ Caso contrário, um usuário que clica em reload várias muito
rapidamente pode usar o
+ mesmo <literal>Session</literal> em duas threads
executando concorrentemente.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Uma exceção lançada pelo Hibernate significa que você tem que dar
rollback na sua
+ transação no banco de dados e fechar a
<literal>Session</literal> imediatamente
+ (discutido mais tarde em maiores detalhes). Se sua
<literal>Session</literal> é
+ limitado pela aplicação, você tem que parar a aplicação. Dando
rollback na
+ transação no banco de dados não põe seus objetos do negócio em um
estado anterior
+ que estavam no início da transação. Isto significa que o estado
da base de dados
+ e os objetos de negócio perdem a sincronização. Geralmente não é
um problema
+ porque as exceções não são recuperáveis e você tem que iniciar
após o
+ rollback de qualquer maneira.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ O <literal>Session</literal> guarda em cache cada
objeto que está no estado persistente
+ (guardado e checado para estado "sujo" pelo Hibernate).
Isto significa que ele cresce
+ infinitamente até que você obtenha uma OutOfMemoryException, se
você o mantiver aberto
+ por muito tempo ou simplesmente carregar dados demais. Uma
solução é chamar
+ <literal>clear()</literal> e
<literal>evict()</literal> para controlar o cache
+ da <literal>Session</literal>, mas você deve
considerar uma Store Procedure
+ se precisar de operações que envolvam grande volume de dados.
Algumas soluções são
+ mostradas no <xref linkend="batch"/>. Manter uma
<literal>Session</literal> aberta
+ durante uma sessão do usuário significa também uma probabilidade
elevada de se acabar
+ com dados velhos.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-demarcation">
+ <title>Demarcação de transações de bancos de dados</title>
+
+ <para>
+ Os limites de uma transação de banco de dados (ou sistema) são sempre
necessários. Nenhuma
+ comunicação com o banco de dados pode ocorrer fora de uma transação de banco
de dados (isto
+ parece confundir muitos desenvolvedores que estão usados modo auto-commit).
Sempre use os
+ limites desobstruídos da transação, até mesmo para operações somente leitura.
Dependendo
+ de seu nível de isolamento e capacidade da base de dados isto pode não ser
requerido,
+ mas não há nenhum aspecto negativo se você demarca sempre transações
explicitamente.
+ Certamente, uma única transação será melhor executada do que muitas
transações pequenas,
+ até mesmo para dados de leitura.
+ </para>
+
+ <para>
+ Uma aplicação do Hibernate pode funcionar em ambientes não gerenciados (isto
é aplicações standalone, Web
+ simples ou Swing) e ambientes gerenciados J2EE. Em um ambiente não
gerenciado, o Hibernate é geralmente
+ responsável pelo seu próprio pool de conexões. O desenvolvedor tem que
manualmente ajustar limites das
+ transaçãos, ou seja, começar, commitar, ou dar rollback nas transações ele
mesmo. Um ambiente gerenciado
+ fornece transações gerenciadas por contêiner (CMT - container-managed
transactions), com um conjunto
+ da transações definido declarativamente em descritores de deployment de EJB
session beans, por exemplo.
+ A demarcação programática é então já não é necessário.
+ </para>
+
+ <para>
+ Entretanto, é freqüentemente desejável manter sua camada de persistência
portável entre ambientes
+ de recurso locais não gerenciados e sistemas que podem confiar em JTA, mas
usar BMT em vez de CMT.
+ Em ambos os casos você usaria demarcação de transação programática. O
Hibernate oferece uma API
+ chamada Transaction que traduz dentro do sistema de transação nativa de seu
ambiente de deployment.
+ Esta API é realmente opcional, mas nós encorajamos fortemente seu uso a menos
que você estiver
+ em um CMT session bean.
+ </para>
+
+ <para>
+ Geralmente, finalizar um <literal>Session</literal>envolve quatro
fases distintas:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ flush da sessão
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ commitar a transação
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ fechar a sessão
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ tratar as exceções
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ A limpeza da sessão já foi bem discutida, agora nós daremos uma olhada na
demarcação da
+ transação e na manipulação de exceção em ambientes controlados e não
controlados.
+ </para>
+
+
+ <sect2 id="transactions-demarcation-nonmanaged"
revision="2">
+ <title>Ambiente não gerenciado</title>
+
+ <para>
+ Se uma camada de persistência do Hibernate roda em um ambiente não
gerenciado, as conexões
+ do banco de dados são geralmente tratadas pelos pools de conexões simples
+ (isto é, não baseados em DataSource) dos quais o Hibernate obtém as
conexões assim
+ que necessita. A maneira de se manipular uma sessão/transação é mais ou
menos assim:
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ Você não pode chamar <literal>flush()</literal> do
<literal>Session()</literal>
+ explicitamente - a chamada ao <literal>commit()</literal>
dispara automaticamente
+ a sincronização para a sessão (dependendo do <xref
linkend="objectstate-flushing">
+ FlushMode</xref>). Uma chamada ao
<literal>close()</literal> marca o fim de uma sessão.
+ A principal implicação do <literal>close()</literal> é que a
conexão JDBC será abandonada
+ pela sessão. Este código Java é portável e funciona em ambientes não
gerenciado e de JTA.
+ </para>
+
+ <para>
+ Uma solução muito mais flexível é gerência integrada de contexto da
"sessão atual"
+ do Hibernate, como descrito anteriormente:
+ </para>
+
+ <programlisting><![CDATA[// Non-managed environment idiom with
getCurrentSession()
+try {
+ factory.getCurrentSession().beginTransaction();
+
+ // do some work
+ ...
+
+ factory.getCurrentSession().getTransaction().commit();
+}
+catch (RuntimeException e) {
+ factory.getCurrentSession().getTransaction().rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ Você muito provavelmente nunca verá estes fragmentos de código em uma
aplicação
+ regular; as exceções fatais (do sistema) devem sempre ser pegas no
"alto".
+ Ou seja, o código que executa chamadas do Hibernate (na camada de
persistência)
+ e o código que trata <literal>RuntimeException</literal> (e
geralmente pode
+ somente limpar acima e na saída) estão em camadas diferentes. O
gerenciamento do
+ contexto atual feito pelo Hibernate pode significativamente simplificar
este
+ projeto, como tudo que você necessita é do acesso a um
<literal>SessionFactory</literal>.
+ A manipulação de exceção é discutida mais tarde neste capítulo.
+ </para>
+
+ <para>
+ Note que você deve selecionar
<literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+ (que é o padrão) e para o segundo exemplo
<literal>"thread"</literal> como seu
+ <literal>hibernate.current_session_context_class</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-jta" revision="3">
+ <title>Usando JTA</title>
+
+ <para>
+ Se sua camada de persistência funcionar em um servidor de aplicação (por
exemplo,
+ dentro dos EJB session beans), cada conexão do datasource obtida pelo
Hibernate
+ automaticamente fará parte da transação global de JTA. Você pode também
instalar uma
+ implementação standalone de JTA e usá-la sem EJB. O Hibernate oferece
duas estratégias
+ para a integração de JTA.
+ </para>
+
+ <para>
+ Se você usar bean-managed transactions (BMT - transações gerenciadas por
bean) o Hibernate dirá
+ ao servidor de aplicação para começar e para terminar uma transação de
BMT se você usar a API
+ Transaction. Assim, o código de gerência de transação é idêntico ao
ambiente não gerenciado.
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ Se você quiser usar um <literal>Session</literal> limitada
por transação, isto é,
+ a funcionalidade do <literal>getCurrentSession()</literal>
para a propagação fácil
+ do contexto, você terá que usar diretamente a API JTA
<literal>UserTransaction</literal>:
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom with getCurrentSession()
+try {
+ UserTransaction tx = (UserTransaction)new InitialContext()
+ .lookup("java:comp/UserTransaction");
+
+ tx.begin();
+
+ // Do some work on Session bound to transaction
+ factory.getCurrentSession().load(...);
+ factory.getCurrentSession().persist(...);
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ tx.rollback();
+ throw e; // or display error message
+}]]></programlisting>
+
+ <para>
+ Com CMT, a demarcação da transação é feita em descritores de deployment
do session beans,
+ não programaticamente, conseqüentemente, o código é reduzido a:
+ </para>
+
+ <programlisting><![CDATA[// CMT idiom
+ Session sess = factory.getCurrentSession();
+
+ // do some work
+ ...
+]]></programlisting>
+
+ <para>
+ Em um CMT/EJB mesmo um rollback acontece automaticamente, desde que uma
exeção <literal>RuntimeException</literal>
+ não tratável seja lançada por um método de um session bean que informa ao
contêiner ajustar a
+ transação global ao rollback. <emphasis>Isto significa que você não
necessita usar a API
+ <literal>Transaction</literal> do Hibernate em tudo com BMT
ou CMT e você obtém a propagação
+ automática do Session "atual" limitada à
transação.</emphasis>
+ </para>
+
+ <para>
+ Veja que você deverá escolher
<literal>org.hibernate.transaction.JTATransactionFactory</literal>
+ se você usar o JTA diretamente (BMT) e
<literal>org.hibernate.transaction.CMTTransactionFactory</literal>
+ em um CMT session bean, quando você configura a fábrica de transação do
Hibernate. Lembre-se também de
+ configurar o
<literal>hibernate.transaction.manager_lookup_class</literal>. Além disso,
certifique-se
+ que seu
<literal>hibernate.current_session_context_class</literal> ou não é
configurado (compatibilidade
+ com o legado) ou é definido para
<literal>"jta"</literal>.
+
+ </para>
+
+ <para>
+ A operação <literal>getCurrentSession()</literal> tem um
aspecto negativo em um ambiente JTA.
+ Há uma advertência para o uso do método liberado de conexão
<literal>after_statement</literal>,
+ o qual é usado então por padrão. Devido a uma limitação simples da
especificação JTA, não é
+ possível para o Hibernate automaticamente limpar quaisquer instâncias
<literal>ScrollableResults</literal>
+ ou <literal>Iterator</literal> abertas retornadas pelo
<literal>scroll()</literal> ou
+ <literal>iterate()</literal>. Você
<emphasis>deve</emphasis> liberar o cursor subjacente da
+ base de dados chamando
<literal>ScrollableResults.close()</literal> ou
+ <literal>Hibernate.close(Iterator)</literal> explicitamente
de um bloco <literal>finally</literal>.
+ (Claro que a maioria de aplicações podem facilmente evitar o uso do
<literal>scroll()</literal> ou
+ do <literal>iterate()</literal> em todo código provindo do
JTA ou do CMT.)
+
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-exceptions">
+ <title>Tratamento de Exceção</title>
+
+ <para>
+ Se a <literal>Session</literal> levantar uma exceção
(incluindo qualquer
+ <literal>SQLException</literal>), você deve imediatamente dar
um rollback
+ na transação do banco, chamando
<literal>Session.close()</literal> e descartando
+ a instância da <literal>Session</literal>. Certos métodos da
<literal>Session</literal>
+ <literal>não</literal> deixarão a sessão em um estado
inconsistente. Nenhuma exceção
+ lançada pelo Hibernate pode ser recuperada. Certifique-se que a
<literal>Session</literal>
+ será fechada chamando <literal>close()</literal> no bloco
<literal>finally</literal>.
+ </para>
+
+ <para>
+ A exceção <literal>HibernateException</literal>, a qual
envolve a maioria dos erros
+ que podem ocorrer em uma camada de persistência do Hibernate, é uma
exceção unchecked (
+ não estava em umas versões mais antigas de Hibernate). Em nossa opinião,
nós não devemos
+ forçar o desenvolvedor a tratar uma exceção irrecuperável em uma camada
mais baixa.
+ Na maioria dos sistemas, as exceções unchecked e fatais são tratadas em
um dos primeiros
+ frames da pilha da chamada do método (isto é, em umas camadas mais
elevadas) e uma mensagem
+ de erro é apresentada ao usuário da aplicação (ou a alguma outra ação
apropriada é feita).
+ Note que Hibernate pode também lançar outras exceções unchecked que não
são um
+ <literal>HibernateException</literal>. Estas, também são,
irrecuperáveis e uma ação
+ apropriada deve ser tomada.
+ </para>
+
+ <para>
+ O Hibernate envolve <literal>SQLException</literal>s lançadas
ao interagir com a base de dados
+ em um <literal>JDBCException</literal>. Na realidade, o
Hibernate tentará converter a exceção em
+ em uma sub classe mais significativa da
<literal>JDBCException</literal>. A
+ <literal>SQLException</literal> subjacente está sempre
disponível através de
+ <literal>JDBCException.getCause()</literal>.
+
+ O Hibernate converte a <literal>SQLException</literal> em uma
sub classe
+ <literal>JDBCException</literal> apropriada usando
<literal>SQLExceptionConverter</literal>
+ associado ao SessionFactory. Por padrão, o
<literal>SQLExceptionConverter</literal> é definido
+ pelo dialeto configurado; entretanto, é também possível conectar em uma
implementação customizada
+ (veja o javadoc para mais detalhes da classe
<literal>SQLExceptionConverterFactory</literal>).
+ Os subtipos padrão de <literal>JDBCException</literal> são:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>JDBCConnectionException</literal> - indica
um erro com a comunicação subjacente de JDBC.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>SQLGrammarException</literal> - indica um
problema da gramática ou da sintaxe com o SQL emitido.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ConstraintViolationException</literal> -
indica algum forma de violação de confinamento de integridade.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockAcquisitionException</literal> - indica
um erro ao adquirir um nível de bloqueio necessário para realizar a operação de
requisição.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>GenericJDBCException</literal> - uma exceção
genérica que não cai em algumas das outras categorias.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-timeout">
+ <title>Timeout de Transação</title>
+
+ <para>
+ Uma característica extremamente importante fornecida por um ambiente
+ gerenciado como EJB e que nunca é fornecido pelo código não gerenciado é
o timeout
+ de transação. Timeouts de transação asseguram que nenhuma transação possa
+ reter indefinidamente recursos enquanto não retorna nenhuma resposta ao
usuário.
+ Fora de um ambiente controlado (JTA), o Hibernate não pode fornecer
inteiramente
+ esta funcionalidade. Entretanto, o Hibernate pode afinal controlar as
operações
+ do acesso a dados, assegurando que o nível de deadlocks e queries do
banco de
+ dados com imensos resultados definidos sejam limitados pelo timeout. Em
um ambiente
+ gerenciado, o Hibernate pode delegar o timeout da transação ao JTA. Esta
funcionalidade
+ é abstraída pelo objeto <literal>Transaction</literal> do
Hibernate.
+ </para>
+
+ <programlisting><![CDATA[
+Session sess = factory.openSession();
+try {
+ //set transaction timeout to 3 seconds
+ sess.getTransaction().setTimeout(3);
+ sess.getTransaction().begin();
+
+ // do some work
+ ...
+
+ sess.getTransaction().commit()
+}
+catch (RuntimeException e) {
+ sess.getTransaction().rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ Veja que <literal>setTimeout()</literal> não pode ser chamado
em um CMT bean,
+ onde os timeouts das transações devem ser definidos declarativamente.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-optimistic">
+ <title>Controle de concorrência otimista</title>
+
+ <para>
+ O único caminho que é consistente com a elevada concorrência e escalabilidade
+ é controle de concorrência otimista com versionamento. Checagem de versão usa
+ número de versão, ou timestamps, para detectar conflitos de atualizações (e
para
+ impedir atualizações perdidas). O Hibernate fornece três caminhos possíveis
para
+ escrever aplicações que usam concorrência otimista. Os casos de uso que nós
mostramos
+ estão no contexto de conversações longas, mas a checagem de versão também tem
o
+ benefício de impedir atualizações perdidas em únicas transações.
+ </para>
+
+ <sect2 id="transactions-optimistic-manual">
+ <title>Checagem de versão da aplicação</title>
+
+ <para>
+ Em uma implementação sem muita ajuda do Hibernate, cada interação com o
banco de dados
+ ocorre em uma nova <literal>Session</literal> e o
desenvolvedor é responsável para
+ recarregar todas as instâncias persistentes da base de dados antes de
manipulá-las.
+ Este caminho força a aplicação a realizar sua própria checagem de versão
para assegurar
+ a conversação do isolamento da transação. Este caminho é menos eficiente
em termos de
+ acesso ao banco de dados. É a caminho mais similar a EJBs entity.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous
Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion != foo.getVersion() ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ A propriedade <literal>version</literal> é mapeada usando
<literal><version></literal>,
+ e o Hibernate vai incrementá-lo-á automaticamente durante o flush se a
entidade
+ estiver alterada.
+ </para>
+
+ <para>
+ Claro, se você se estiver operando em um ambiente de baixa concorrência
de dados
+ e não requerer a checagem de versão, você pode usar este caminho e apenas
saltar a
+ checagem de versão. Nesse caso, o <emphasis>ultimo commit realizdo
</emphasis> é
+ a estratégia padrão para suas conversações longas. Mantenha em mente que
isto pode
+ confundir os usuários da aplicação, assim como eles podem experimentar
atualizações
+ perdidas sem mensagens de erro ou uma possibilidade ajustar mudanças de
conflito.
+
+ </para>
+
+ <para>
+ Claro que, checagem manual da versão é somente praticável em
circunstâncias triviais
+ e não para a maioria de aplicações. Freqüentemente, os grafos completos
de objetos
+ modificados têm que ser verificados, não somente únicas instâncias. O
Hibernate oferece
+ checagem de versão automática com uma
<literal>Session</literal> estendida ou instâncias
+ desatachadas como o paradigma do projeto.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-longsession">
+ <title>Sessão estendida e versionamento automático</title>
+
+ <para>
+ Uma única instância de <literal>Session</literal> e suas
instâncias persistentes
+ são usadas para a conversação inteira, isto é conhecido como
+ <emphasis>session-per-conversation</emphasis>. O Hibernate
verifica versões da instância
+ no momento dio flush, lançando uma exceção se a modificação concorrente
for detectada.
+ Até o desenvolvedor pegar e tratar essa exceção (as opções comuns são a
oportunidade
+ para que o usuário intercale as mudanças ou reinicie a conversação do
negócio com
+ dados não antigos).
+ </para>
+
+ <para>
+ The <literal>Session</literal> is disconnected from any
underlying JDBC connection
+ when waiting for user interaction. This approach is the most efficient in
terms
+ of database access. The application need not concern itself with version
checking or
+ with reattaching detached instances, nor does it have to reload instances
in every
+ database transaction.
+ A <literal>Session</literal> é desconectada de toda a conexão
JDBC subjacente
+ enquanto espera a interação do usuário. Este caminho é a mais eficiente
em termos
+ de acesso a bancos de dados. A aplicação não necessita concernir-se com a
checagem
+ de versão ou com as instâncias destacadas reatadas, nem tem que
recarregar instâncias
+ em cada transação.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded earlier by the
old session
+Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start
transaction
+
+foo.setProperty("bar");
+
+session.flush(); // Only for last transaction in conversation
+t.commit(); // Also return JDBC connection
+session.close(); // Only for last transaction in
conversation]]></programlisting>
+ <para>
+ O objeto <literal>foo</literal> sabe que
<literal>Session</literal> já foi carregada. Começando
+ uma nova transação em uma sessão velha obtém uma conexão nova e recomeça
a sessão. Commitando
+ uma transação desconecta uma sessão da conexão JDBC e retorna a conexão
ao pool. Após a reconexão,
+ forçar uma checagem de versão em dados que você não está atualizando,
você pode chamar
+ <literal>Session.lock()</literal> com o
<literal>LockMode.READ</literal> em todos os objetos
+ que possam ter sido atualizados por uma outra transação. Você não
necessita bloquear nenhum
+ dado para atualizar. Geralmente você configuraria
<literal>FlushMode.MANUAL</literal> em uma
+ <literal>Session</literal> estendida, de modo que somente o
último ciclo da transação tenha
+ permissão de persistir todas as modificações feitas nesta conversação.
Disso, somente esta última
+ transação incluiria a operação <literal>flush()</literal> e
então chamar também <literal>close()</literal>
+ da sessão para terminar a conversação.
+ </para>
+
+ <para>
+ Este pattern é problemático se a <literal>Session</literal>
for demasiadamente grande para
+ ser armazenado durante o tempo que usuário pensar, por exemplo um
<literal>HttpSession</literal>
+ estiver mantido tão pequeno quanto possível. Como o
<literal>Session</literal> é também cache
+ de primeiro nível (imperativo) e contém todos os objetos carregados, nós
podemos provavelmente
+ usar esta estratégia somente para alguns ciclos de requisição/resposta.
Você deve usar a
+ <literal>Session</literal> somente para uma única
conversação, porque ela logo também
+ estará com dados velhos.
+ </para>
+
+ <para>
+ (Note que versões mais atuais de Hibernate requerem a desconexão e o
reconexão explícitas de
+ uma <literal>Session</literal>. Estes métodos são
desatualizados, como o início e término de
+ uma transação tem o mesmo efeito.)
+ </para>
+
+ <para>
+ Note também que você deve manter a <literal>Session</literal>
desconectada fechada
+ para a camada de persistência. Ou seja, use um EJB stateful session bean
para
+ prender a <literal>Session</literal> em um ambiente do três
camadas e não o
+ transferir à camada web (ou até serializá-lo para uma camada separada)
+ para armazená-lo no <literal>HttpSession</literal>.
+
+ </para>
+
+ <para>
+ O pattern sessão estendida, ou
<emphasis>session-per-conversation</emphasis>, é mais
+ difícil de implementar com gerenciamento automático de sessão atual. Você
precisa fornecer
+ sua própria implementação do
<literal>CurrentSessionContext</literal> para isto
+ (veja o Hibernate Wiki para exemplos).
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-detached">
+ <title>Objetos destacados e versionamento automático</title>
+
+ <para>
+ Cada interação com o armazenamento persistente ocorre em uma
<literal>Session</literal> nova.
+ Entretanto, as mesmas instâncias persistentes são reusadas para cada
interação com o banco de dados.
+ A aplicação manipula o estado das instâncias desatachadas originalmente
carregadas em um outro
+ <literal>Session</literal> e reata-os então usando
<literal>Session.update()</literal>,
+ <literal>Session.saveOrUpdate()</literal> ou
<literal>Session.merge()</literal>.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous
Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded
already
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Outra vez, o Hibernate verificará versões da instância durante o flush,
+ lançando uma exceção se ocorrer conflitos de atualizações.
+ </para>
+
+ <para>
+ Você pode também chamar o <literal>lock()</literal> em vez de
<literal>update()</literal>
+ e usar <literal>LockMode.READ</literal> (executando uma
checagem de versão, ignorando
+ todos os caches) se você estiver certo de que o objeto não foi
modificado.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-customizing">
+ <title>Versionamento automático customizado</title>
+
+ <para>
+ Você pode desabilitar o incremento da versão automática de Hibernate para
propriedades
+ e coleções particulares configurando o mapeamento do atributo
<literal>optimistic-lock</literal>
+ para false. O Hibernate então não irá incrementa versões se a propriedade
estiver
+ modificada.
+ </para>
+
+ <para>
+ Os esquemas da base de dados legada são freqüentemente estáticos e não
podem ser modificados.
+ Ou outras aplicações puderam também acessar a mesma base de dados e não
sabem tratar a
+ versão dos números ou timestamps. Em ambos os casos, o versionamento não
pode confiar em uma
+ coluna particular em uma tabela. Para forçar uma checagem de versão sem
uma versão ou mapeamento
+ da propriedade do timestamp com uma comparação do estado de todos os
campos em uma linha,
+ configure <literal>optimistic-lock="all"</literal>
no mapeamento <literal><class></literal>.
+ Note que isto conceitualmente é somente feito em trabalhos se Hibernate
puder comparar o estado
+ velho e novo, isto é, se você usa um único
<literal>Session</literal> longo e não
+ session-per-request-with-detached-objects.
+ </para>
+
+ <para>
+ Às vezes a modificação concorrente pode ser permitida tão longa quanto às
mudanças que
+ tiveram sido feitas que não sobrepuseram. Se você configurar
<literal>optimistic-lock="dirty"</literal>
+ ao mapear o <literal><class></literal>, o
Hibernate comparará somente campos
+ modificados durante o flush.
+ </para>
+
+ <para>
+ Em ambos os casos, com as colunas dedicadas da versão/timestamp ou com
comparação do
+ campo cheio/modificados, o Hibernate usa uma única declaração UPDATE (com
uma cláusula
+ WHERE apropriada ) por entidade para executar a checagem da versão e
atualizar a informação.
+ Se você usa a persistência transitiva para cascatear o reatamento das
entidades associadas,
+ o Hibernate pode executar atualizações desnecessárias. Isso não é
geralmente um problema,
+ mas triggers <emphasis>on update</emphasis> em um banco de
dados podem ser executados
+ mesmo quando nenhuma mudança foi feita nas instâncias destacadas. Você
pode customizar
+ este comportamento configurando
<literal>select-before-update="true"</literal> no
+ mapeamento <literal><class></literal>,
forçando o Hibernate a dá um SELECT nas
+ instâncias para assegurar-se esse as mudanças ocorreram realmente, antes
de atualizar
+ a linha.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-locking">
+ <title>Locking pessimista</title>
+
+ <para>
+ Não se pretende que os usuários gastam muitas horas se preocupando com suas
estratégias de
+ locking. Geralmente é o bastante para especificar um nível de isolamento para
as conexões
+ JDBC e então deixar simplesmente o banco de dados fazer todo o trabalho.
Entretanto, os
+ usuários avançados podem às vezes desejar obter locks pessimistas exclusivos,
ou re-obter
+ locks no início de uma nova transação.
+ </para>
+
+ <para>
+ O Hibernate usará sempre o mecanismo de lock da base de dados, nunca trava
objetos
+ na memória!
+ </para>
+
+ <para>
+ A classe <literal>LockMode</literal> define os diferentes níveis
de lock que o Hibernate
+ pode adquirir. Um lock é obtido pelos seguintes mecanismos:
+
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>LockMode.WRITE</literal> é adquirido
automaticamente quando o Hibernate atualiza
+ ou insere uma linha.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE</literal> pode ser adquirido
explicitamente pelo usuário
+ usando <literal>SELECT ... FOR UPDATE</literal> em um
banco de dados que suporte
+ esse sintaxe.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE_NOWAIT</literal> pode ser
adquirido explicitamente pelo usuário
+ usando <literal>SELECT ... FOR UPDATE NOWAIT</literal> no
Oracle.
+
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.READ</literal> é adquirido
automaticamente quando o Hibernate lê
+ dados em um nível Repeatable Read ou Serializable isolation. Pode ser
readquirido
+ explicitamente pelo usuário.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.NONE</literal> representa a ausência do lock.
Todos os objetos mudam para
+ esse estado de lock no final da <literal>Transaction</literal>.
Objetos associados com a sessão
+ através do método <literal>update()</literal> ou
<literal>saveOrUpdate()</literal> também são
+ inicializados com esse lock mode.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ O lock obtido "explicitamente pelo usuário" se dá em uma das
seguintes maneiras:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Uma chamada a <literal>Session.load()</literal>,
especificando
+ o <literal>LockMode</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Uma chamada a <literal>Session.lock()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Uma chamada a <literal>Query.setLockMode()</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Se uma <literal>Session.load()</literal> é invocada com
<literal>UPGRADE</literal> ou
+ <literal>UPGRADE_NOWAIT</literal>, e o objeto requisitado ainda
não foi carregado
+ pela sessão, o objeto é carregado usando <literal>SELECT ... FOR
UPDATE</literal>.
+ Se <literal>load()</literal> for chamado para um objeto que já
foi carregado
+ com um lock menos restritivo que o novo lock solicitado, o Hibernate invoca o
+ método <literal>lock()</literal> para aquele objeto.
+ </para>
+
+ <para>
+ O método <literal>Session.lock()</literal> executa uma
verificação no número da versão
+ se o modo de lock especificado for <literal>READ</literal>,
<literal>UPGRADE</literal> ou
+ <literal>UPGRADE_NOWAIT</literal>.. (No caso do
<literal>UPGRADE</literal> ou
+ <literal>UPGRADE_NOWAIT</literal>, é usado <literal>SELECT
... FOR UPDATE</literal>.)
+ </para>
+
+ <para>
+ Se o banco de dados não suportar o lock mode solicitado, o Hibernate vai usar
um modo
+ alternativo apropriado (ao invés de lançar uma exceção). Isso garante que a
aplicação
+ vai ser portável.
+ </para>
+
+ </sect1>
+
+ <sect1 id="transactions-connection-release">
+ <title>Modos de liberar a Connection</title>
+
+ <para>
+ O comportamento legado do Hibernate (2.x) em consideração ao gerenciamento da
conexão
+ via JDBC fez com que a <literal>Session</literal> precisasse
obter uma conexão
+ quando ela precisasse pela primeira vez e depois manter a conexão enquanto
+ a sessão não fosse fechada. O Hibernate 3.x introduz a idéia de modos de
liberar a
+ sessão, para informar a sessão a forma como deve manusear a sua conexão JDBC.
+ Veja que essa discussão só é pertinente para conexões fornecidas com um
+ <literal>ConnectionProvider</literal> configurado; conexões
fornecidas pelo usuário
+ estão fora do escopo dessa discussão. Os diferentes modos de liberação estão
definidos
+ pelos valores da enumeração
+ <literal>org.hibernate.ConnectionReleaseMode</literal>:
+
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ON_CLOSE</literal> - essencialmente é o modo
legado descrito acima. A sessão
+ do Hibernate obtêm a conexão quando precisar executar alguma operação
JDBC pela
+ primeira vez e mantem enquanto a conexão não for fechada.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_TRANSACTION</literal> – informa que a
conexão deve ser
+ liberada após a conclusão de uma
<literal>org.hibernate.Transaction</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>AFTER_STATEMENT</literal> (também conhecida com
liberação agressiva) – informa
+ que a conexão deve ser liberada após a execução de cada statement. A
liberação agressiva
+ não ocorre se o statement deixa pra trás algum recurso aberto
associado com a sessão
+ obtida; atualmente, a única situação em que isso é possível é com o
uso de
+ <literal>org.hibernate.ScrollableResults</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ O parâmetro de configuração
<literal>hibernate.connection.release_mode</literal> é usado
+ para especificar qual modo de liberação deve ser usado. Opções disponíveis:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>auto</literal> (padrão) – essa opção delega ao
modo de liberação retornado pelo
+ método
<literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()</literal>.
+ Para JTATransactionFactory, ele retorna
ConnectionReleaseMode.AFTER_STATEMENT; para
+ JDBCTransactionFactory, ele retorna
ConnectionReleaseMode.AFTER_TRANSACTION.
+ Raramente é uma boa idéia alterar padrão, como frequencia ao se fazer
isso temos falhas
+ que parecem bugs e/ou suposições inválidas no código do usuário.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>on_close</literal> - indica o uso da
ConnectionReleaseMode.ON_CLOSE. Essa opção
+ foi deixada para manter a compatibilidade, mas seu uso é fortemente
desencorajado.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_transaction</literal> – indica o uso da
ConnectionReleaseMode.AFTER_TRANSACTION.
+ Essa opção nada deve ser usada com ambientes JTA. Também note que no
caso da
+ ConnectionReleaseMode.AFTER_TRANSACTION, se a sessão foi colocada no
modo auto-commit a
+ conexão vai ser liberada de forma similar ao modo AFTER_STATEMENT.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>after_statement</literal> – indica o uso
ConnectionReleaseMode.AFTER_STATEMENT.
+ Adicionalmente, o <literal>ConnectionProvider</literal>
configurado é consultado para
+ verificar se suporta essa configuração
((<literal>supportsAggressiveRelease()</literal>).
+ Se não suportar, o modo de liberação é redefinido como
ConnectionRelease-Mode.AFTER_TRANSACTION.
+ Essa configuração só é segura em ambientes onde podemos readquirir a
mesma conexão JDBC
+ toda vez que o método
<literal>ConnectionProvider.getConnection()</literal> for chamado ou
+ em um ambiente auto-commit onde não importa se nós recuperamos a
mesma conexão.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+</chapter>
+
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/tutorial.xml
===================================================================
--- core/trunk/documentation/manual/pt-BR/src/main/docbook/content/tutorial.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++ core/trunk/documentation/manual/pt-BR/src/main/docbook/content/tutorial.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,1533 +1,1550 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="tutorial">
- <title>Introdução ao Hibernate</title>
-
- <sect1 id="tutorial-intro" revision="1">
- <title>Prefácio</title>
-
- <para>
- Este capítulo é um tutorial introdutório
para novos usuários do Hibernate. Nós iniciaremos com uma simples linha de
comando em uma aplicação usando uma base de dados em
memória tornando isto um passo de fácil de compreender.
- </para>
-
- <para>
- Este tutorial é voltado para novos usuários do Hibernate, mas
requer um conhecimento de Java e SQL. Este tutorial é baseado no tutorial de
Michael Gloegl, as bibliotecas Third Party foram nomeadas para JDK 1.4 e 5.0. Você pode
precisar de outras bibliotecas para JDK 1.3.
- </para>
-
- <para>
- O código fonte para o tutorial está incluído no diretório da distribuição
- <literal>doc/reference/tutorial/</literal>.
- </para>
-
- </sect1>
-
- <sect1 id="tutorial-firstapp" revision="2">
- <title>Parte 1 – A primeira aplicação Hibernate</title>
-
- <para>
- Primeiro, iremos criar uma simples aplicação Hibernate
baseada em console. Usaremos uma base de dados Java (HSQL DB), então
não teremos que instalar nenhum servidor de base de dados.
- </para>
-
- <para>
- Vamos supor que precisemos de uma aplicação com um
banco de dados pequeno que possa armazenar e atender os eventos que queremos, e as
informaççes sobre os hosts destes eventos.
- </para>
-
- <para>
- A primeira coisa que devemos fazer é configurar nosso
diretório de desenvolvimento,
- e colocar todas as bibliotecas Java que precisamos dentro dele.
Faça o download da
- distribuição do Hibernate no site do Hibernate.
Descompacte o pacote e coloque todas
- as bibliotecas necessárias encontradas no diretório
<literal>/lib</literal>, dentro do
- diretório <literal>/lib</literal> do seu novo projeto.
Você deverá ter algo parecido
- com isso:
- </para>
-
- <programlisting><![CDATA[.
-+lib
- antlr.jar
- cglib.jar
- asm.jar
- asm-attrs.jars
- commons-collections.jar
- commons-logging.jar
- hibernate3.jar
- jta.jar
- dom4j.jar
- log4j.jar ]]></programlisting>
-
- <para>
- Esta é a configuração mínima
requerida das bibliotecas (observe que também foi copiado
- o hibernate3.jar da pasta principal do Hibernate) para o Hibernate
<emphasis>na hora do desenvolvimento</emphasis>. O Hibernate permite que você
utilize mais ou menos bibliotecas.
- Veja o arquivo <literal>README.txt</literal> no
diretório <literal>lib/</literal> da
distribuição
- do Hibernate para maiores informaççes sobre bibliotecas
requeridas e opcionais.
- (Atualmente, a biblioteca Log4j não é requerida, mas
é preferida por muitos desenvolvedores.)
- </para>
-
- <para>
- Agora, iremos criar uma classe que representa o evento que queremos armazenar
na base de dados..
- </para>
-
- <sect2 id="tutorial-firstapp-firstclass" revision="1">
- <title>A primeira Classe</title>
-
- <para>
- Nossa primeira classe de persistência é uma simples classe JavaBean com
algumas propriedades:
- </para>
-
- <programlisting><![CDATA[package events;
-
-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;
- }
-}]]></programlisting>
-
- <para>
- Você pode ver que esta classe usa o padrão JavaBean para o nomeamento
convencional da propriedade getter e dos métodos setter, como também a visibilidade
private 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. O construtor sem argumento é requerido para instanciar um
objeto desta classe com a reflexão.
- </para>
-
- <para>
- A propriedade <literal>id</literal> 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
- (esp. aplicações web) precisam destinguir os objetos pelo identificador,
então você deverá
- considerar esta, uma característica em lugar de uma limitação. Porém, nós
normalmente não
- manipulamos a identidade de um objeto, consequentemente o método setter
deverá ser privado.
- O Hibernate somente nomeará os identificadores quando um objeto for
salvo. Você pode ver como
- o Hibernate pode acessar métodos públicos, privados, e protegidos, como
também campos
- (públicos, privados, protegidos) diretamente. A escolha está até você, e
você pode combinar
- isso para adaptar seu projeto de aplicação
- </para>
-
- <para>
- O construtor sem argumentos é um requerimento para todas as classes
persistentes;
- O Hibernate tem que 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
- </para>
-
- <para>
- Coloque este fonte Java no diretório chamado
<literal>src</literal> na pasta de desenvolvimento,
- e em seu pacote correto. O diretório deverá ser parecido como este:
- </para>
-
- <programlisting><![CDATA[.
-+lib
- <Hibernate and third-party libraries>
-+src
- +events
- Event.java]]></programlisting>
-
- <para>
- No próximo passo, iremos falar sobre as classes de persistência do
Hibernate..
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-firstapp-mapping" revision="1">
- <title>O mapeamento do arquivo</title>
-
- <para>
- O Hibernate precisa saber como carregar e armazenar objetos da classe de
- persistência. Isto será onde 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.
- </para>
-
- <para>
- A estrutura básica de um arquivo de mapeamento é parecida com:
- </para>
-
- <programlisting><![CDATA[<?xml version="1.0"?>
-<!DOCTYPE hibernate-mapping PUBLIC
- "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
-
-<hibernate-mapping>
-[...]
-</hibernate-mapping>]]></programlisting>
-
- <para>
- Note que o Hibernate DTD é muito sofisticado. Você pode usar isso para
auto-conclusão
- no mapeamento XML dos elementos e atributos no seu editor ou IDE. Você
também pode
- abrir o arquivo DTD no seu editor – é a maneira mais fácil de ter uma
visão geral
- de todos os elementos e atributos 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 do
diretório
- da aplicação (classpath). O arquivo DTD está incluído no
<literal>hibernate3.jar</literal> como
- também no diretório <literal>src/</literal> da distribuição
do Hibernate.
- </para>
-
- <para>
- Nós omitiremos a declaração do DTD nos exemplos futuros para encurtar o
código. Isto, é claro, não é opcional.
- </para>
-
- <para>
- Entre os dois tags <literal>hibernate-mapping</literal>,
inclua um elemento <literal>class</literal>.
- 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
- </para>
-
- <programlisting><![CDATA[<hibernate-mapping>
-
- <class name="events.Event" table="EVENTS">
-
- </class>
-
-</hibernate-mapping>]]></programlisting>
-
- <para>
- Mais adiante iremos dizer ao Hibernate como fazer para persistir e
carregar objetos da classe
- <literal>Event</literal> da tabela
<literal>EVENTS</literal>, cada instancia 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, nós não iremos se
importar com esta propriedade
- identificadora, nós iremos configurar uma estratégia de geração de id’s
para uma chave primária
- de uma surrogate key:
- </para>
-
- <programlisting><![CDATA[<hibernate-mapping>
-
- <class name="events.Event" table="EVENTS">
- <id name="id" column="EVENT_ID">
- <generator class="native"/>
- </id>
- </class>
-
-</hibernate-mapping>]]></programlisting>
-
- <para>
- O elemento <literal>id</literal> é a declaração da
propriedade identificadora,
- o <literal>name="id"</literal> declara o nome da
propriedade Java –
- o Hibernate irá usar os métodos getter e setter para acessar a
propriedade.
- O atributo da coluna informa ao Hibernate qual coluna da tabela
<literal>EVENTS</literal> nós
- iremos usar como chave primária. O elemento
<literal>generator</literal> especifica
- a estratégia de geração do identificador, neste caso usaremos
<literal>native</literal>, que
- escolhe a melhor estratégia dependendo da base de dados (dialeto)
configurada.
- O Hibernate suporta a base de dados gerada, globalmente única, bem como a
atribuição
- aos identificadores da aplicação (ou toda estratégia escrita para uma
extensão).
- </para>
-
- <para>
- Finalmente incluiremos as declarações para as propriedades persistentes
da classe
- no arquivo mapeado. Por default, nenhuma das propriedades da classe é
considerada persistente:
- </para>
-
- <programlisting><![CDATA[
-<hibernate-mapping>
-
- <class name="events.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>]]></programlisting>
-
- <para>
- Da mesma maneira que com o elemento <literal>id</literal>, o
atributo <literal>name</literal> do elemento
- <literal>property</literal> informa ao Hibernate qual método
getter e setter deverá usar.
- Assim, neste caso, o Hibernate irá procurar pelo
<literal>getDate()/setDate()</literal>,
- como também pelo <literal>getTitle()/setTitle()</literal>.
- </para>
-
- <para>
- Porque fazer o mapeamento da propriedade
<literal>date</literal> incluído no
- atributo <literal>column</literal>, e no title não fazer?
- Sem o atributo <literal>column</literal> o Hibernate por
padrão usa o nome
- da propriedade como o nome da coluna. Isto trabalha muito
- bem para o <literal>title</literal>. Entretanto o
<literal>date</literal> é uma palavra-chave reservada
- na maioria dos bancos de dados, assim nós melhoramos o mapeamentos
- disto com um nome diferente.
- </para>
-
- <para>
- A próxima coisa interessante é que mapemanto do
<literal>title</literal>
- também falta o atributo <literal>type</literal>. O tipo que
declaramos e o uso nos
- arquivos mapeados, não são como você pôde esperar, atributos de dados
Java.
- Eles não são como os tipos de base de dados SQL.
- Esses tipos podem ser chamados de <emphasis>Tipos de mapeamento
Hibernate</emphasis>, 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 <literal>type</literal>
- próprio, caso o tipo do atributo 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 padrão que você espera ou necessita.
- Este é o caso com a propriedade <literal>date</literal>. O
Hibernate não pode saber se a propriedade
- (que é do <literal>java.util.Date</literal>) pode mapear para
uma coluna do tipo <literal>date</literal>
- do SQL, <literal>timestamp</literal>, ou
<literal>time</literal> .
- Nós preservamos a informação cheia de datas e horas pelo mapeamento da
propriedade com um conversor
- <literal>timestamp</literal>.
- </para>
-
- <para>
- Este arquivo de mapeamento deve ser salvo como
<literal>Event.hbm.xml</literal>,
- corretamente no diretório próximo ao arquivo fonte da Classe Java
<literal>Event</literal>.
- O nomeamento dos arquivos de mapeamento podem ser arbitrários, porém o
sufixo
- <literal>hbm.xml</literal> é uma convenção da comunidade dos
desenvolvedores do Hibernate.
- Esta estrutura do diretório deve agora se parecer com isso:
- </para>
-
- <programlisting><![CDATA[.
-+lib
- <Hibernate and third-party libraries>
-+src
- +events
- Event.java
- Event.hbm.xml]]></programlisting>
-
- <para>
- Nós iremos continuar com a configuração principal do Hibernate.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-firstapp-configuration"
revision="2">
- <title>Configuração do Hibernate</title>
-
- <para>
- Agora nós temos uma classe persistente e este arquivo de mapeamento no
lugar.
- Está na hora de configurar o Hibernate. Antes de fazermos isso, iremos
precisar de uma base de dados.
- O HSQL DB, um SQL DBMS feito em java, pode ser baixado através do site do
HSQL
DB(http://hsqldb.org/).
- Atualmente, você só precisa baixar o
<literal>hsqldb.jar</literal>.
- Coloque este arquivo no diretório da pasta de desenvolvimento
<literal>lib/</literal>.
- </para>
-
- <para>
- Crie um diretório chamado <literal>data</literal> no
diretório root de desenvolvimento –
- Isto será onde o HSQL DB irá armazenar arquivos de dados. Agora iremos
iniciar o banco de dados
- executando <literal>java -classpath ../lib/hsqldb.jar
org.hsqldb.Server</literal> neste diretório de dados.
- Você pode ver ele iniciando e conectando ao socket TCP/IP, isto será onde
nossa aplicação irá se
- conectar depois. Se você deseja iniciar uma nova base de dados durante
este tutorial,
- finalize o HSQL DB(pressionando o <literal>CTRL + C</literal>
na janela), delete todos os
- arquivos no diretório <literal>data/</literal>, e inicie o
HSQL BD novamente.
- </para>
-
- <para>
- O Hibernate é uma camada na sua aplicação na qual se conecta com a base
de dados, para isso
- necessita de informação da conexão. As conexões são feitas através de um
pool de conexão JDBC,
- na qual teremos que configurar. A distribuição do Hibernate contém
diversas ferramentas de pooling
- da conexão JDBC de fonte aberta, mas iremos usar o pool de conexão
interna para este tutorial.
- Note que você tem que copiar a biblioteca necessária em seu classpath e
use configurações
- diferentes para pooling de conexão caso você deseje utilizar um software
de pooling JDBC terceirizado
- para qualidade de produção.
- </para>
-
- <para>
- Para as configurações do Hibernate, nós podemos usar um arquivo simples
<literal>hibernate.properties</literal>,
- um arquivo mais ligeiramente sofisticado
<literal>hibernate.cfg.xml</literal> ou até mesmo uma
- instalação programática completa. A maioria dos usuários preferem
utilizar o arquivo de configuração XML
- </para>
-
- <programlisting><![CDATA[<?xml version='1.0'
encoding='utf-8'?>
-<!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://hibernate.sourceforge.net/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">create</property>
-
- <mapping resource="events/Event.hbm.xml"/>
-
- </session-factory>
-
-</hibernate-configuration>]]></programlisting>
-
- <para>
- Note que esta configuração XML usa um diferente DTD. Nós configuraremos
- as <literal>SessionFactory</literal> do Hibernate – uma
factory global responsável
- por uma base de dedados particular. Se você tiver diversas bases de
dados,
- use diversas configurações
<literal><session-factory></literal>, geralmente
- em diversos arquivos de configuração (para uma partida mais fácil).
- </para>
-
- <para>
- As primeiras quatro <literal>propriedades</literal> do
elemento contém a configuração
- necessária para a conexão ao JDBC. A propriedade
<literal>propriedade</literal> dialect
- do elemento especifica a variante particular do SQL que o Hibernate gera.
- O gerenciamento automático de sessão do Hibernate para contextos de
persistência
- estará disponível em breve. A opção
<literal>hbm2ddl.auto</literal> habilita a geração
- automática de schemas da base de dados – diretamente na base de dados.
- Isto também pode ser naturalmente desligado (removendo a opção de
configuração) ou redirecionando
- para um arquivo com ajuda do <literal>SchemaExport</literal>
nas tarefas do Ant.
- Finalmente, iremos adicionar os arquivos das classes de persistência
mapeadas na configuração.
- </para>
-
- <para>
- Copie este arquivo no diretório fonte, assim isto irá terminar na raiz
(root) do
- classpath. O Hibernate automaticamente procura por um arquivo chamado
- <literal>hibernate.cfg.xml</literal> na raiz do classpath, no
startup.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-firstapp-ant" revision="1">
- <title>Construindo com o Ant</title>
-
- <para>
- Nos iremos, agora, construir o tutorial com Ant. Você ira precisar o Ant
instalado –
- se encontra disponível <ulink
url="http://ant.apache.org/bindownload.cgi">na página de download do
Ant</ulink>.
- Como instalar o Ant, não será abordado aqui. Caso tenha alguma dúvida,
por favor,
- vá ao <ulink
url="http://ant.apache.org/manual/index.html">Ant manual</ulink>.
- Depois que tiver instalado o Ant, podemos começar a criar o arquivo de
construção <literal>build.xml</literal>.
- Este arquivo será chamado de <literal>build.xml</literal> e
posto diretamente no diretório de desenvolvimento.
- </para>
-
- <para>
- Um arquivo básico de build, se parece com isto:
- </para>
-
- <programlisting><![CDATA[<project
name="hibernate-tutorial" default="compile">
-
- <property name="sourcedir" value="${basedir}/src"/>
- <property name="targetdir" value="${basedir}/bin"/>
- <property name="librarydir" value="${basedir}/lib"/>
-
- <path id="libraries">
- <fileset dir="${librarydir}">
- <include name="*.jar"/>
- </fileset>
- </path>
-
- <target name="clean">
- <delete dir="${targetdir}"/>
- <mkdir dir="${targetdir}"/>
- </target>
-
- <target name="compile" depends="clean, copy-resources">
- <javac srcdir="${sourcedir}"
- destdir="${targetdir}"
- classpathref="libraries"/>
- </target>
-
- <target name="copy-resources">
- <copy todir="${targetdir}">
- <fileset dir="${sourcedir}">
- <exclude name="**/*.java"/>
- </fileset>
- </copy>
- </target>
-
-</project>]]></programlisting>
-
- <para>
- Isto irá avisar ao Ant para adicionar todos os arquivos no diretório lib
terminando com
- <literal>.jar</literal>, para o classpath usado para
compilação. Irá também copiar todos os
- arquivos não-java para o diretório alvo (arquivos de configuração,
mapeamento). Se você rodar
- o ant agora, deverá ter esta saída.
- </para>
-
- <programlisting><![CDATA[C:\hibernateTutorial\>ant
-Buildfile: build.xml
-
-copy-resources:
- [copy] Copying 2 files to C:\hibernateTutorial\bin
-
-compile:
- [javac] Compiling 1 source file to C:\hibernateTutorial\bin
-
-BUILD SUCCESSFUL
-Total time: 1 second ]]></programlisting>
-
- </sect2>
-
- <sect2 id="tutorial-firstapp-helpers" revision="3">
- <title>Startup and helpers</title>
-
- <para>
- É hora de carregar e arquivar alguns objetos
<literal>Event</literal>, mas primeiro
- nós temos de completar o setup com algum código de infraestrutura. Este
startup
- inclui a construção de um objeto
<literal>SessionFactory</literal> global e armazenar
- isto em algum lugar de fácil acesso para o código da aplicação.
- Uma <literal>SessionFactory</literal> pode abrir novas
<literal>Session</literal>'s.
- Uma <literal>Session</literal> representa uma unidade
single-theaded do trabalho, a
- <literal>SessionFactory</literal> é um objeto global
thread-safe, instanciado uma vez.
- </para>
-
- <para>
- Nos iremos criar uma classe de ajuda
<literal>HibernateUtil</literal>, que toma
- conta do startup e faz acesso a uma
<literal>SessionFactory</literal> conveniente.
- Vamos dar uma olhada na implementação:
- </para>
-
- <programlisting><![CDATA[package util;
-
-import org.hibernate.*;
-import org.hibernate.cfg.*;
-
-public class HibernateUtil {
-
- private static final SessionFactory sessionFactory;
-
- static {
- try {
- // Create the SessionFactory from hibernate.cfg.xml
- sessionFactory = 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;
- }
-
-}]]></programlisting>
-
- <para>
- Esta classe não só produz a global
<literal>SessionFactory</literal> no seu static initializer
- (chamado uma vez pela JVM quando a classe é carregada), mas também
esconde o fato
- de que isto usa um static singleton. Ela pode muito bem, enxergar a
- <literal>SessionFactory</literal> do JNDI em um application
server.
- </para>
-
- <para>
- Se você der à <literal>SessionFactory</literal> um nome, no
seu arquivo de configuração.
- O Hibernate irá, de fato, tentar uni-lo ao JNDI depois que estiver
construído.
- Para evitar este completamente este código, você também poderia usar JMX
deployment
- e deixar o contêiner JMX capaz, instanciar e unir um
<literal>HibernateService</literal>
- no JNDI. Essas opções avançadas são discutidas no documento de referência
do Hibernate.
- </para>
-
- <para>
- Coloque o <literal>HibernateUtil.java</literal> no diretório
de arquivos
- de desenvolvimento(source), em um pacote após o
<literal>events</literal>:
- </para>
-
- <programlisting><![CDATA[.
-+lib
- <Hibernate and third-party libraries>
-+src
- +events
- Event.java
- Event.hbm.xml
- +util
- HibernateUtil.java
- hibernate.cfg.xml
-+data
-build.xml]]></programlisting>
-
- <para>
- Novamente, isto deve compilar sem problemas. Finalmente, nós precisamos
configurar
- um sistema de logging – o Hibernate usa commons logging e deixa você
escolher entre o
- Log4j e o logging do JDK 1.4 . A maioria dos desenvolvedores preferem o
Log4j: copie
- <literal>log4j.properties</literal> da distribuição do
Hibernate (está no diretório
- <literal>etc/</literal>), para seu diretório
<literal>src</literal>,
- depois vá em hibernate.cfg.xml. Dê uma olhada no exemplo de configuração
e mude as
- configurações se você quizer ter uma saída mais detalhada. Por default,
apenas as
- mensagems de startup e shwwn do Hibernate é mostrada no stdout.
- </para>
-
- <para>
- O tutorial de infra-estrutura está completo - e nós já estamos preparados
para algum
- trabalho de verdade com o Hibernate.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-firstapp-workingpersistence"
revision="4">
- <title>Carregando e salvando objetos</title>
-
- <para>
- Finalmente, nós podemos usar o Hibernate para carregar e armazenar
objetos.
- Nós escrevemos uma classe <literal>EventManager</literal> com
um método main():
- </para>
-
- <programlisting><![CDATA[package events;
-import org.hibernate.Session;
-
-import java.util.Date;
-
-import 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();
- }
-
-}]]></programlisting>
-
- <para>
- Nós criamos um novo objeto <literal>Event</literal>, e
passamos para o Hibernate.
- O Hibernate sabe como tomar conta do SQL e executa
<literal>INSERT</literal>s
- no banco de dados. Vamos dar uma olhada na
<literal>Session</literal> e no
- código <literal>Transaction</literal>-handling antes de
executarmos.
- </para>
-
- <para>
- Um <literal>Session</literal> é uma unidade simples de
trabalho. Por agora nós
- iremos pegar coisas simples e assumir uma granularidade de um-pra-um
entre uma
- <literal>Session</literal> do Hibernate e uma transação de
banco de dados.
- Para proteger nosso código de um atual sistema subjacente de transação
(nesse
- caso puro JDBC, mas também poderia rodar com JTA), nos usamos a API
- <literal>Transaction</literal>, que está disponível na
<literal>Session</literal> do Hibernate.
- </para>
-
- <para>
- O que a <literal>sessionFactory.getCurrentSession()</literal>
faz? Primeiro, você pode
- chamar quantas vezes e de onde quiser, uma vez você recebe sua
<literal>SessionFactory</literal>
- (fácil graças ao <literal>HibernateUtil</literal>). O método
<literal>getCurrentSession()</literal>
- sempre retorna a unidade de trabalho "corrente". Lembra de que
nós mudamos a opção
- de configuração desse mecanismo para thread no
<literal>hibernate.cfg.xml</literal>? Daqui em
- diante, o escopo da unidade de trabalho corrente é a thread Java
- corrente que executa nossa aplicação. Entretanto, esta não é toda a
verdade. Uma
- <literal>Session</literal> começa quando é primeiramente
necessária, quando é feita a
- primeira chamada à <literal>getCurrentSession()</literal>. É
então limitado pelo Hibernate
- para thread corrente. Quando a transação termina, tanto com commit quanto
rollback,
- o Hibernate também desune a <literal>Session</literal> da
thread e fecha isso pra você.
- Se você chamar <literal>getCurrentSession()</literal>
novamente, você receberá uma nova
- <literal>Session</literal> e pode começar uma nova unidade de
trabalho. Esse modelo de
- programação de limite de thread
<emphasis>thread-bound</emphasis>, é o modo mais popular
- de se usar o Hibernate.
- </para>
-
- <para>
- Dê uma olhada no <xref linkend="transactions"/> para mais
informações a
- respeito de manipulação de transação e demarcação. Nós também pulamos
qualquer
- manipulação de erro e rollback no exemplo anterior.
- </para>
-
- <para>
- Para executar esta primeira rotina, nos teremos que adicionar um ponto de
chamada
- para o arquivo de build do Ant:
- </para>
-
- <programlisting><![CDATA[<target name="run"
depends="compile">
- <java fork="true" classname="events.EventManager"
classpathref="libraries">
- <classpath path="${targetdir}"/>
- <arg value="${action}"/>
- </java>
-</target>]]></programlisting>
-
- <para>
- O valor do argumento <literal>action</literal>, é setado na
linha de comando quando chamando esse ponto:
- </para>
-
- <programlisting><![CDATA[C:\hibernateTutorial\>ant run
-Daction=store]]></programlisting>
-
- <para>
- Você deverá ver, após a compilação, o startup do Hibernate e, dependendo
da sua
- configuração, muito log de saída. No final você verá a seguinte linha:
- </para>
-
- <programlisting><![CDATA[[java] Hibernate: insert into EVENTS
(EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
-
- <para>
- Este é o <literal>INSERT</literal> executado pelo Hibernate,
os pontos de interrogação
- representam parêmetros de união do JDBC. Para ver os valores
substituídos, ou para diminuir a
- verbalidade do log, check seu
l<literal>log4j.properties</literal>.
- </para>
-
- <para>
- Agora nós gostaríamos de listar os eventos arquivados, então nós
adicionamos uma
- opção para o método main:
- </para>
-
- <programlisting><![CDATA[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());
- }
-}]]></programlisting>
-
- <para>
- Nos também adicionamos um novo <literal>método
listEvents()</literal>:
- </para>
-
- <programlisting><![CDATA[private List listEvents() {
-
- Session session = HibernateUtil.getSessionFactory().getCurrentSession();
-
- session.beginTransaction();
-
- List result = session.createQuery("from Event").list();
-
- session.getTransaction().commit();
-
- return result;
-}]]></programlisting>
-
- <para>
- O que nós fazemos aqui, é usar uma query HQL (Hibernate Query Language),
- para carregar todos os objetos <literal>Event</literal>
exitentes no banco de dados.
- O Hibernate irá gerar o SQL apropriado, enviar para o banco de dados e
popular objetos
- <literal>Event</literal> com os dados. Você pode criar
queries mais complexas com
- HQL, claro.
- </para>
-
- <para>
- Agora, para executar e testar tudo isso, siga os passos a seguir:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- Execute <literal>ant run -Daction=store</literal>
para armazenar algo no banco de dados
- e, claro, gerar o esquema do banco de dados antes pelo hbm2ddl.
- </para>
- </listitem>
- <listitem>
- <para>
- Agora desabilite hbm2ddl comentando a propriedade no seu arquivo
<literal>hibernate.cfg.xml</literal>.
- Normalmente só se deixa habilitado em teste unitários contínuos,
mas outra carga de hbm2ddl
- pode <emphasis>remover</emphasis> tudo que você já
tenha arquivado. Sa configuração
- <literal>create</literal>, atualmente são traduzidas
para "apague todas as tabelas do esquema,
- então recrie todas quando a SessionFactory estiver pronta".
- </para>
- </listitem>
- </itemizedlist>
-
- <para>
- Se você agora chamar o Ant com
<literal>-Daction=list</literal>, você deverá ver os
- eventos que você acabou de criar. Você pode também chamar a ação
<literal>store</literal>
- mais algumas vezes.
- </para>
-
- <para>
- Nota: A maioria dos novos usuários do Hibernate falha nesse ponto e nós
regularmente, vemos
- questões sobre mensagens de erro de <emphasis>tabela não encontrada
</emphasis> .
- Entretanto, se você seguir os passos marcados acima, você não terá esse
problema,
- com o hbm2ddl criando o esquema do banco de dados na primeira execução, e
restarts
- subsequentes da aplicação irão usar este esquema. Se você mudar o
mapeamento e/ou
- o esquema do banco de dados, terá de re-habilitar o hbm2ddl mais uma
vez.
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="tutorial-associations">
- <title>Part 2 - Mapeando associações</title>
-
- <para>
- Nós mapeamos uma classe de entidade de persistência para uma tabela. Agora
vamos continuar
- e adicionar algumas associações de classe. Primeiro nos iremos adicionar
pessoas a nossa aplicação,
- e armazenar os eventos de que elas participam.
- </para>
-
- <sect2 id="tutorial-associations-mappinguser"
revision="1">
- <title>Mapeando a classe Person</title>
-
- <para>
- O primeiro código da classe <literal>Person</literal> é
simples:
- </para>
-
- <programlisting><![CDATA[package events;
-
-public class Person {
-
- private Long id;
- private int age;
- private String firstname;
- private String lastname;
-
- public Person() {}
-
- // Accessor methods for all properties, private setter for 'id'
-
-}]]></programlisting>
-
- <para>
- Crie um novo arquivo de mapeamento, chamado
<literal>Person.hbm.xml</literal> (não
- esqueça a referencia ao DTD no topo)
- </para>
-
- <programlisting><![CDATA[<hibernate-mapping>
-
- <class name="events.Person" table="PERSON">
- <id name="id" column="PERSON_ID">
- <generator class="native"/>
- </id>
- <property name="age"/>
- <property name="firstname"/>
- <property name="lastname"/>
- </class>
-
-</hibernate-mapping>]]></programlisting>
-
- <para>
- Finalmente, adicione o novo mapeamento a configuração do Hibernate:
- </para>
-
- <programlisting><![CDATA[<mapping
resource="events/Event.hbm.xml"/>
-<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
-
- <para>
- Nos iremos agora criar uma associação entre estas duas entidades.
Obviamente,
- pessoas (Person) podem participar de eventos, e eventos possuem
participantes.
- As questões de design com que teremos de lidar são: direcionalidade,
multiplicidade e
- comportamento de coleção.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-associations-unidirset"
revision="3">
- <title>Uma associação Set-based unidirectional</title>
-
- <para>
- Nos iremos adicionar uma coleção de eventos na classe
<literal>Person</literal>. Desse jeito
- poderemos navegar pelos eventos de uma pessoa em particular, sem executar
uma query explicitamente –
- apenas chamando <literal>aPerson.getEvents()</literal>. Nos
usaremos uma coleção Java, um
- <literal>Set</literal>, porquê a coleção não conterá
elementos duplicados e a ordem não é
- relevante para nós.
- </para>
-
- <para>
- Vamos escrever o código para isto nas classes Java e então mapear:
- </para>
-
- <programlisting><![CDATA[public class Person {
-
- private Set events = new HashSet();
-
- public Set getEvents() {
- return events;
- }
-
- public void setEvents(Set events) {
- this.events = events;
- }
-}]]></programlisting>
-
- <para>
- 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
<literal>Event</literal>, se quisermos
- ser capaz de navegar bidirecionalmente, i.e. um -
<literal>anEvent.getParticipants()</literal>.
- Isto não é necessário, de perspectiva funcional. Você poderia sempre
executar uma query explicita
- que retornasse 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" valores em ambos
- os lados, nós chamamos isto uma associação
<emphasis>muitos-para-muitos</emphasis>. Daqui pra frente,
- nos usaremos o mapeamento muitos-para-muitos do Hibernate:
- </para>
-
- <programlisting><![CDATA[<class name="events.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="events.Event"/>
- </set>
-
-</class>]]></programlisting>
-
- <para>
- O Hibernate suporta todo tipo de mapeamento de coleção , sendo um
<literal><set></literal> mais comum.
- Para uma associação muitos-para-muitos (ou relacionamento de entidade
<emphasis>n:m</emphasis> ),
- uma tabela de associação é necessária. Cada linha nessa tabela representa
um link entre uma pessoa e um
- evento. O nome da tabela é configurado com o atributo
<literal>table</literal> do elemento
- <literal>set</literal>. O nome da coluna identificadora na
associção, peloo lado da pessoa,
- é definido com o elemento
<literal><key></literal> , o nome da coluna pelo lado dos
eventos,
- e definido com o atributo <literal>column</literal> do
<literal><many-to-many></literal>.
- 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).
- </para>
-
- <para>
- O esquema de mapeamento para o banco de dados está a seguir:
- </para>
-
- <programlisting><![CDATA[
- _____________ __________________
- | | | | _____________
- | EVENTS | | PERSON_EVENT | | |
- |_____________| |__________________| | PERSON |
- | | | | |_____________|
- | *EVENT_ID | <--> | *EVENT_ID | | |
- | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID |
- | TITLE | |__________________| | AGE |
- |_____________| | FIRSTNAME |
- | LASTNAME |
- |_____________|
- ]]></programlisting>
-
- </sect2>
-
- <sect2 id="tutorial-associations-working"
revision="1">
- <title>Trabalhando a associação</title>
-
- <para>
- Vamos trazer juntos algumas pessoas e eventos em um novo método na classe
<literal>EventManager</literal>::
- </para>
-
- <programlisting><![CDATA[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();
-}]]></programlisting>
-
- <para>
- Após carregar um <literal>Person</literal> e um
<literal>Event</literal>, 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 <literal>update()</literal> ou
<literal>save()</literal>, o Hibernate detecta automaticamente
- que a coleção foi modificada e necessita ser atualizada. Isso é chamado
de <emphasis>checagem
- suja automática</emphasis>, e você também pode usá-la modificando o
nome ou a data de qualquer um dos
- seus objetos. Assim que eles estiverem no estado
<emphasis>persistent</emphasis>, ou seja,
- limitado por uma <literal>Session</literal> do Hibernate em
particular (i.e. eles foram carregados ou
- salvos dentro de uma unidade de trabalho), o Hibernate monitora qualquer
alteração e executa o SQL
- em modo de escrita em segundo plano. O processo de sincronização do
estado da memória com o banco de
- dados, geralmente apenas no final de uma unidade de trabalho, é chamado
de <emphasis>flushing</emphasis>.
- No nosso código, a unidade de trabalho termina com o commit da transação
do banco de dados –
- como definido pela opção de configuração da
<literal>thread</literal> da classe
<literal>CurrentSessionContext</literal>.
- </para>
-
- <para>
- Você pode também querer carregar pessoas e eventos em diferentes unidades
de trabalho.
- Ou você modifica um objeto fora de uma
<literal>Session</literal>, quando não se encontra no
- estado persistent (se já esteve neste estado anteriormente, chamamos esse
estado de
- <emphasis>detached</emphasis>). Você pode até mesmo modificar
uma coleção quando esta
- se encontrar no estado detached.
- </para>
-
- <programlisting><![CDATA[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();
-}]]></programlisting>
-
- <para>
- A chamada <literal>update</literal> cria um objeto persistent
novamente, você poderia
- 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 detached 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.
- </para>
-
- <para>
- Bom, isso não foi muito usado na nossa situação, porém, é um importante
conceito que você
- pode aplicar em seus aplicativos. Agora, complete este exercício
adicionando uma nova ação
- ao método main( ) da classe <literal>EventManager</literal>
e chame-o pela linha de comando.
- Se você precisar dos identificadores de uma pessoa ou evento – o método
<literal>save()</literal>
- retorna estes identificadores (você poderá modificar alguns dos métodos
anteriores para retornar aquele
- identificador):
- </para>
-
- <programlisting><![CDATA[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);]]></programlisting>
-
- <para>
- 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
<literal>int</literal> ou uma <literal>String</literal>.
- Nós chamamos essas classes de <emphasis>value
types</emphasis>, e suas instâncias <emphasis>depend</emphasis>
- 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 <literal>firstname</literal>
- mesmo se elas tiverem o mesmo objeto firstname). Naturalmente, os value
types não são apenas encontrados
- dentro da JDK (de fato, em um aplicativo Hibernate todas as classes JDK
são consideradas como value types),
- mas você pode também criar suas classes como, por exemplo,
<literal>Address</literal> ou <literal>MonetaryAmount</literal>.
-
- </para>
-
- <para>
- Você também pode criar uma coleção de value types. Isso é conceitualmente
muito diferente
- de uma coleção de referências para outras entidades, mas em Java parece
ser quase a mesma coisa.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-associations-valuecollections">
- <title>Coleção de valores</title>
-
- <para>
- Nós adicionamos uma coleção de objetos de tipo de valores à entidade
<literal>Person</literal>.
- Nós querermos armazenar endereços de e-mail, para isso utilizamos o tipo
<literal>String</literal>,
- e a coleção novamente será um <literal>Set</literal>:
- </para>
- <programlisting><![CDATA[private Set emailAddresses = new
HashSet();
-
-public Set getEmailAddresses() {
- return emailAddresses;
-}
-
-public void setEmailAddresses(Set emailAddresses) {
- this.emailAddresses = emailAddresses;
-}]]></programlisting>
-
- <para>
- O mapeamento deste <literal>Set</literal>:
- </para>
-
- <programlisting><![CDATA[<set name="emailAddresses"
table="PERSON_EMAIL_ADDR">
- <key column="PERSON_ID"/>
- <element type="string" column="EMAIL_ADDR"/>
-</set>]]></programlisting>
-
- <para>
- A diferença comparada com o mapeamento anterior se encontra na parte
<literal>element</literal>,
- que indica ao Hibernate que a coleção não contém referências à outra
entidade, mas uma coleção de
- elementos do tipo <literal>String</literal> (a tag name em
miniscula indica que se trata de um
- mapeamento do Hibernate para conversão de tipos). Mais uma vez, o
atributo <literal>table</literal>
- do elemento <literal>set</literal> determina o nome da tabela
para a coleção. O elemento
- <literal>key</literal> define o nome da coluna de chave
estrangeira na tabela de coleção.
- O atributo <literal>column</literal> dentro do elemento
<literal>element</literal> define o
- nome da coluna onde os valores da <literal>String</literal>
serão armazenados.
- </para>
-
- <para>
- Dê uma olhada no esquema atualizado:
- </para>
-
- <programlisting><![CDATA[
- _____________ __________________
- | | | | _____________
- | 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 |
- |_____________|
- ]]></programlisting>
-
- <para>
- Você pode observar que a chave primária da tabela da coleção é de na
verdade uma chave composta,
- usando ambas 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.
- </para>
-
- <para>
- Você pode agora tentar adicionar elementos a essa coleção, do mesmo modo
que fizemos
- anteriormente ligando pessoas e eventos. È o mesmo código em Java:
- </para>
-
- <programlisting><![CDATA[private void addEmailToPerson(Long
personId, String emailAddress) {
-
- Session session = HibernateUtil.getSessionFactory().getCurrentSession();
- session.beginTransaction();
-
- Person aPerson = (Person) session.load(Person.class, personId);
-
- // The getEmailAddresses() might trigger a lazy load of the collection
- aPerson.getEmailAddresses().add(emailAddress);
-
- session.getTransaction().commit();
-}]]></programlisting>
-
- <para>
- This time we didnt' use a <emphasis>fetch</emphasis>
query to initialize the collection.
- Hence, the call to its getter method will trigger an additional select to
initialize
- it, so we can add an element to it. Monitor the SQL log and try to
optimize this with
- an eager fetch.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-associations-bidirectional"
revision="1">
- <title>Associações bidirecionais</title>
-
- <para>
- Agora iremos mapear uma associação bidirecional – fazendo a associação
entre pessoas e
- eventos, de ambos os lados, em Java. Logicamente, o esquema do banco de
dados não muda,
- nós continuamos tendo multiplicidades muitos-para-muitos. Um banco de
dados é mais flexível do que
- uma linguagem de programação para redes, ele não precisa de nenhuma
direção de navegação – os
- dados podem ser acessados em qualquer caminho possível.
- </para>
-
- <para>
- Primeiramente, adicione uma coleção de participantes à classe
<literal>Event</literal>:
- </para>
-
- <programlisting><![CDATA[private Set participants = new HashSet();
-
-public Set getParticipants() {
- return participants;
-}
-
-public void setParticipants(Set participants) {
- this.participants = participants;
-}]]></programlisting>
-
- <para>
- Agora mapeie este lado da associação em
<literal>Event.hbm.xml</literal>.
- </para>
-
- <programlisting><![CDATA[<set name="participants"
table="PERSON_EVENT" inverse="true">
- <key column="EVENT_ID"/>
- <many-to-many column="PERSON_ID" class="events.Person"/>
-</set>]]></programlisting>
-
- <para>
- Como você pode ver, esses é uma mapeamento normal usando
<literal>set</literal> em ambos documenentos
- de mapeamento. Observe que o nome das colunas em
<literal>key</literal> e <literal>many-to-many</literal>
- estão trocados em ambos os documentos de mapeamento. A adição mais
importante feita está no atributo
- <literal>inverse="true"</literal> no elemento set
do mapeamento da coleção da classe <literal>Event</literal>.
- </para>
-
- <para>
- Isso significa que o Hibernate deve pegar o outro lado – a classe
<literal>Person</literal> –
- quando necessitar encontrar informação sobre a relação entre as duas
entidades. Isso será muito
- mais facilmente compreendido quando você analisar como a relação
bidirecional entre as entidades é criada.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-associations-usingbidir">
- <title>Trabalhando com links bidirecionais</title>
-
- <para>
- Primeiro tenha em mente que o Hibernate não afeta a semântica normal do
Java. Como nós criamos
- um link entre uma <literal>Person</literal> e um
<literal>Event</literal> no exemplo unidirecional?
- Nós adicionamos uma instância de <literal>Event</literal>, da
coleção de referências de eventos,
- a uma instância de <literal>Person</literal>. Então,
obviamente, se nós queremos que este link funcione
- bidirecionalmente, nós devemos fazer a mesma coisa para o outro lado –
adicionando uma referência de
- <literal>Person</literal> na coleção de um
<literal>Event</literal>. Esse acerto de link de ambos
- os lados é absolutamente necessário e você nunca deve esquecer de
faze-lo.
- </para>
-
- <para>
- Muitos desenvolvedores programam de maneira defensiva e criam métodos
- gerenciador de associações que ajusta corretamente ambos os lados:
- </para>
-
- <programlisting><![CDATA[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);
-}]]></programlisting>
-
- <para>
- Observe que os métodos set e get da a coleção estão protegidos – isso
permite que classes e
- subclasses do mesmo pacote continuem acessando os métodos, mas previne
que qualquer outra classe,
- que não esteja no mesmo pacote, acesse a coleção diretamente. Você
provavelmente deve fazer a mesma
- coisa para a coleção do outro lado.
- </para>
-
- <para>
- E sobre o mapeamento do atributo <literal>inverse</literal>?
Pra você, e para o Java, um link bidirecional
- é simplesmente o fato de ajustar corretamente as referências de ambos os
lados. O Hibernate, entretanto
- não possui informação necessária para corretamente adaptar os estados
<literal>INSERT</literal> e
- <literal>UPDATE</literal> do SQL, e precisa de ajuda para
manipular as propriedades das associações
- bidirecionais. Fazer um lado da associação com o atributo
<literal>inverse</literal> instrui o Hibernate
- para basicamente ignora-lo, considerando-o uma
<emphasis>cópia</emphasis> do outro lado. Isso é todo o
- necessário para o Hibernate trabalhar com todas as possibilidades quando
transformando um modelo de
- navegação bidirecional em esquema de banco de dados do SQL. As regras que
você possui para lembrar são
- diretas: Todas associações bidirecionais necessitam que um lado possua o
atributo inverse. Em uma
- associação de um-para-muitos, o lado de "muitos" deve conter o
atributo <literal>inverse</literal>,
- já em uma associação de muitos-para-muitos você pode pegar qualquer lado,
não há diferença.
- </para>
-
- </sect2>
-
- <para>
- Agora, vamos portar este exemplo para um pequeno aplicativo para internet.
-
- </para>
-
- </sect1>
-
- <sect1 id="tutorial-webapp">
- <title>EventManager um aplicativo para internet</title>
-
- <para>
- Um aplicativo para internet do Hibernate usa uma
<literal>Session</literal> e uma <literal>Transaction</literal>
- quase do mesmo modo que um aplicativo standalone. Entretanto, alguns patterns
comuns são úteis.
- Nós agora criaremos um <literal>EventManagerServlet</literal>.
Esse servlet lista todos os eventos
- salvos no banco de dados, e cria um formulário HTML para entrada de novos
eventos.
- </para>
-
- <sect2 id="tutorial-webapp-servlet" revision="1">
- <title>Criando um servlet básico</title>
-
- <para>
- Crie uma nova classe no seu diretório fonte, no pacote
<literal>events</literal>:
- </para>
-
- <programlisting><![CDATA[package events;
-
-// Imports
-
-public class EventManagerServlet extends HttpServlet {
-
- // Servlet code
-}]]></programlisting>
-
- <para>
- O servlet manuseia somente requisições <literal>GET</literal>
do HTTP,
- portanto o método que iremos implementar é
<literal>doGet()</literal>:
- </para>
-
- <programlisting><![CDATA[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();
- throw new ServletException(ex);
- }
-
-}]]></programlisting>
-
- <para>
- O pattern que estamos aplicando neste código é chamado
<emphasis>session-per-request</emphasis>.
- Quando uma requisição chega ao servlet, uma nova
<literal>Session</literal> do Hibernate é
- aberta através da primeira chamada para
<literal>getCurrentSession()</literal> em
- <literal>SessionFactory</literal>. Então uma transação do
banco de dados é inicializada -
- todo acesso a dados deve ocorrer dentro de uma transação, não importando
se o dado é de leitura ou escrita.
- (nós não devemos usar o modo auto-commit em aplicações).
-
- </para>
-
- <para>
- Agora, as possibilidades de ações de uma requisição serão processadas e
uma resposta HTML será renderizada.
- Nós já iremos chegar nesta parte.
- </para>
-
- <para>
- Finalmente, a unidade de trabalho termina quando o processamento e a
restituição são completados.
- Se ocorrer algum erro durante o processamento ou a restituição, uma
exceção será lançada e a
- transação do banco de dados encerrada. Isso completa o pattern
<literal>session-per-request</literal>.
- 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 site do Hibernate e do Wiki para maiores informações
sobre esse pattern,
- chamado <emphasis>Open Session in View</emphasis>.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-webapp-processing" revision="1">
- <title>Processando e renderizando</title>
-
- <para>
- Vamos implementar o processamento da requisição e a restituição da página
HTML.
- </para>
-
-<programlisting><![CDATA[// 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();]]></programlisting>
-
- <para>
- O estilo de código acima, misturando linguagem HTML e Java não será
funcional em um aplicativo
- mais complexo—tenha em mente que neste manual nós estamos
apenas ilustrando conceitos
- básicos do Hibernate. O código imprime um cabeçalho HTML e um rodapé.
Dentro desta página,
- é mostrado um formulário em HTML, para entrada de novos eventos, e uma
lista de todos
- os eventos contidos no banco de dados. O primeiro método é trivial e
apenas imprime
- uma página HTML:
- </para>
-
- <programlisting><![CDATA[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>");
-}]]></programlisting>
-
- <para>
- O método <literal>listEvents()</literal> usa a
<literal>Session</literal> do Hibernate
- associada a thread atual para executar um query:
- </para>
-
- <programlisting><![CDATA[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>");
- for (Iterator it = result.iterator(); 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>");
- }
-}]]></programlisting>
-
- <para>
- Finalmente, a action <literal>store</literal> é passada pra o
método
- <literal>createAndStoreEvent()</literal>, que também usa a
- <literal>Session</literal> da thread atual:
- </para>
-
- <programlisting><![CDATA[protected void createAndStoreEvent(String
title, Date theDate) {
- Event theEvent = new Event();
- theEvent.setTitle(title);
- theEvent.setDate(theDate);
-
- HibernateUtil.getSessionFactory()
- .getCurrentSession().save(theEvent);
-}]]></programlisting>
-
- <para>
- Pronto, o servlet está completo. Uma requisição para o servlet será
processada
- em uma <literal>Session</literal> e uma
<literal>Transaction</literal> simples.
- Como anteriormente, no aplicativo standalone, o Hibernate pode
automaticamente
- associar esses objetos a thread atual em execução. Isso possibilita a
liberdade
- de você modelar seu código e acessar o método
<literal>SessionFactory</literal>
- do jeito que achar melhor. Geralmente você irá usar um design mais
sofisticado
- e mover o código de acesso a dados para dentro de objetos de acesso a
dados
- (o patter DAO). Leia o Hibernate Wiki para maiores exemplos.
- </para>
-
- </sect2>
-
- <sect2 id="tutorial-webapp-deploy">
- <title>Instalando e testando</title>
-
- <para>
- Para fazer o deploy desta aplicação você tem que criar um arquivo para
web, um WAR.
- Adicione o alvo Ant abaixo em seu
<literal>build.xml</literal>:
- </para>
-
-<programlisting><![CDATA[<target name="war"
depends="compile">
- <war destfile="hibernate-tutorial.war" webxml="web.xml">
- <lib dir="${librarydir}">
- <exclude name="jsdk*.jar"/>
- </lib>
-
- <classes dir="${targetdir}"/>
- </war>
-</target>]]></programlisting>
-
- <para>
- Esta target cria um arquivo chamado
<literal>hibernate-tutorial.war</literal>
- no diretório do seu projeto. Ele empacota todas as bibliotecas e o
arquivo de
- descrição <literal>web.xml</literal>, o qual é esperado no
diretório base do seu projeto:
- </para>
-
- <programlisting><![CDATA[<?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>events.EventManagerServlet</servlet-class>
- </servlet>
-
- <servlet-mapping>
- <servlet-name>Event Manager</servlet-name>
- <url-pattern>/eventmanager</url-pattern>
- </servlet-mapping>
-</web-app>]]></programlisting>
-
- <para>
- Antes de você compilar e fazer o deploy desta aplicação web, note que uma
biblioteca
- adicional é requerida: <literal>jsdk.jar</literal>. Esse é o
Java servlet development kit,
- se você não possui esta biblioteca, faça seu download na página da Sun e
copie-a
- para seu diretório de bibliotecas. Entretanto, será usado somente para a
compilação e
- excluído do pacote WAR.
- </para>
-
- <para>
- Para compilar e instalar execute <literal>ant war</literal>
no seu diretório do projeto
- e copie o arquivo <literal>hibernate-tutorial.war</literal>
para o diretório
- <literal>webapp</literal> do Tomcat. Se você não possui o
Tomcat instalado faça
- o download e siga as instruções de instalação. Você não precisa modificar
- nenhuma configuração do Tomcat para rodar este aplicativo.
- </para>
-
- <para>
- Uma vez feito o deploy e com Tomcat rodando, acesse o aplicativo em
-
<literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>.
- Veja o log do Tomcat para observar a inicialização do Hibernate quando a
- primeira requisição chega ao servlet (o inicializador estático dentro de
- <literal>HibernateUtil</literal> é chamado) e para ter uma
depuração
- detalhada se ocorrer alguma exceção.
- </para>
-
- </sect2>
-
- </sect1>
-
- <sect1 id="tutorial-summary" revision="1">
- <title>Sumário</title>
-
- <para>
- Este manual cobriu os princípios básicos para criação de uma aplicação
simples do Hibernate
- e uma pequena aplicação web.
- </para>
-
- <para>
- Se você já se sente seguro com o Hibernate, continue navegando na
documentação de referência
- por tópicos que você acha interessante – os tópicos mais questionados são:
- processo de transação (<xref linkend="transactions"/>), uso
da API (<xref linkend="objectstate"/>)
- e características de consulta (<xref
linkend="objectstate-querying"/>).
- </para>
-
- <para>
- Não esqueça de visitar o site do Hibernate para obter mais tutoriais
especializados.
- </para>
-
- </sect1>
-
-</chapter>
+<chapter id="tutorial">
+ <title>Introdução ao Hibernate</title>
+
+ <sect1 id="tutorial-intro" revision="1">
+ <title>Prefácio</title>
+
+ <para>
+ Este capítulo é um tutorial introdutório
para novos usuários do Hibernate. Nós iniciaremos com uma simples linha de
comando em uma aplicação usando uma base de dados em
memória tornando isto um passo de fácil de compreender.
+ </para>
+
+ <para>
+ Este tutorial é voltado para novos usuários do Hibernate, mas
requer um conhecimento de Java e SQL. Este tutorial é baseado no tutorial de
Michael Gloegl, as bibliotecas Third Party foram nomeadas para JDK 1.4 e 5.0. Você pode
precisar de outras bibliotecas para JDK 1.3.
+ </para>
+
+ <para>
+ O código fonte para o tutorial está incluído no diretório da distribuição
+ <literal>doc/reference/tutorial/</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="tutorial-firstapp" revision="2">
+ <title>Parte 1 – A primeira aplicação Hibernate</title>
+
+ <para>
+ Primeiro, iremos criar uma simples aplicação Hibernate
baseada em console. Usaremos uma base de dados Java (HSQL DB), então
não teremos que instalar nenhum servidor de base de dados.
+ </para>
+
+ <para>
+ Vamos supor que precisemos de uma aplicação com um
banco de dados pequeno que possa armazenar e atender os eventos que queremos, e as
informaççes sobre os hosts destes eventos.
+ </para>
+
+ <para>
+ A primeira coisa que devemos fazer é configurar nosso
diretório de desenvolvimento,
+ e colocar todas as bibliotecas Java que precisamos dentro dele.
Faça o download da
+ distribuição do Hibernate no site do Hibernate.
Descompacte o pacote e coloque todas
+ as bibliotecas necessárias encontradas no diretório
<literal>/lib</literal>, dentro do
+ diretório <literal>/lib</literal> do seu novo projeto.
Você deverá ter algo parecido
+ com isso:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ antlr.jar
+ cglib.jar
+ asm.jar
+ asm-attrs.jars
+ commons-collections.jar
+ commons-logging.jar
+ hibernate3.jar
+ jta.jar
+ dom4j.jar
+ log4j.jar ]]></programlisting>
+
+ <para>
+ Esta é a configuração mínima
requerida das bibliotecas (observe que também foi copiado
+ o hibernate3.jar da pasta principal do Hibernate) para o Hibernate
<emphasis>na hora do desenvolvimento</emphasis>. O Hibernate permite que você
utilize mais ou menos bibliotecas.
+ Veja o arquivo <literal>README.txt</literal> no
diretório <literal>lib/</literal> da
distribuição
+ do Hibernate para maiores informaççes sobre bibliotecas
requeridas e opcionais.
+ (Atualmente, a biblioteca Log4j não é requerida, mas
é preferida por muitos desenvolvedores.)
+ </para>
+
+ <para>
+ Agora, iremos criar uma classe que representa o evento que queremos armazenar
na base de dados..
+ </para>
+
+ <sect2 id="tutorial-firstapp-firstclass" revision="1">
+ <title>A primeira Classe</title>
+
+ <para>
+ Nossa primeira classe de persistência é uma simples classe JavaBean com
algumas propriedades:
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+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;
+ }
+}]]></programlisting>
+
+ <para>
+ Você pode ver que esta classe usa o padrão JavaBean para o nomeamento
convencional da propriedade getter e dos métodos setter, como também a visibilidade
private 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. O construtor sem argumento é requerido para instanciar um
objeto desta classe com a reflexão.
+ </para>
+
+ <para>
+ A propriedade <literal>id</literal> 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
+ (esp. aplicações web) precisam destinguir os objetos pelo identificador,
então você deverá
+ considerar esta, uma característica em lugar de uma limitação. Porém, nós
normalmente não
+ manipulamos a identidade de um objeto, consequentemente o método setter
deverá ser privado.
+ O Hibernate somente nomeará os identificadores quando um objeto for
salvo. Você pode ver como
+ o Hibernate pode acessar métodos públicos, privados, e protegidos, como
também campos
+ (públicos, privados, protegidos) diretamente. A escolha está até você, e
você pode combinar
+ isso para adaptar seu projeto de aplicação
+ </para>
+
+ <para>
+ O construtor sem argumentos é um requerimento para todas as classes
persistentes;
+ O Hibernate tem que 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
+ </para>
+
+ <para>
+ Coloque este fonte Java no diretório chamado
<literal>src</literal> na pasta de desenvolvimento,
+ e em seu pacote correto. O diretório deverá ser parecido como este:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java]]></programlisting>
+
+ <para>
+ No próximo passo, iremos falar sobre as classes de persistência do
Hibernate..
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-mapping" revision="1">
+ <title>O mapeamento do arquivo</title>
+
+ <para>
+ O Hibernate precisa saber como carregar e armazenar objetos da classe de
+ persistência. Isto será onde 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.
+ </para>
+
+ <para>
+ A estrutura básica de um arquivo de mapeamento é parecida com:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Note que o Hibernate DTD é muito sofisticado. Você pode usar isso para
auto-conclusão
+ no mapeamento XML dos elementos e atributos no seu editor ou IDE. Você
também pode
+ abrir o arquivo DTD no seu editor – é a maneira mais fácil de ter uma
visão geral
+ de todos os elementos e atributos 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 do
diretório
+ da aplicação (classpath). O arquivo DTD está incluído no
<literal>hibernate3.jar</literal> como
+ também no diretório <literal>src/</literal> da distribuição
do Hibernate.
+ </para>
+
+ <para>
+ Nós omitiremos a declaração do DTD nos exemplos futuros para encurtar o
código. Isto, é claro, não é opcional.
+ </para>
+
+ <para>
+ Entre os dois tags <literal>hibernate-mapping</literal>,
inclua um elemento <literal>class</literal>.
+ 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
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Event" table="EVENTS">
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Mais adiante iremos dizer ao Hibernate como fazer para persistir e
carregar objetos da classe
+ <literal>Event</literal> da tabela
<literal>EVENTS</literal>, cada instancia 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, nós não iremos se
importar com esta propriedade
+ identificadora, nós iremos configurar uma estratégia de geração de id’s
para uma chave primária
+ de uma surrogate key:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="native"/>
+ </id>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ O elemento <literal>id</literal> é a declaração da
propriedade identificadora,
+ o <literal>name="id"</literal> declara o nome da
propriedade Java –
+ o Hibernate irá usar os métodos getter e setter para acessar a
propriedade.
+ O atributo da coluna informa ao Hibernate qual coluna da tabela
<literal>EVENTS</literal> nós
+ iremos usar como chave primária. O elemento
<literal>generator</literal> especifica
+ a estratégia de geração do identificador, neste caso usaremos
<literal>native</literal>, que
+ escolhe a melhor estratégia dependendo da base de dados (dialeto)
configurada.
+ O Hibernate suporta a base de dados gerada, globalmente única, bem como a
atribuição
+ aos identificadores da aplicação (ou toda estratégia escrita para uma
extensão).
+ </para>
+
+ <para>
+ Finalmente incluiremos as declarações para as propriedades persistentes
da classe
+ no arquivo mapeado. Por default, nenhuma das propriedades da classe é
considerada persistente:
+ </para>
+
+ <programlisting><![CDATA[
+<hibernate-mapping>
+
+ <class name="events.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>]]></programlisting>
+
+ <para>
+ Da mesma maneira que com o elemento <literal>id</literal>, o
atributo <literal>name</literal> do elemento
+ <literal>property</literal> informa ao Hibernate qual método
getter e setter deverá usar.
+ Assim, neste caso, o Hibernate irá procurar pelo
<literal>getDate()/setDate()</literal>,
+ como também pelo <literal>getTitle()/setTitle()</literal>.
+ </para>
+
+ <para>
+ Porque fazer o mapeamento da propriedade
<literal>date</literal> incluído no
+ atributo <literal>column</literal>, e no title não fazer?
+ Sem o atributo <literal>column</literal> o Hibernate por
padrão usa o nome
+ da propriedade como o nome da coluna. Isto trabalha muito
+ bem para o <literal>title</literal>. Entretanto o
<literal>date</literal> é uma palavra-chave reservada
+ na maioria dos bancos de dados, assim nós melhoramos o mapeamentos
+ disto com um nome diferente.
+ </para>
+
+ <para>
+ A próxima coisa interessante é que mapemanto do
<literal>title</literal>
+ também falta o atributo <literal>type</literal>. O tipo que
declaramos e o uso nos
+ arquivos mapeados, não são como você pôde esperar, atributos de dados
Java.
+ Eles não são como os tipos de base de dados SQL.
+ Esses tipos podem ser chamados de <emphasis>Tipos de mapeamento
Hibernate</emphasis>, 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 <literal>type</literal>
+ próprio, caso o tipo do atributo 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 padrão que você espera ou necessita.
+ Este é o caso com a propriedade <literal>date</literal>. O
Hibernate não pode saber se a propriedade
+ (que é do <literal>java.util.Date</literal>) pode mapear para
uma coluna do tipo <literal>date</literal>
+ do SQL, <literal>timestamp</literal>, ou
<literal>time</literal> .
+ Nós preservamos a informação cheia de datas e horas pelo mapeamento da
propriedade com um conversor
+ <literal>timestamp</literal>.
+ </para>
+
+ <para>
+ Este arquivo de mapeamento deve ser salvo como
<literal>Event.hbm.xml</literal>,
+ corretamente no diretório próximo ao arquivo fonte da Classe Java
<literal>Event</literal>.
+ O nomeamento dos arquivos de mapeamento podem ser arbitrários, porém o
sufixo
+ <literal>hbm.xml</literal> é uma convenção da comunidade dos
desenvolvedores do Hibernate.
+ Esta estrutura do diretório deve agora se parecer com isso:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java
+ Event.hbm.xml]]></programlisting>
+
+ <para>
+ Nós iremos continuar com a configuração principal do Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-configuration"
revision="2">
+ <title>Configuração do Hibernate</title>
+
+ <para>
+ Agora nós temos uma classe persistente e este arquivo de mapeamento no
lugar.
+ Está na hora de configurar o Hibernate. Antes de fazermos isso, iremos
precisar de uma base de dados.
+ O HSQL DB, um SQL DBMS feito em java, pode ser baixado através do site do
HSQL
DB(http://hsqldb.org/).
+ Atualmente, você só precisa baixar o
<literal>hsqldb.jar</literal>.
+ Coloque este arquivo no diretório da pasta de desenvolvimento
<literal>lib/</literal>.
+ </para>
+
+ <para>
+ Crie um diretório chamado <literal>data</literal> no
diretório root de desenvolvimento –
+ Isto será onde o HSQL DB irá armazenar arquivos de dados. Agora iremos
iniciar o banco de dados
+ executando <literal>java -classpath ../lib/hsqldb.jar
org.hsqldb.Server</literal> neste diretório de dados.
+ Você pode ver ele iniciando e conectando ao socket TCP/IP, isto será onde
nossa aplicação irá se
+ conectar depois. Se você deseja iniciar uma nova base de dados durante
este tutorial,
+ finalize o HSQL DB(pressionando o <literal>CTRL + C</literal>
na janela), delete todos os
+ arquivos no diretório <literal>data/</literal>, e inicie o
HSQL BD novamente.
+ </para>
+
+ <para>
+ O Hibernate é uma camada na sua aplicação na qual se conecta com a base
de dados, para isso
+ necessita de informação da conexão. As conexões são feitas através de um
pool de conexão JDBC,
+ na qual teremos que configurar. A distribuição do Hibernate contém
diversas ferramentas de pooling
+ da conexão JDBC de fonte aberta, mas iremos usar o pool de conexão
interna para este tutorial.
+ Note que você tem que copiar a biblioteca necessária em seu classpath e
use configurações
+ diferentes para pooling de conexão caso você deseje utilizar um software
de pooling JDBC terceirizado
+ para qualidade de produção.
+ </para>
+
+ <para>
+ Para as configurações do Hibernate, nós podemos usar um arquivo simples
<literal>hibernate.properties</literal>,
+ um arquivo mais ligeiramente sofisticado
<literal>hibernate.cfg.xml</literal> ou até mesmo uma
+ instalação programática completa. A maioria dos usuários preferem
utilizar o arquivo de configuração XML
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0'
encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/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">create</property>
+
+ <mapping resource="events/Event.hbm.xml"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Note que esta configuração XML usa um diferente DTD. Nós configuraremos
+ as <literal>SessionFactory</literal> do Hibernate – uma
factory global responsável
+ por uma base de dedados particular. Se você tiver diversas bases de
dados,
+ use diversas configurações
<literal><session-factory></literal>, geralmente
+ em diversos arquivos de configuração (para uma partida mais fácil).
+ </para>
+
+ <para>
+ As primeiras quatro <literal>propriedades</literal> do
elemento contém a configuração
+ necessária para a conexão ao JDBC. A propriedade
<literal>propriedade</literal> dialect
+ do elemento especifica a variante particular do SQL que o Hibernate gera.
+ O gerenciamento automático de sessão do Hibernate para contextos de
persistência
+ estará disponível em breve. A opção
<literal>hbm2ddl.auto</literal> habilita a geração
+ automática de schemas da base de dados – diretamente na base de dados.
+ Isto também pode ser naturalmente desligado (removendo a opção de
configuração) ou redirecionando
+ para um arquivo com ajuda do <literal>SchemaExport</literal>
nas tarefas do Ant.
+ Finalmente, iremos adicionar os arquivos das classes de persistência
mapeadas na configuração.
+ </para>
+
+ <para>
+ Copie este arquivo no diretório fonte, assim isto irá terminar na raiz
(root) do
+ classpath. O Hibernate automaticamente procura por um arquivo chamado
+ <literal>hibernate.cfg.xml</literal> na raiz do classpath, no
startup.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-ant" revision="1">
+ <title>Construindo com o Ant</title>
+
+ <para>
+ Nos iremos, agora, construir o tutorial com Ant. Você ira precisar o Ant
instalado –
+ se encontra disponível <ulink
url="http://ant.apache.org/bindownload.cgi">na página de download do
Ant</ulink>.
+ Como instalar o Ant, não será abordado aqui. Caso tenha alguma dúvida,
por favor,
+ vá ao <ulink
url="http://ant.apache.org/manual/index.html">Ant manual</ulink>.
+ Depois que tiver instalado o Ant, podemos começar a criar o arquivo de
construção <literal>build.xml</literal>.
+ Este arquivo será chamado de <literal>build.xml</literal> e
posto diretamente no diretório de desenvolvimento.
+ </para>
+
+ <para>
+ Um arquivo básico de build, se parece com isto:
+ </para>
+
+ <programlisting><![CDATA[<project
name="hibernate-tutorial" default="compile">
+
+ <property name="sourcedir" value="${basedir}/src"/>
+ <property name="targetdir" value="${basedir}/bin"/>
+ <property name="librarydir" value="${basedir}/lib"/>
+
+ <path id="libraries">
+ <fileset dir="${librarydir}">
+ <include name="*.jar"/>
+ </fileset>
+ </path>
+
+ <target name="clean">
+ <delete dir="${targetdir}"/>
+ <mkdir dir="${targetdir}"/>
+ </target>
+
+ <target name="compile" depends="clean, copy-resources">
+ <javac srcdir="${sourcedir}"
+ destdir="${targetdir}"
+ classpathref="libraries"/>
+ </target>
+
+ <target name="copy-resources">
+ <copy todir="${targetdir}">
+ <fileset dir="${sourcedir}">
+ <exclude name="**/*.java"/>
+ </fileset>
+ </copy>
+ </target>
+
+</project>]]></programlisting>
+
+ <para>
+ Isto irá avisar ao Ant para adicionar todos os arquivos no diretório lib
terminando com
+ <literal>.jar</literal>, para o classpath usado para
compilação. Irá também copiar todos os
+ arquivos não-java para o diretório alvo (arquivos de configuração,
mapeamento). Se você rodar
+ o ant agora, deverá ter esta saída.
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+ [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+ [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-helpers" revision="3">
+ <title>Startup and helpers</title>
+
+ <para>
+ É hora de carregar e arquivar alguns objetos
<literal>Event</literal>, mas primeiro
+ nós temos de completar o setup com algum código de infraestrutura. Este
startup
+ inclui a construção de um objeto
<literal>SessionFactory</literal> global e armazenar
+ isto em algum lugar de fácil acesso para o código da aplicação.
+ Uma <literal>SessionFactory</literal> pode abrir novas
<literal>Session</literal>'s.
+ Uma <literal>Session</literal> representa uma unidade
single-theaded do trabalho, a
+ <literal>SessionFactory</literal> é um objeto global
thread-safe, instanciado uma vez.
+ </para>
+
+ <para>
+ Nos iremos criar uma classe de ajuda
<literal>HibernateUtil</literal>, que toma
+ conta do startup e faz acesso a uma
<literal>SessionFactory</literal> conveniente.
+ Vamos dar uma olhada na implementação:
+ </para>
+
+ <programlisting><![CDATA[package util;
+
+import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+ private static final SessionFactory sessionFactory;
+
+ static {
+ try {
+ // Create the SessionFactory from hibernate.cfg.xml
+ sessionFactory = 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;
+ }
+
+}]]></programlisting>
+
+ <para>
+ Esta classe não só produz a global
<literal>SessionFactory</literal> no seu static initializer
+ (chamado uma vez pela JVM quando a classe é carregada), mas também
esconde o fato
+ de que isto usa um static singleton. Ela pode muito bem, enxergar a
+ <literal>SessionFactory</literal> do JNDI em um application
server.
+ </para>
+
+ <para>
+ Se você der à <literal>SessionFactory</literal> um nome, no
seu arquivo de configuração.
+ O Hibernate irá, de fato, tentar uni-lo ao JNDI depois que estiver
construído.
+ Para evitar este completamente este código, você também poderia usar JMX
deployment
+ e deixar o contêiner JMX capaz, instanciar e unir um
<literal>HibernateService</literal>
+ no JNDI. Essas opções avançadas são discutidas no documento de referência
do Hibernate.
+ </para>
+
+ <para>
+ Coloque o <literal>HibernateUtil.java</literal> no diretório
de arquivos
+ de desenvolvimento(source), em um pacote após o
<literal>events</literal>:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ +events
+ Event.java
+ Event.hbm.xml
+ +util
+ HibernateUtil.java
+ hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+ <para>
+ Novamente, isto deve compilar sem problemas. Finalmente, nós precisamos
configurar
+ um sistema de logging – o Hibernate usa commons logging e deixa você
escolher entre o
+ Log4j e o logging do JDK 1.4 . A maioria dos desenvolvedores preferem o
Log4j: copie
+ <literal>log4j.properties</literal> da distribuição do
Hibernate (está no diretório
+ <literal>etc/</literal>), para seu diretório
<literal>src</literal>,
+ depois vá em hibernate.cfg.xml. Dê uma olhada no exemplo de configuração
e mude as
+ configurações se você quizer ter uma saída mais detalhada. Por default,
apenas as
+ mensagems de startup e shwwn do Hibernate é mostrada no stdout.
+ </para>
+
+ <para>
+ O tutorial de infra-estrutura está completo - e nós já estamos preparados
para algum
+ trabalho de verdade com o Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-workingpersistence"
revision="4">
+ <title>Carregando e salvando objetos</title>
+
+ <para>
+ Finalmente, nós podemos usar o Hibernate para carregar e armazenar
objetos.
+ Nós escrevemos uma classe <literal>EventManager</literal> com
um método main():
+ </para>
+
+ <programlisting><![CDATA[package events;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+import 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();
+ }
+
+}]]></programlisting>
+
+ <para>
+ Nós criamos um novo objeto <literal>Event</literal>, e
passamos para o Hibernate.
+ O Hibernate sabe como tomar conta do SQL e executa
<literal>INSERT</literal>s
+ no banco de dados. Vamos dar uma olhada na
<literal>Session</literal> e no
+ código <literal>Transaction</literal>-handling antes de
executarmos.
+ </para>
+
+ <para>
+ Um <literal>Session</literal> é uma unidade simples de
trabalho. Por agora nós
+ iremos pegar coisas simples e assumir uma granularidade de um-pra-um
entre uma
+ <literal>Session</literal> do Hibernate e uma transação de
banco de dados.
+ Para proteger nosso código de um atual sistema subjacente de transação
(nesse
+ caso puro JDBC, mas também poderia rodar com JTA), nos usamos a API
+ <literal>Transaction</literal>, que está disponível na
<literal>Session</literal> do Hibernate.
+ </para>
+
+ <para>
+ O que a <literal>sessionFactory.getCurrentSession()</literal>
faz? Primeiro, você pode
+ chamar quantas vezes e de onde quiser, uma vez você recebe sua
<literal>SessionFactory</literal>
+ (fácil graças ao <literal>HibernateUtil</literal>). O método
<literal>getCurrentSession()</literal>
+ sempre retorna a unidade de trabalho "corrente". Lembra de que
nós mudamos a opção
+ de configuração desse mecanismo para thread no
<literal>hibernate.cfg.xml</literal>? Daqui em
+ diante, o escopo da unidade de trabalho corrente é a thread Java
+ corrente que executa nossa aplicação. Entretanto, esta não é toda a
verdade. Uma
+ </para>
+
+ <para>
+ <literal>Session</literal> começa quando é primeiramente necessária, quando
é feita a
+ primeira chamada à <literal>getCurrentSession()</literal>. É
então limitado pelo Hibernate
+ para thread corrente. Quando a transação termina, tanto com commit quanto
rollback,
+ o Hibernate também desune a <literal>Session</literal> da
thread e fecha isso pra você.
+ Se você chamar <literal>getCurrentSession()</literal>
novamente, você receberá uma nova
+ <literal>Session</literal> e pode começar uma nova unidade de
trabalho. Esse modelo de
+ programação de limite de thread
<emphasis>thread-bound</emphasis>, é o modo mais popular
+ de se usar o Hibernate.
+ </para>
+ <para>
+ Related to the unit of work scope, should the Hibernate
<literal>Session</literal> be used to
+ execute one or several database operations? The above example uses one
<literal>Session</literal>
+ for one operation. This is pure coincidence, the example is just not complex enough
to show any
+ other approach. The scope of a Hibernate <literal>Session</literal> is
flexible but you should
+ never design your application to use a new Hibernate
<literal>Session</literal> for
+ <emphasis>every</emphasis> database operation. So even if you see it a
few more times in
+ the following (very trivial) examples, consider
<emphasis>session-per-operation</emphasis>
+ an anti-pattern. A real (web) application is shown later in this tutorial.
+ </para>
+ <para>
+ Dê uma olhada no <xref linkend="transactions"/> para mais
informações a
+ respeito de manipulação de transação e demarcação. Nós também pulamos
qualquer
+ manipulação de erro e rollback no exemplo anterior.
+ </para>
+
+ <para>
+ Para executar esta primeira rotina, nos teremos que adicionar um ponto de
chamada
+ para o arquivo de build do Ant:
+ </para>
+
+ <programlisting><![CDATA[<target name="run"
depends="compile">
+ <java fork="true" classname="events.EventManager"
classpathref="libraries">
+ <classpath path="${targetdir}"/>
+ <arg value="${action}"/>
+ </java>
+</target>]]></programlisting>
+
+ <para>
+ O valor do argumento <literal>action</literal>, é setado na
linha de comando quando chamando esse ponto:
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant run
-Daction=store]]></programlisting>
+
+ <para>
+ Você deverá ver, após a compilação, o startup do Hibernate e, dependendo
da sua
+ configuração, muito log de saída. No final você verá a seguinte linha:
+ </para>
+
+ <programlisting><![CDATA[[java] Hibernate: insert into EVENTS
(EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+ <para>
+ Este é o <literal>INSERT</literal> executado pelo Hibernate,
os pontos de interrogação
+ representam parêmetros de união do JDBC. Para ver os valores
substituídos, ou para diminuir a
+ verbalidade do log, check seu
l<literal>log4j.properties</literal>.
+ </para>
+
+ <para>
+ Agora nós gostaríamos de listar os eventos arquivados, então nós
adicionamos uma
+ opção para o método main:
+ </para>
+
+ <programlisting><![CDATA[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());
+ }
+}]]></programlisting>
+
+ <para>
+ Nos também adicionamos um novo <literal>método
listEvents()</literal>:
+ </para>
+
+ <programlisting><![CDATA[private List listEvents() {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+
+ session.beginTransaction();
+
+ List result = session.createQuery("from Event").list();
+
+ session.getTransaction().commit();
+
+ return result;
+}]]></programlisting>
+
+ <para>
+ O que nós fazemos aqui, é usar uma query HQL (Hibernate Query Language),
+ para carregar todos os objetos <literal>Event</literal>
exitentes no banco de dados.
+ O Hibernate irá gerar o SQL apropriado, enviar para o banco de dados e
popular objetos
+ <literal>Event</literal> com os dados. Você pode criar
queries mais complexas com
+ HQL, claro.
+ </para>
+
+ <para>
+ Agora, para executar e testar tudo isso, siga os passos a seguir:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Execute <literal>ant run -Daction=store</literal>
para armazenar algo no banco de dados
+ e, claro, gerar o esquema do banco de dados antes pelo hbm2ddl.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Agora desabilite hbm2ddl comentando a propriedade no seu arquivo
<literal>hibernate.cfg.xml</literal>.
+ Normalmente só se deixa habilitado em teste unitários contínuos,
mas outra carga de hbm2ddl
+ pode <emphasis>remover</emphasis> tudo que você já
tenha arquivado. Sa configuração
+ <literal>create</literal>, atualmente são traduzidas
para "apague todas as tabelas do esquema,
+ então recrie todas quando a SessionFactory estiver pronta".
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Se você agora chamar o Ant com
<literal>-Daction=list</literal>, você deverá ver os
+ eventos que você acabou de criar. Você pode também chamar a ação
<literal>store</literal>
+ mais algumas vezes.
+ </para>
+
+ <para>
+ Nota: A maioria dos novos usuários do Hibernate falha nesse ponto e nós
regularmente, vemos
+ questões sobre mensagens de erro de <emphasis>tabela não encontrada
</emphasis> .
+ Entretanto, se você seguir os passos marcados acima, você não terá esse
problema,
+ com o hbm2ddl criando o esquema do banco de dados na primeira execução, e
restarts
+ subsequentes da aplicação irão usar este esquema. Se você mudar o
mapeamento e/ou
+ o esquema do banco de dados, terá de re-habilitar o hbm2ddl mais uma
vez.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="tutorial-associations">
+ <title>Part 2 - Mapeando associações</title>
+
+ <para>
+ Nós mapeamos uma classe de entidade de persistência para uma tabela. Agora
vamos continuar
+ e adicionar algumas associações de classe. Primeiro nos iremos adicionar
pessoas a nossa aplicação,
+ e armazenar os eventos de que elas participam.
+ </para>
+
+ <sect2 id="tutorial-associations-mappinguser"
revision="1">
+ <title>Mapeando a classe Person</title>
+
+ <para>
+ O primeiro código da classe <literal>Person</literal> é
simples:
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+public class Person {
+
+ private Long id;
+ private int age;
+ private String firstname;
+ private String lastname;
+
+ public Person() {}
+
+ // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+ <para>
+ Crie um novo arquivo de mapeamento, chamado
<literal>Person.hbm.xml</literal> (não
+ esqueça a referencia ao DTD no topo)
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="events.Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="native"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Finalmente, adicione o novo mapeamento a configuração do Hibernate:
+ </para>
+
+ <programlisting><![CDATA[<mapping
resource="events/Event.hbm.xml"/>
+<mapping resource="events/Person.hbm.xml"/>]]></programlisting>
+
+ <para>
+ Nos iremos agora criar uma associação entre estas duas entidades.
Obviamente,
+ pessoas (Person) podem participar de eventos, e eventos possuem
participantes.
+ As questões de design com que teremos de lidar são: direcionalidade,
multiplicidade e
+ comportamento de coleção.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-unidirset"
revision="3">
+ <title>Uma associação Set-based unidirectional</title>
+
+ <para>
+ Nos iremos adicionar uma coleção de eventos na classe
<literal>Person</literal>. Desse jeito
+ poderemos navegar pelos eventos de uma pessoa em particular, sem executar
uma query explicitamente –
+ apenas chamando <literal>aPerson.getEvents()</literal>. Nos
usaremos uma coleção Java, um
+ <literal>Set</literal>, porquê a coleção não conterá
elementos duplicados e a ordem não é
+ relevante para nós.
+ </para>
+
+ <para>
+ Vamos escrever o código para isto nas classes Java e então mapear:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+
+ private Set events = new HashSet();
+
+ public Set getEvents() {
+ return events;
+ }
+
+ public void setEvents(Set events) {
+ this.events = events;
+ }
+}]]></programlisting>
+
+ <para>
+ 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
<literal>Event</literal>, se quisermos
+ ser capaz de navegar bidirecionalmente, i.e. um -
<literal>anEvent.getParticipants()</literal>.
+ Isto não é necessário, de perspectiva funcional. Você poderia sempre
executar uma query explicita
+ que retornasse 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" valores em ambos
+ os lados, nós chamamos isto uma associação
<emphasis>muitos-para-muitos</emphasis>. Daqui pra frente,
+ nos usaremos o mapeamento muitos-para-muitos do Hibernate:
+ </para>
+
+ <programlisting><![CDATA[<class name="events.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="events.Event"/>
+ </set>
+
+</class>]]></programlisting>
+
+ <para>
+ O Hibernate suporta todo tipo de mapeamento de coleção , sendo um
<literal><set></literal> mais comum.
+ Para uma associação muitos-para-muitos (ou relacionamento de entidade
<emphasis>n:m</emphasis> ),
+ uma tabela de associação é necessária. Cada linha nessa tabela representa
um link entre uma pessoa e um
+ evento. O nome da tabela é configurado com o atributo
<literal>table</literal> do elemento
+ <literal>set</literal>. O nome da coluna identificadora na
associção, peloo lado da pessoa,
+ é definido com o elemento
<literal><key></literal> , o nome da coluna pelo lado dos
eventos,
+ e definido com o atributo <literal>column</literal> do
<literal><many-to-many></literal>.
+ 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).
+ </para>
+
+ <para>
+ O esquema de mapeamento para o banco de dados está a seguir:
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | |
+ |_____________| |__________________| | PERSON |
+ | | | | |_____________|
+ | *EVENT_ID | <--> | *EVENT_ID | | |
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE |
+ |_____________| | FIRSTNAME |
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-working"
revision="1">
+ <title>Trabalhando a associação</title>
+
+ <para>
+ Vamos trazer juntos algumas pessoas e eventos em um novo método na classe
<literal>EventManager</literal>::
+ </para>
+
+ <programlisting><![CDATA[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();
+}]]></programlisting>
+
+ <para>
+ Após carregar um <literal>Person</literal> e um
<literal>Event</literal>, 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 <literal>update()</literal> ou
<literal>save()</literal>, o Hibernate detecta automaticamente
+ que a coleção foi modificada e necessita ser atualizada. Isso é chamado
de <emphasis>checagem
+ suja automática</emphasis>, e você também pode usá-la modificando o
nome ou a data de qualquer um dos
+ seus objetos. Assim que eles estiverem no estado
<emphasis>persistent</emphasis>, ou seja,
+ limitado por uma <literal>Session</literal> do Hibernate em
particular (i.e. eles foram carregados ou
+ salvos dentro de uma unidade de trabalho), o Hibernate monitora qualquer
alteração e executa o SQL
+ em modo de escrita em segundo plano. O processo de sincronização do
estado da memória com o banco de
+ dados, geralmente apenas no final de uma unidade de trabalho, é chamado
de <emphasis>flushing</emphasis>.
+ No nosso código, a unidade de trabalho termina com o commit da transação
do banco de dados –
+ como definido pela opção de configuração da
<literal>thread</literal> da classe
<literal>CurrentSessionContext</literal>.
+ </para>
+
+ <para>
+ Você pode também querer carregar pessoas e eventos em diferentes unidades
de trabalho.
+ Ou você modifica um objeto fora de uma
<literal>Session</literal>, quando não se encontra no
+ estado persistent (se já esteve neste estado anteriormente, chamamos esse
estado de
+ <emphasis>detached</emphasis>). Você pode até mesmo modificar
uma coleção quando esta
+ se encontrar no estado detached.
+ </para>
+
+ <programlisting><![CDATA[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();
+}]]></programlisting>
+
+ <para>
+ A chamada <literal>update</literal> cria um objeto persistent
novamente, você poderia
+ 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 detached 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.
+ </para>
+
+ <para>
+ Bom, isso não foi muito usado na nossa situação, porém, é um importante
conceito que você
+ pode aplicar em seus aplicativos. Agora, complete este exercício
adicionando uma nova ação
+ ao método main( ) da classe <literal>EventManager</literal>
e chame-o pela linha de comando.
+ Se você precisar dos identificadores de uma pessoa ou evento – o método
<literal>save()</literal>
+ retorna estes identificadores (você poderá modificar alguns dos métodos
anteriores para retornar aquele
+ identificador):
+ </para>
+
+ <programlisting><![CDATA[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);]]></programlisting>
+
+ <para>
+ 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
<literal>int</literal> ou uma <literal>String</literal>.
+ Nós chamamos essas classes de <emphasis>value
types</emphasis>, e suas instâncias <emphasis>depend</emphasis>
+ 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 <literal>firstname</literal>
+ mesmo se elas tiverem o mesmo objeto firstname). Naturalmente, os value
types não são apenas encontrados
+ dentro da JDK (de fato, em um aplicativo Hibernate todas as classes JDK
são consideradas como value types),
+ mas você pode também criar suas classes como, por exemplo,
<literal>Address</literal> ou <literal>MonetaryAmount</literal>.
+
+ </para>
+
+ <para>
+ Você também pode criar uma coleção de value types. Isso é conceitualmente
muito diferente
+ de uma coleção de referências para outras entidades, mas em Java parece
ser quase a mesma coisa.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-valuecollections">
+ <title>Coleção de valores</title>
+
+ <para>
+ Nós adicionamos uma coleção de objetos de tipo de valores à entidade
<literal>Person</literal>.
+ Nós querermos armazenar endereços de e-mail, para isso utilizamos o tipo
<literal>String</literal>,
+ e a coleção novamente será um <literal>Set</literal>:
+ </para>
+ <programlisting><![CDATA[private Set emailAddresses = new
HashSet();
+
+public Set getEmailAddresses() {
+ return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+ this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+ <para>
+ O mapeamento deste <literal>Set</literal>:
+ </para>
+
+ <programlisting><![CDATA[<set name="emailAddresses"
table="PERSON_EMAIL_ADDR">
+ <key column="PERSON_ID"/>
+ <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+ <para>
+ A diferença comparada com o mapeamento anterior se encontra na parte
<literal>element</literal>,
+ que indica ao Hibernate que a coleção não contém referências à outra
entidade, mas uma coleção de
+ elementos do tipo <literal>String</literal> (a tag name em
miniscula indica que se trata de um
+ mapeamento do Hibernate para conversão de tipos). Mais uma vez, o
atributo <literal>table</literal>
+ do elemento <literal>set</literal> determina o nome da tabela
para a coleção. O elemento
+ <literal>key</literal> define o nome da coluna de chave
estrangeira na tabela de coleção.
+ O atributo <literal>column</literal> dentro do elemento
<literal>element</literal> define o
+ nome da coluna onde os valores da <literal>String</literal>
serão armazenados.
+ </para>
+
+ <para>
+ Dê uma olhada no esquema atualizado:
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | 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 |
+ |_____________|
+ ]]></programlisting>
+
+ <para>
+ Você pode observar que a chave primária da tabela da coleção é de na
verdade uma chave composta,
+ usando ambas 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.
+ </para>
+
+ <para>
+ Você pode agora tentar adicionar elementos a essa coleção, do mesmo modo
que fizemos
+ anteriormente ligando pessoas e eventos. È o mesmo código em Java:
+ </para>
+
+ <programlisting><![CDATA[private void addEmailToPerson(Long
personId, String emailAddress) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+
+ // The getEmailAddresses() might trigger a lazy load of the collection
+ aPerson.getEmailAddresses().add(emailAddress);
+
+ session.getTransaction().commit();
+}]]></programlisting>
+
+ <para>
+ This time we didnt' use a <emphasis>fetch</emphasis>
query to initialize the collection.
+ Hence, the call to its getter method will trigger an additional select to
initialize
+ it, so we can add an element to it. Monitor the SQL log and try to
optimize this with
+ an eager fetch.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-bidirectional"
revision="1">
+ <title>Associações bidirecionais</title>
+
+ <para>
+ Agora iremos mapear uma associação bidirecional – fazendo a associação
entre pessoas e
+ eventos, de ambos os lados, em Java. Logicamente, o esquema do banco de
dados não muda,
+ nós continuamos tendo multiplicidades muitos-para-muitos. Um banco de
dados é mais flexível do que
+ uma linguagem de programação para redes, ele não precisa de nenhuma
direção de navegação – os
+ dados podem ser acessados em qualquer caminho possível.
+ </para>
+
+ <para>
+ Primeiramente, adicione uma coleção de participantes à classe
<literal>Event</literal>:
+ </para>
+
+ <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+ return participants;
+}
+
+public void setParticipants(Set participants) {
+ this.participants = participants;
+}]]></programlisting>
+
+ <para>
+ Agora mapeie este lado da associação em
<literal>Event.hbm.xml</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="participants"
table="PERSON_EVENT" inverse="true">
+ <key column="EVENT_ID"/>
+ <many-to-many column="PERSON_ID" class="events.Person"/>
+</set>]]></programlisting>
+
+ <para>
+ Como você pode ver, esses é uma mapeamento normal usando
<literal>set</literal> em ambos documenentos
+ de mapeamento. Observe que o nome das colunas em
<literal>key</literal> e <literal>many-to-many</literal>
+ estão trocados em ambos os documentos de mapeamento. A adição mais
importante feita está no atributo
+ <literal>inverse="true"</literal> no elemento set
do mapeamento da coleção da classe <literal>Event</literal>.
+ </para>
+
+ <para>
+ Isso significa que o Hibernate deve pegar o outro lado – a classe
<literal>Person</literal> –
+ quando necessitar encontrar informação sobre a relação entre as duas
entidades. Isso será muito
+ mais facilmente compreendido quando você analisar como a relação
bidirecional entre as entidades é criada.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-usingbidir">
+ <title>Trabalhando com links bidirecionais</title>
+
+ <para>
+ Primeiro tenha em mente que o Hibernate não afeta a semântica normal do
Java. Como nós criamos
+ um link entre uma <literal>Person</literal> e um
<literal>Event</literal> no exemplo unidirecional?
+ Nós adicionamos uma instância de <literal>Event</literal>, da
coleção de referências de eventos,
+ a uma instância de <literal>Person</literal>. Então,
obviamente, se nós queremos que este link funcione
+ bidirecionalmente, nós devemos fazer a mesma coisa para o outro lado –
adicionando uma referência de
+ <literal>Person</literal> na coleção de um
<literal>Event</literal>. Esse acerto de link de ambos
+ os lados é absolutamente necessário e você nunca deve esquecer de
faze-lo.
+ </para>
+
+ <para>
+ Muitos desenvolvedores programam de maneira defensiva e criam métodos
+ gerenciador de associações que ajusta corretamente ambos os lados:
+ </para>
+
+ <programlisting><![CDATA[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);
+}]]></programlisting>
+
+ <para>
+ Observe que os métodos set e get da a coleção estão protegidos – isso
permite que classes e
+ subclasses do mesmo pacote continuem acessando os métodos, mas previne
que qualquer outra classe,
+ que não esteja no mesmo pacote, acesse a coleção diretamente. Você
provavelmente deve fazer a mesma
+ coisa para a coleção do outro lado.
+ </para>
+
+ <para>
+ E sobre o mapeamento do atributo <literal>inverse</literal>?
Pra você, e para o Java, um link bidirecional
+ é simplesmente o fato de ajustar corretamente as referências de ambos os
lados. O Hibernate, entretanto
+ não possui informação necessária para corretamente adaptar os estados
<literal>INSERT</literal> e
+ <literal>UPDATE</literal> do SQL, e precisa de ajuda para
manipular as propriedades das associações
+ bidirecionais. Fazer um lado da associação com o atributo
<literal>inverse</literal> instrui o Hibernate
+ para basicamente ignora-lo, considerando-o uma
<emphasis>cópia</emphasis> do outro lado. Isso é todo o
+ necessário para o Hibernate trabalhar com todas as possibilidades quando
transformando um modelo de
+ navegação bidirecional em esquema de banco de dados do SQL. As regras que
você possui para lembrar são
+ diretas: Todas associações bidirecionais necessitam que um lado possua o
atributo inverse. Em uma
+ associação de um-para-muitos, o lado de "muitos" deve conter o
atributo <literal>inverse</literal>,
+ já em uma associação de muitos-para-muitos você pode pegar qualquer lado,
não há diferença.
+ </para>
+
+ </sect2>
+
+ <para>
+ Agora, vamos portar este exemplo para um pequeno aplicativo para internet.
+
+ </para>
+
+ </sect1>
+
+ <sect1 id="tutorial-webapp">
+ <title>EventManager um aplicativo para internet</title>
+
+ <para>
+ Um aplicativo para internet do Hibernate usa uma
<literal>Session</literal> e uma <literal>Transaction</literal>
+ quase do mesmo modo que um aplicativo standalone. Entretanto, alguns patterns
comuns são úteis.
+ Nós agora criaremos um <literal>EventManagerServlet</literal>.
Esse servlet lista todos os eventos
+ salvos no banco de dados, e cria um formulário HTML para entrada de novos
eventos.
+ </para>
+
+ <sect2 id="tutorial-webapp-servlet" revision="1">
+ <title>Criando um servlet básico</title>
+
+ <para>
+ Crie uma nova classe no seu diretório fonte, no pacote
<literal>events</literal>:
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+// Imports
+
+public class EventManagerServlet extends HttpServlet {
+
+ // Servlet code
+}]]></programlisting>
+
+ <para>
+ O servlet manuseia somente requisições <literal>GET</literal>
do HTTP,
+ portanto o método que iremos implementar é
<literal>doGet()</literal>:
+ </para>
+
+ <programlisting><![CDATA[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();
+ throw new ServletException(ex);
+ }
+
+}]]></programlisting>
+
+ <para>
+ O pattern que estamos aplicando neste código é chamado
<emphasis>session-per-request</emphasis>.
+ Quando uma requisição chega ao servlet, uma nova
<literal>Session</literal> do Hibernate é
+ aberta através da primeira chamada para
<literal>getCurrentSession()</literal> em
+ <literal>SessionFactory</literal>. Então uma transação do
banco de dados é inicializada -
+ todo acesso a dados deve ocorrer dentro de uma transação, não importando
se o dado é de leitura ou escrita.
+ (nós não devemos usar o modo auto-commit em aplicações).
+
+ </para>
+ <para>
+ Do <emphasis>not</emphasis> use a new Hibernate
<literal>Session</literal> for
+ every database operation. Use one Hibernate <literal>Session</literal>
that is
+ scoped to the whole request. Use
<literal>getCurrentSession()</literal>, so that
+ it is automatically bound to the current Java thread.
+ </para>
+ <para>
+ Agora, as possibilidades de ações de uma requisição serão processadas e
uma resposta HTML será renderizada.
+ Nós já iremos chegar nesta parte.
+ </para>
+
+ <para>
+ Finalmente, a unidade de trabalho termina quando o processamento e a
restituição são completados.
+ Se ocorrer algum erro durante o processamento ou a restituição, uma
exceção será lançada e a
+ transação do banco de dados encerrada. Isso completa o pattern
<literal>session-per-request</literal>.
+ 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 site do Hibernate e do Wiki para maiores informações
sobre esse pattern,
+ chamado <emphasis>Open Session in View</emphasis>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-processing" revision="1">
+ <title>Processando e renderizando</title>
+
+ <para>
+ Vamos implementar o processamento da requisição e a restituição da página
HTML.
+ </para>
+
+<programlisting><![CDATA[// 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();]]></programlisting>
+
+ <para>
+ O estilo de código acima, misturando linguagem HTML e Java não será
funcional em um aplicativo
+ mais complexo—tenha em mente que neste manual nós estamos
apenas ilustrando conceitos
+ básicos do Hibernate. O código imprime um cabeçalho HTML e um rodapé.
Dentro desta página,
+ é mostrado um formulário em HTML, para entrada de novos eventos, e uma
lista de todos
+ os eventos contidos no banco de dados. O primeiro método é trivial e
apenas imprime
+ uma página HTML:
+ </para>
+
+ <programlisting><![CDATA[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>");
+}]]></programlisting>
+
+ <para>
+ O método <literal>listEvents()</literal> usa a
<literal>Session</literal> do Hibernate
+ associada a thread atual para executar um query:
+ </para>
+
+ <programlisting><![CDATA[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>");
+ for (Iterator it = result.iterator(); 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>");
+ }
+}]]></programlisting>
+
+ <para>
+ Finalmente, a action <literal>store</literal> é passada pra o
método
+ <literal>createAndStoreEvent()</literal>, que também usa a
+ <literal>Session</literal> da thread atual:
+ </para>
+
+ <programlisting><![CDATA[protected void createAndStoreEvent(String
title, Date theDate) {
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().save(theEvent);
+}]]></programlisting>
+
+ <para>
+ Pronto, o servlet está completo. Uma requisição para o servlet será
processada
+ em uma <literal>Session</literal> e uma
<literal>Transaction</literal> simples.
+ Como anteriormente, no aplicativo standalone, o Hibernate pode
automaticamente
+ associar esses objetos a thread atual em execução. Isso possibilita a
liberdade
+ de você modelar seu código e acessar o método
<literal>SessionFactory</literal>
+ do jeito que achar melhor. Geralmente você irá usar um design mais
sofisticado
+ e mover o código de acesso a dados para dentro de objetos de acesso a
dados
+ (o patter DAO). Leia o Hibernate Wiki para maiores exemplos.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-deploy">
+ <title>Instalando e testando</title>
+
+ <para>
+ Para fazer o deploy desta aplicação você tem que criar um arquivo para
web, um WAR.
+ Adicione o alvo Ant abaixo em seu
<literal>build.xml</literal>:
+ </para>
+
+<programlisting><![CDATA[<target name="war"
depends="compile">
+ <war destfile="hibernate-tutorial.war" webxml="web.xml">
+ <lib dir="${librarydir}">
+ <exclude name="jsdk*.jar"/>
+ </lib>
+
+ <classes dir="${targetdir}"/>
+ </war>
+</target>]]></programlisting>
+
+ <para>
+ Esta target cria um arquivo chamado
<literal>hibernate-tutorial.war</literal>
+ no diretório do seu projeto. Ele empacota todas as bibliotecas e o
arquivo de
+ descrição <literal>web.xml</literal>, o qual é esperado no
diretório base do seu projeto:
+ </para>
+
+ <programlisting><![CDATA[<?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>events.EventManagerServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Event Manager</servlet-name>
+ <url-pattern>/eventmanager</url-pattern>
+ </servlet-mapping>
+</web-app>]]></programlisting>
+
+ <para>
+ Antes de você compilar e fazer o deploy desta aplicação web, note que uma
biblioteca
+ adicional é requerida: <literal>jsdk.jar</literal>. Esse é o
Java servlet development kit,
+ se você não possui esta biblioteca, faça seu download na página da Sun e
copie-a
+ para seu diretório de bibliotecas. Entretanto, será usado somente para a
compilação e
+ excluído do pacote WAR.
+ </para>
+
+ <para>
+ Para compilar e instalar execute <literal>ant war</literal>
no seu diretório do projeto
+ e copie o arquivo <literal>hibernate-tutorial.war</literal>
para o diretório
+ <literal>webapp</literal> do Tomcat. Se você não possui o
Tomcat instalado faça
+ o download e siga as instruções de instalação. Você não precisa modificar
+ nenhuma configuração do Tomcat para rodar este aplicativo.
+ </para>
+
+ <para>
+ Uma vez feito o deploy e com Tomcat rodando, acesse o aplicativo em
+
<literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>.
+ Veja o log do Tomcat para observar a inicialização do Hibernate quando a
+ primeira requisição chega ao servlet (o inicializador estático dentro de
+ <literal>HibernateUtil</literal> é chamado) e para ter uma
depuração
+ detalhada se ocorrer alguma exceção.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="tutorial-summary" revision="1">
+ <title>Sumário</title>
+
+ <para>
+ Este manual cobriu os princípios básicos para criação de uma aplicação
simples do Hibernate
+ e uma pequena aplicação web.
+ </para>
+
+ <para>
+ Se você já se sente seguro com o Hibernate, continue navegando na
documentação de referência
+ por tópicos que você acha interessante – os tópicos mais questionados são:
+ processo de transação (<xref linkend="transactions"/>), uso
da API (<xref linkend="objectstate"/>)
+ e características de consulta (<xref
linkend="objectstate-querying"/>).
+ </para>
+
+ <para>
+ Não esqueça de visitar o site do Hibernate para obter mais tutoriais
especializados.
+ </para>
+
+ </sect1>
+
+</chapter>
Modified: core/trunk/documentation/manual/pt-BR/src/main/docbook/content/xml.xml
===================================================================
--- core/trunk/documentation/manual/pt-BR/src/main/docbook/content/xml.xml 2007-10-26
00:46:38 UTC (rev 14135)
+++ core/trunk/documentation/manual/pt-BR/src/main/docbook/content/xml.xml 2007-10-26
00:48:48 UTC (rev 14136)
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-<chapter id="xml">
+<chapter id="xml">
<title>Mapeamento XML</title>
<para><emphasis>