HHH-9986 - Fix reference manual inconsistencies for 5.0

This commit is contained in:
Steve Ebersole 2015-07-29 08:41:39 -05:00
parent 0b6ea757e3
commit ff565fddb0
152 changed files with 151 additions and 12140 deletions

View File

@ -1,92 +0,0 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<authorgroup xmlns="http://docbook.org/ns/docbook">
<author>
<personname>
<firstname>Gavin</firstname>
<surname>King</surname>
</personname>
</author>
<author>
<personname>
<firstname>Christian</firstname>
<surname>Bauer</surname>
</personname>
</author>
<author>
<personname>
<firstname>Steve</firstname>
<surname>Ebersole</surname>
</personname>
</author>
<author>
<personname>
<firstname>Max</firstname>
<othername>Rydahl</othername>
<surname>Andersen</surname>
</personname>
</author>
<author>
<personname>
<firstname>Emmanuel</firstname>
<surname>Bernard</surname>
</personname>
</author>
<author>
<personname>
<firstname>Hardy</firstname>
<surname>Ferentschik</surname>
</personname>
</author>
<author>
<personname>
<firstname>Adam</firstname>
<surname>Warski</surname>
</personname>
</author>
<author>
<personname>
<firstname>Gail</firstname>
<surname>Badner</surname>
</personname>
</author>
<author>
<personname>
<firstname>Brett</firstname>
<surname>Meyer</surname>
</personname>
</author>
<othercredit>
<personname>
<firstname>James</firstname>
<surname>Cobb</surname>
</personname>
<affiliation>
<shortaffil>Graphic Design</shortaffil>
</affiliation>
</othercredit>
<othercredit>
<personname>
<firstname>Cheyenne</firstname>
<surname>Weaver</surname>
</personname>
<affiliation>
<shortaffil>Graphic Design</shortaffil>
</affiliation>
</othercredit>
<editor>
<personname>
<firstname>Misty</firstname>
<surname>Stanley-Jones</surname>
</personname>
</editor>
</authorgroup>

View File

@ -1,252 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="batch">
<title>Batch Processing</title>
<para>
The following example shows an antipattern for batch inserts.
</para>
<example>
<title>Naive way to insert 100000 lines with Hibernate</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/batch_insert.java" parse="text" /></programlisting>
<para>
This fails with exception <systemitem>OutOfMemoryException</systemitem> after around 50000 rows on most
systems. The reason is that Hibernate caches all the newly inserted Customer instances in the session-level
cache. There are several ways to avoid this problem.
</para>
</example>
<para>
Before batch processing, enable JDBC batching. To enable JDBC batching, set the property
<property>hibernate.jdbc.batch_size</property> to an integer between 10 and 50.
</para>
<note>
<para>
Hibernate disables insert batching at the JDBC level transparently if you use an identity identifier generator.
</para>
</note>
<para>
If the above approach is not appropriate, you can disable the second-level cache, by setting
<property>hibernate.cache.use_second_level_cache</property> to <literal>false</literal>.
</para>
<section>
<title>Batch inserts</title>
<para>
When you make new objects persistent, employ methods <methodname>flush()</methodname> and
<methodname>clear()</methodname> to the session regularly, to control the size of the first-level cache.
</para>
<example>
<title>Flushing and clearing the <classname>Session</classname></title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/flush_and_clear_session.java" parse="text" /></programlisting>
</example>
</section>
<section>
<title>Batch updates</title>
<para>
When you retriev and update data, <methodname>flush()</methodname> and <methodname>clear()</methodname> the
session regularly. In addition, use method <methodname>scroll()</methodname> to take advantage of server-side
cursors for queries that return many rows of data.
</para>
<example>
<title>Using <methodname>scroll()</methodname></title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/using_scroll.java" parse="text" /></programlisting>
</example>
</section>
<section>
<title>StatelessSession</title>
<para>
<interfacename>StatelessSession</interfacename> is a command-oriented API provided by Hibernate. Use it to stream
data to and from the database in the form of detached objects. A <interfacename>StatelessSession</interfacename>
has no persistence context associated with it and does not provide many of the higher-level life cycle
semantics. Some of the things not provided by a <interfacename>StatelessSession</interfacename> include:
</para>
<itemizedlist>
<title>Features and behaviors not provided by <interfacename>StatelessSession</interfacename></title>
<listitem>
<para>
a first-level cache
</para>
</listitem>
<listitem>
<para>
interaction with any second-level or query cache
</para>
</listitem>
<listitem>
<para>
transactional write-behind or automatic dirty checking
</para>
</listitem>
</itemizedlist>
<itemizedlist>
<title>Limitations of <interfacename>StatelessSession</interfacename></title>
<listitem>
<para>
Operations performed using a stateless session never cascade to associated instances.
</para>
</listitem>
<listitem>
<para>
Collections are ignored by a stateless session.
</para>
</listitem>
<listitem>
<para>
Operations performed via a stateless session bypass Hibernate's event model and interceptors.
</para>
</listitem>
<listitem>
<para>
Due to the lack of a first-level cache, Stateless sessions are vulnerable to data aliasing effects.
</para>
</listitem>
<listitem>
<para>
A stateless session is a lower-level abstraction that is much closer to the underlying JDBC.
</para>
</listitem>
</itemizedlist>
<example>
<title>Using a <interfacename>StatelessSession</interfacename></title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/using_a_StatelessSession.java" parse="text" /></programlisting>
<para>
The <classname>Customer</classname> instances returned by the query are immediately detached. They are never
associated with any persistence context.
</para>
</example>
<para>
The <methodname>insert()</methodname>, <methodname>update()</methodname>, and <methodname>delete()</methodname>
operations defined by the <interfacename>StatelessSession</interfacename> interface operate directly on database
rows. They cause the corresponding SQL operations to be executed immediately. They have different semantics from
the <methodname>save()</methodname>, <methodname>saveOrUpdate()</methodname>, and
<methodname>delete()</methodname> operations defined by the <interfacename>Session</interfacename> interface.
</para>
</section>
<section>
<title>Hibernate Query Language for DML</title>
<para>
DML, or <firstterm>Data Markup Language</firstterm>, refers to SQL statements such as <literal>INSERT</literal>,
<literal>UPDATE</literal>, and <literal>DELETE</literal>. Hibernate provides methods for bulk SQL-style DML
statement execution, in the form of <firstterm>Hibernate Query Language (HQL)</firstterm>.
</para>
<section>
<title>HQL for UPDATE and DELETE</title>
<example>
<title>Psuedo-syntax for UPDATE and DELETE statements using HQL</title>
<screen>
( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?
</screen>
<para>
The <literal>?</literal> suffix indications an optional parameter. The <literal>FROM</literal> and
<literal>WHERE</literal> clauses are each optional.
</para>
</example>
<para>
The <literal>FROM</literal> clause can only refer to a single entity, which can be aliased. If the entity name
is aliased, any property references must be qualified using that alias. If the entity name is not aliased, then
it is illegal for any property references to be qualified.
</para>
<para>
Joins, either implicit or explicit, are prohibited in a bulk HQL query. You can use sub-queries in the
<literal>WHERE</literal> clause, and the sub-queries themselves can contain joins.
</para>
<example>
<title>Executing an HQL UPDATE, using the <methodname>Query.executeUpdate()</methodname> method</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/executeUpdate.java" parse="text" /></programlisting>
</example>
<para>
In keeping with the EJB3 specification, HQL UPDATE statements, by default, do not effect the version or the
timestamp property values for the affected entities. You can use a versioned update to force Hibernate to reset
the version or timestamp property values, by adding the <literal>VERSIONED</literal> keyword after the
<literal>UPDATE</literal> keyword.
</para>
<example>
<title>Updating the version of timestamp</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/updating_version.java" parse="text" /></programlisting>
</example>
<note>
<para>
If you use the <literal>VERSIONED</literal> statement, you cannot use custom version types, which use class
<classname>org.hibernate.usertype.UserVersionType</classname>.
</para>
</note>
<example>
<title>A HQL <literal>DELETE</literal> statement</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/hql_delete.java" parse="text" /></programlisting>
</example>
<para>
Method <methodname>Query.executeUpdate()</methodname> returns an <type>int</type> value, which indicates the
number of entities effected by the operation. This may or may not correlate to the number of rows effected in
the database. An HQL bulk operation might result in multiple SQL statements being executed, such as for
joined-subclass. In the example of joined-subclass, a <literal>DELETE</literal> against one of the subclasses
may actually result in deletes in the tables underlying the join, or further down the inheritance hierarchy.
</para>
</section>
<section>
<title>HQL syntax for INSERT</title>
<example>
<title>Pseudo-syntax for INSERT statements</title>
<screen>
INSERT INTO EntityName <replaceable>properties_list</replaceable> <replaceable>select_statement</replaceable>
</screen>
</example>
<para>
Only the <literal>INSERT INTO ... SELECT ...</literal> form is supported. You cannot specify explicit values to
insert.
</para>
<para>
The <replaceable>properties_list</replaceable> is analogous to the column specification in the <literal>SQL
INSERT</literal> statement. For entities involved in mapped inheritance, you can only use properties directly
defined on that given class-level in the <replaceable>properties_list</replaceable>. Superclass properties are
not allowed and subclass properties are irrelevant. In other words, <literal>INSERT</literal> statements are
inherently non-polymorphic.
</para>
<para>
The <replaceable>select_statement</replaceable> can be any valid HQL select query, but the return types must
match the types expected by the INSERT. Hibernate verifies the return types during query compilation, instead of
expecting the database to check it. Problems might result from Hibernate types which are equivalent, rather than
equal. One such example is a mismatch between a property defined as an <type>org.hibernate.type.DateType</type>
and a property defined as an <type>org.hibernate.type.TimestampType</type>, even though the database may not
make a distinction, or may be capable of handling the conversion.
</para>
<para>
If <replaceable>id</replaceable> property is not specified in the <replaceable>properties_list</replaceable>,
Hibernate generates a value automatically. Automatic generation is only available if you use ID generators which
operate on the database. Otherwise, Hibernate throws an exception during parsing. Available in-database
generators are <classname>org.hibernate.id.SequenceGenerator</classname> and its subclasses, and objects which
implement <interfacename>org.hibernate.id.PostInsertIdentifierGenerator</interfacename>. The most notable
exception is <classname>org.hibernate.id.TableHiLoGenerator</classname>, which does not expose a selectable way
to get its values.
</para>
<para>
For properties mapped as either version or timestamp, 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 seed value defined by the
org.hibernate.type.VersionType is used.
</para>
<example>
<title>HQL INSERT statement</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/hql-insert.java" parse="text" /></programlisting>
</example>
</section>
<section>
<title>More information on HQL</title>
<para>
This section is only a brief overview of HQL. For more information, see <xref linkend="chap-hql" />.
</para>
</section>
</section>
</chapter>

View File

@ -1,557 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>Caching</title>
</info>
<section>
<title>The query cache</title>
<para>
If you have queries that run over and over, with the same parameters, query caching provides performance gains.
</para>
<para>
Caching introduces overhead in the area of transactional processing. For example, if you cache results of a query
against an object, Hibernate needs to keep track of whether any changes have been committed against the object,
and invalidate the cache accordingly. In addition, the benefit from caching query results is limited, and highly
dependent on the usage patterns of your application. For these reasons, Hibernate disables the query cache by
default.
</para>
<procedure>
<title>Enabling the query cache</title>
<step>
<title>Set the <property>hibernate.cache.use_query_cache</property> property to <literal>true</literal>.</title>
<para>
This setting creates two new cache regions:
</para>
<itemizedlist>
<listitem>
<para>
<code>org.hibernate.cache.internal.StandardQueryCache</code> holds the cached query results.
</para>
</listitem>
<listitem>
<para>
<code>org.hibernate.cache.spi.UpdateTimestampsCache</code> holds timestamps of the most recent updates to
queryable tables. These timestamps validate results served from the query cache.
</para>
</listitem>
</itemizedlist>
</step>
<step>
<title>Adjust the cache timeout of the underlying cache region</title>
<para>
If you configure your underlying cache implementation to use expiry or timeouts, set the cache timeout of the
underlying cache region for the <code>UpdateTimestampsCache</code> to a higher value than the timeouts of any
of the query caches. It is possible, and recommended, to set the UpdateTimestampsCache region never to
expire. To be specific, a LRU (Least Recently Used) cache expiry policy is never appropriate.
</para>
</step>
<step>
<title>Enable results caching for specific queries</title>
<para>
Since most queries do not benefit from caching of their results, you need to enable caching for individual
queries, e ven after enabling query caching overall. To enable results caching for a particular query, call
<methodname>org.hibernate.Query.setCacheable(true)</methodname>. This call allows the query to look for
existing cache results or add its results to the cache when it is executed.
</para>
</step>
</procedure>
<para>
The query cache does not cache the state of the actual entities in the cache. It caches identifier values and
results of value type. Therefore, always use the query cache in conjunction with the second-level
cache for those entities which should be cached as part of a query result cache.
</para>
<section>
<title>Query cache regions</title>
<para>
For fine-grained control over query cache expiration policies, specify a named cache region for a particular
query by calling <methodname>Query.setCacheRegion()</methodname>.
</para>
<example>
<title>Method <methodname>setCacheRegion</methodname></title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/setCacheRegion.java" parse="text" /></programlisting>
</example>
<para>
To force the query cache to refresh one of its regions and disregard any cached results in the region, call
<code>org.hibernate.Query.setCacheMode(CacheMode.REFRESH)</code>. In conjunction with the region defined for the
given query, Hibernate selectively refreshes the results cached in that particular region. This is much more
efficient than bulk eviction of the region via <code>org.hibernate.SessionFactory.evictQueries()</code>.
</para>
</section>
</section>
<section>
<title>Second-level cache providers</title>
<para>
Hibernate is compatible with several second-level cache providers. None of the providers support all of
Hibernate's possible caching strategies. <xref linkend="caching-provider-table" /> lists the providers, along with
their interfaces and supported caching strategies. For definitions of caching strategies, see <xref
linkend="caching-strategies-list" />.
</para>
<section>
<title>Configuring your cache providers</title>
<para>
You can configure your cache providers using either annotations or mapping files.
</para>
<formalpara>
<title>Entities</title>
<para>
By default, entities are not part of the second-level cache, and their use is not recommended. If you
absolutely must use entities, set the <code>shared-cache-mode</code> element in
<filename>persistence.xml</filename>, or use property <property>javax.persistence.sharedCache.mode</property>
in your configuration. Use one of the values in <xref linkend="shared-cache-mode-values" />.
</para>
</formalpara>
<table id="shared-cache-mode-values">
<title>Possible values for Shared Cache Mode</title>
<tgroup cols="2">
<thead>
<row>
<entry>Value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>ENABLE_SELECTIVE</entry>
<entry>
<para>
Entities are not cached unless you explicitly mark them as cachable. This is the default and
recommended value.
</para>
</entry>
</row>
<row>
<entry>DISABLE_SELECTIVE</entry>
<entry>
<para>
Entities are cached unless you explicitly mark them as not cacheable.
</para>
</entry>
</row>
<row>
<entry>ALL</entry>
<entry>
<para>
All entities are always cached even if you mark them as not cacheable.
</para>
</entry>
</row>
<row>
<entry>NONE</entry>
<entry>
<para>
No entities are cached even if you mark them as cacheable. This option basically disables second-level
caching.
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
Set the global default cache concurrency strategy The cache concurrency strategy with the
<property>hibernate.cache.default_cache_concurrency_strategy</property> configuration property. See <xref
linkend="caching-strategies-list" /> for possible values.
</para>
<note>
<para>
When possible, define the cache concurrency strategy per entity rather than globally. Use the
<code>@org.hibernate.annotations.Cache</code> annotation.
</para>
</note>
<example id="configuring-cache-providers-annotations">
<title>Configuring cache providers using annotations</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/cache_providers_mapping.java" parse="text" /></programlisting>
<para>
You can cache the content of a collection or the identifiers, if the collection contains other entities. Use
the <code>@Cache</code> annotation on the Collection property.
</para>
<para>
<code>@Cache</code> can take several attributes.
</para>
<variablelist>
<title>Attributes of <code>@Cache</code> annotation</title>
<varlistentry>
<term>usage</term>
<listitem>
<para>
The given cache concurrency strategy, which may be:
</para>
<itemizedlist>
<listitem>
<para>
<literal>NONE</literal>
</para>
</listitem>
<listitem>
<para>
<literal>READ_ONLY</literal>
</para>
</listitem>
<listitem>
<para>
<literal>NONSTRICT_READ_WRITE</literal>
</para>
</listitem>
<listitem>
<para>
<literal>READ_WRITE</literal>
</para>
</listitem>
<listitem>
<para>
<literal>TRANSACTIONAL</literal>
</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>region</term>
<listitem>
<para>
The cache region. This attribute is optional, and defaults to the fully-qualified class name of the
class, or the qually-qualified role name of the collection.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>include</term>
<listitem>
<para>
Whether or not to include all properties.. Optional, and can take one of two possible values.
</para>
<itemizedlist>
<listitem>
<para>
A value of <literal>all</literal> includes all properties. This is the default.
</para>
</listitem>
<listitem>
<para>
A value of <literal>non-lazy</literal> only includes non-lazy properties.
</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
</example>
<example>
<title>Configuring cache providers using mapping files</title>
<programlisting language="XML" role="XML"><xi:include href="extras/cache_providers.xml" parse="text" /></programlisting>
<para>
Just as in the <xref linkend="configuring-cache-providers-annotations" />, you can provide attributes in the
mapping file. There are some specific differences in the syntax for the attributes in a mapping file.
</para>
<variablelist>
<varlistentry>
<term>usage</term>
<listitem>
<para>
The caching strategy. This attribute is required, and can be any of the following values.
</para>
<itemizedlist>
<listitem><para>transactional</para></listitem>
<listitem><para>read-write</para></listitem>
<listitem><para>nonstrict-read-write</para></listitem>
<listitem><para>read-only</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>region</term>
<listitem>
<para>
The name of the second-level cache region. This optional attribute defaults to the class or collection
role name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>include</term>
<listitem>
<para>
Whether properties of the entity mapped with <literal>lazy=true</literal> can be cached when
attribute-level lazy fetching is enabled. Defaults to <literal>all</literal> and can also be
<literal>non-lazy</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Instead of <code>&lt;cache&gt;</code>, you can use <code>&lt;class-cache&gt;</code> and
<code>&lt;collection-cache&gt;</code> elements in <filename>hibernate.cfg.xml</filename>.
</para>
</example>
</section>
<section id="caching-strategies-list" revision="1">
<title>Caching strategies</title>
<variablelist>
<varlistentry>
<term>read-only</term>
<listitem>
<para>
A read-only cache is good for data that needs to be read often but not modified. It is simple, performs
well, and is safe to use in a clustered environment.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>nonstrict-read-write</term>
<listitem>
<para>
Some applications only rarely need to modify data. This is the case if two transactions are unlikely to
try to update the same item simultaneously. In this case, you do not need strict transaction isolation,
and a nonstrict-read-write cache might be appropriate. If the cache is used in a JTA environment, you must
specify <classname>hibernate.transaction.manager_lookup_class</classname>. In other environments, ensore
that the transaction is complete before you call <methodname>Session.close()</methodname> or
<methodname>Session.disconnect()</methodname>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>read-write</term>
<listitem>
<para>
A read-write cache is appropriate for an application which needs to update data regularly. Do not use a
read-write strategy if you need serializable transaction isolation. In a JTA environment, specify a
strategy for obtaining the JTA TransactionManager by setting the property
<property>hibernate.transaction.manager_lookup_class</property>. In non-JTA environments, be sure the
transaction is complete before you call <methodname>Session.close()</methodname> or
<methodname>Session.disconnect()</methodname>.
</para>
<note>
<para>
To use the read-write strategy in a clustered environment, the underlying cache implementation must
support locking. The build-in cache providers do not support locking.
</para>
</note>
</listitem>
</varlistentry>
<varlistentry>
<term>transactional</term>
<listitem>
<para>
The transactional cache strategy provides support for transactional cache providers such as JBoss
TreeCache. You can only use such a cache in a JTA environment, and you must first specify
<classname>hibernate.transaction.manager_lookup_class</classname>.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="caching-provider-table" revision="1">
<title>Second-level cache providers for Hibernate</title>
<informaltable>
<tgroup cols="5">
<thead>
<row>
<entry>Cache</entry>
<entry>Interface</entry>
<entry>Supported strategies</entry>
</row>
</thead>
<tbody>
<row>
<entry>HashTable (testing only)</entry>
<entry></entry>
<entry>
<itemizedlist>
<listitem><para>read-only</para></listitem>
<listitem><para>nonstrict-read-write</para></listitem>
<listitem><para>read-write</para></listitem>
</itemizedlist>
</entry>
</row>
<row>
<entry>EHCache</entry>
<entry></entry>
<entry>
<itemizedlist>
<listitem><para>read-only</para></listitem>
<listitem><para>nonstrict-read-write</para></listitem>
<listitem><para>read-write</para></listitem>
<listitem><para>transactional</para></listitem>
</itemizedlist>
</entry>
</row>
<row>
<entry>Infinispan</entry>
<entry></entry>
<entry>
<itemizedlist>
<listitem><para>read-only</para></listitem>
<listitem><para>transactional</para></listitem>
</itemizedlist>
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
</section>
<section>
<title>Managing the cache</title>
<section>
<title>Moving items into and out of the cache</title>
<variablelist>
<title>Actions that add an item to internal cache of the Session</title>
<varlistentry>
<term>Saving or updating an item</term>
<listitem>
<itemizedlist>
<listitem>
<para>
<methodname>save()</methodname>
</para>
</listitem>
<listitem>
<para>
<methodname>update()</methodname>
</para>
</listitem>
<listitem>
<para>
<methodname>saveOrUpdate()</methodname>
</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>Retrieving an item</term>
<listitem>
<itemizedlist>
<listitem>
<para>
<methodname>load()</methodname>
</para>
</listitem>
<listitem>
<para>
<methodname>get()</methodname>
</para>
</listitem>
<listitem>
<para>
<methodname>list()</methodname>
</para>
</listitem>
<listitem>
<para>
<methodname>iterate()</methodname>
</para>
</listitem>
<listitem>
<para>
<methodname>scroll()</methodname>
</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
<formalpara>
<title>Syncing or removing a cached item</title>
<para>
The state of an object is synchronized with the database when you call method
<methodname>flush()</methodname>. To avoid this synchronization, you can remove the object and all collections
from the first-level cache with the <methodname>evict()</methodname> method. To remove all items from the
Session cache, use method <methodname>Session.clear()</methodname>.
</para>
</formalpara>
<example>
<title>Evicting an item from the first-level cache</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/evicting_item.java" parse="text" /></programlisting>
</example>
<formalpara>
<title>Determining whether an item belongs to the Session cache</title>
<para>
The Session provides a <methodname>contains()</methodname> method to determine if an instance belongs to the
session cache.
</para>
</formalpara>
<example>
<title>Second-level cache eviction</title>
<para>
You can evict the cached state of an instance, entire class, collection instance or entire collection role,
using methods of <classname>SessionFactory</classname>.
</para>
<programlisting language="Java" role="JAVA"><xi:include href="extras/evicting_from_second_level_cache.java" parse="text" /></programlisting>
</example>
<section>
<title>Interactions between a Session and the second-level cache</title>
<para>
The CacheMode controls how a particular session interacts with the second-level cache.
</para>
<informaltable>
<tgroup cols="2">
<tbody>
<row>
<entry>CacheMode.NORMAL</entry>
<entry>reads items from and writes them to the second-level cache.</entry>
</row>
<row>
<entry>CacheMode.GET</entry>
<entry>reads items from the second-level cache, but does not write to the second-level cache except to
update data.</entry>
</row>
<row>
<entry>CacheMode.PUT</entry>
<entry>writes items to the second-level cache. It does not read from the second-level cache. It bypasses
the effect of <property>hibernate.cache.use_minimal_puts</property> and forces a refresh of the
second-level cache for all items read from the database.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title>Browsing the contents of a second-level or query cache region</title>
<para>
After enabling statistics, you can browse the contents of a second-level cache or query cache region.
</para>
<procedure>
<title>Enabling Statistics</title>
<step>
<para>
Set <code>hibernate.generate_statistics</code> to <literal>true</literal>.
</para>
</step>
<step>
<para>
Optionally, set <code>hibernate.cache.use_structured_entries</code> to <literal>true</literal>, to cause
Hibernate to store the cache entries in a human-readable format.
</para>
</step>
</procedure>
<example>
<title>Browsing the second-level cache entries via the Statistics API</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/browsing_cache.java" parse="text" /></programlisting>
</example>
</section>
</section>
</section>
</chapter>

View File

@ -1,458 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook">
<title>Data categorizations</title>
<para>
Hibernate understands both the Java and JDBC representations of application data. The ability to read and write
object data to a database is called <firstterm>marshalling</firstterm>, and is the function of a Hibernate
<classname>type</classname>. A <classname>type</classname> is an implementation of the
<interfacename>org.hibernate.type.Type</interfacename> interface. A Hibernate <classname>type</classname> describes
various aspects of behavior of the Java type such as how to check for equality and how to clone values.
</para>
<note>
<title>Usage of the word <wordasword>type</wordasword></title>
<para>
A Hibernate <classname>type</classname> is neither a Java type nor a SQL datatype. It provides information about
both of these.
</para>
<para>
When you encounter the term <firstterm>type</firstterm> in regards to Hibernate, it may refer to the Java type,
the JDBC type, or the Hibernate type, depending on context.
</para>
</note>
<para>
Hibernate categorizes types into two high-level groups: <xref linkend="value-types" />
and <xref linkend="entity-types" />.
</para>
<section xml:id="value-types">
<title>Value types</title>
<para>
A <firstterm>value type</firstterm> does not define its own lifecycle. It is, in effect, owned by an <xref
linkend="entity-types" />, which defines its
lifecycle. Value types are further classified into three sub-categories.
</para>
<itemizedlist>
<listitem><para><xref linkend="value-basic-types" /></para></listitem>
<listitem><para><xref linkend="value-national-character-types" /></para></listitem>
<listitem><para><xref linkend="value-composite-types" /></para></listitem>
<listitem><para><xref linkend="value-collection-types" /></para></listitem>
</itemizedlist>
<section xml:id="value-basic-types">
<title>Basic types</title>
<para>
Basic value types usually map a single database value, or column, to a single, non-aggregated Java
type. Hibernate provides a number of built-in basic types, which follow the natural mappings recommended in the
JDBC specifications. You can override these mappings and provide and use alternative mappings. These topics are
discussed further on.
</para>
<table>
<title>Basic Type Mappings</title>
<tgroup cols="4">
<thead>
<row>
<entry>Hibernate type</entry>
<entry>Database type</entry>
<entry>JDBC type</entry>
<entry>Type registry</entry>
</row>
</thead>
<tbody>
<row>
<entry>org.hibernate.type.StringType</entry>
<entry>string</entry>
<entry>VARCHAR</entry>
<entry>string, java.lang.String</entry>
</row>
<row>
<entry>org.hibernate.type.MaterializedClob</entry>
<entry>string</entry>
<entry>CLOB</entry>
<entry>materialized_clob</entry>
</row>
<row>
<entry>org.hibernate.type.TextType</entry>
<entry>string</entry>
<entry>LONGVARCHAR</entry>
<entry>text</entry>
</row>
<row>
<entry>org.hibernate.type.CharacterType</entry>
<entry>char, java.lang.Character</entry>
<entry>CHAR</entry>
<entry>char, java.lang.Character</entry>
</row>
<row>
<entry>org.hibernate.type.BooleanType</entry>
<entry>boolean</entry>
<entry>BIT</entry>
<entry>boolean, java.lang.Boolean</entry>
</row>
<row>
<entry>org.hibernate.type.NumericBooleanType</entry>
<entry>boolean</entry>
<entry>INTEGER, 0 is false, 1 is true</entry>
<entry>numeric_boolean</entry>
</row>
<row>
<entry>org.hibernate.type.YesNoType</entry>
<entry>boolean</entry>
<entry>CHAR, 'N'/'n' is false, 'Y'/'y' is true. The uppercase value is written to the database.</entry>
<entry>yes_no</entry>
</row>
<row>
<entry>org.hibernate.type.TrueFalseType</entry>
<entry>boolean</entry>
<entry>CHAR, 'F'/'f' is false, 'T'/'t' is true. The uppercase value is written to the database.</entry>
<entry>true_false</entry>
</row>
<row>
<entry>org.hibernate.type.ByteType</entry>
<entry>byte, java.lang.Byte</entry>
<entry>TINYINT</entry>
<entry>byte, java.lang.Byte</entry>
</row>
<row>
<entry>org.hibernate.type.ShortType</entry>
<entry>short, java.lang.Short</entry>
<entry>SMALLINT</entry>
<entry>short, java.lang.Short</entry>
</row>
<row>
<entry>org.hibernate.type.IntegerTypes</entry>
<entry>int, java.lang.Integer</entry>
<entry>INTEGER</entry>
<entry>int, java.lang.Integer</entry>
</row>
<row>
<entry>org.hibernate.type.LongType</entry>
<entry>long, java.lang.Long</entry>
<entry>BIGINT</entry>
<entry>long, java.lang.Long</entry>
</row>
<row>
<entry>org.hibernate.type.FloatType</entry>
<entry>float, java.lang.Float</entry>
<entry>FLOAT</entry>
<entry>float, java.lang.Float</entry>
</row>
<row>
<entry>org.hibernate.type.DoubleType</entry>
<entry>double, java.lang.Double</entry>
<entry>DOUBLE</entry>
<entry>double, java.lang.Double</entry>
</row>
<row>
<entry>org.hibernate.type.BigIntegerType</entry>
<entry>java.math.BigInteger</entry>
<entry>NUMERIC</entry>
<entry>big_integer</entry>
</row>
<row>
<entry>org.hibernate.type.BigDecimalType</entry>
<entry>java.math.BigDecimal</entry>
<entry>NUMERIC</entry>
<entry>big_decimal, java.math.bigDecimal</entry>
</row>
<row>
<entry>org.hibernate.type.TimestampType</entry>
<entry>java.sql.Timestamp</entry>
<entry>TIMESTAMP</entry>
<entry>timestamp, java.sql.Timestamp</entry>
</row>
<row>
<entry>org.hibernate.type.TimeType</entry>
<entry>java.sql.Time</entry>
<entry>TIME</entry>
<entry>time, java.sql.Time</entry>
</row>
<row>
<entry>org.hibernate.type.DateType</entry>
<entry>java.sql.Date</entry>
<entry>DATE</entry>
<entry>date, java.sql.Date</entry>
</row>
<row>
<entry>org.hibernate.type.CalendarType</entry>
<entry>java.util.Calendar</entry>
<entry>TIMESTAMP</entry>
<entry>calendar, java.util.Calendar</entry>
</row>
<row>
<entry>org.hibernate.type.CalendarDateType</entry>
<entry>java.util.Calendar</entry>
<entry>DATE</entry>
<entry>calendar_date</entry>
</row>
<row>
<entry>org.hibernate.type.CurrencyType</entry>
<entry>java.util.Currency</entry>
<entry>VARCHAR</entry>
<entry>currency, java.util.Currency</entry>
</row>
<row>
<entry>org.hibernate.type.LocaleType</entry>
<entry>java.util.Locale</entry>
<entry>VARCHAR</entry>
<entry>locale, java.utility.locale</entry>
</row>
<row>
<entry>org.hibernate.type.TimeZoneType</entry>
<entry>java.util.TimeZone</entry>
<entry>VARCHAR, using the TimeZone ID</entry>
<entry>timezone, java.util.TimeZone</entry>
</row>
<row>
<entry>org.hibernate.type.UrlType</entry>
<entry>java.net.URL</entry>
<entry>VARCHAR</entry>
<entry>url, java.net.URL</entry>
</row>
<row>
<entry>org.hibernate.type.ClassType</entry>
<entry>java.lang.Class</entry>
<entry>VARCHAR, using the class name</entry>
<entry>class, java.lang.Class</entry>
</row>
<row>
<entry>org.hibernate.type.BlobType</entry>
<entry>java.sql.Blob</entry>
<entry>BLOB</entry>
<entry>blog, java.sql.Blob</entry>
</row>
<row>
<entry>org.hibernate.type.ClobType</entry>
<entry>java.sql.Clob</entry>
<entry>CLOB</entry>
<entry>clob, java.sql.Clob</entry>
</row>
<row>
<entry>org.hibernate.type.BinaryType</entry>
<entry>primitive byte[]</entry>
<entry>VARBINARY</entry>
<entry>binary, byte[]</entry>
</row>
<row>
<entry>org.hibernate.type.MaterializedBlobType</entry>
<entry>primitive byte[]</entry>
<entry>BLOB</entry>
<entry>materized_blob</entry>
</row>
<row>
<entry>org.hibernate.type.ImageType</entry>
<entry>primitive byte[]</entry>
<entry>LONGVARBINARY</entry>
<entry>image</entry>
</row>
<row>
<entry>org.hibernate.type.BinaryType</entry>
<entry>java.lang.Byte[]</entry>
<entry>VARBINARY</entry>
<entry>wrapper-binary</entry>
</row>
<row>
<entry>org.hibernate.type.CharArrayType</entry>
<entry>char[]</entry>
<entry>VARCHAR</entry>
<entry>characters, char[]</entry>
</row>
<row>
<entry>org.hibernate.type.CharacterArrayType</entry>
<entry>java.lang.Character[]</entry>
<entry>VARCHAR</entry>
<entry>wrapper-characters, Character[], java.lang.Character[]</entry>
</row>
<row>
<entry>org.hibernate.type.UUIDBinaryType</entry>
<entry>java.util.UUID</entry>
<entry>BINARY</entry>
<entry>uuid-binary, java.util.UUID</entry>
</row>
<row>
<entry>org.hibernate.type.UUIDCharType</entry>
<entry>java.util.UUID</entry>
<entry>CHAR, can also read VARCHAR</entry>
<entry>uuid-char</entry>
</row>
<row>
<entry>org.hibernate.type.PostgresUUIDType</entry>
<entry>java.util.UUID</entry>
<entry>PostgreSQL UUID, through Types#OTHER, which complies to the PostgreSQL JDBC driver
definition</entry>
<entry>pg-uuid</entry>
</row>
<row>
<entry>org.hibernate.type.SerializableType</entry>
<entry>implementors of java.lang.Serializable</entry>
<entry>VARBINARY</entry>
<entry> Unlike the other value types, multiple instances of this type are registered. It is registered
once under java.io.Serializable, and registered under the specific java.io.Serializable implementation
class names.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section xml:id="value-national-character-types">
<title>National Character Types</title>
<para>
National Character types, which is a new feature since JDBC 4.0 API, now available in hibernate type system.
National Language Support enables you retrieve data or insert data into a database in any character
set that the underlying database supports.
</para>
<para>
Depending on your environment, you might want to set the configuration option <property>hibernate.use_nationalized_character_data</property>
to true and having all string or clob based attributes having this national character support automatically.
There is nothing else to be changed, and you don't have to use any hibernate specific mapping, so it is portable
( though the national character support feature is not required and may not work on other JPA provider impl ).
</para>
<para>
The other way of using this feature is having the <classname>@Nationalized</classname> annotation on the attribute
that should be nationalized. This only works on string based attributes, including string, char, char array and clob.
<programlisting role="JAVA">
@Entity( name="NationalizedEntity")
public static class NationalizedEntity {
@Id
private Integer id;
@Nationalized
private String nvarcharAtt;
@Lob
@Nationalized
private String materializedNclobAtt;
@Lob
@Nationalized
private NClob nclobAtt;
@Nationalized
private Character ncharacterAtt;
@Nationalized
private Character[] ncharArrAtt;
@Type(type = "ntext")
private String nlongvarcharcharAtt;
}</programlisting>
</para>
<table>
<title>National Character Type Mappings</title>
<tgroup cols="4">
<thead>
<row>
<entry>Hibernate type</entry>
<entry>Database type</entry>
<entry>JDBC type</entry>
<entry>Type registry</entry>
</row>
</thead>
<tbody>
<row>
<entry>org.hibernate.type.StringNVarcharType</entry>
<entry>string</entry>
<entry>NVARCHAR</entry>
<entry>nstring</entry>
</row>
<row>
<entry>org.hibernate.type.NTextType</entry>
<entry>string</entry>
<entry>LONGNVARCHAR</entry>
<entry>materialized_clob</entry>
</row>
<row>
<entry>org.hibernate.type.NClobType</entry>
<entry>java.sql.NClob</entry>
<entry>NCLOB</entry>
<entry>nclob</entry>
</row>
<row>
<entry>org.hibernate.type.MaterializedNClobType</entry>
<entry>string</entry>
<entry>NCLOB</entry>
<entry>materialized_nclob</entry>
</row>
<row>
<entry>org.hibernate.type.PrimitiveCharacterArrayNClobType</entry>
<entry>char[]</entry>
<entry>NCHAR</entry>
<entry>char[]</entry>
</row>
<row>
<entry>org.hibernate.type.CharacterNCharType</entry>
<entry>java.lang.Character</entry>
<entry>NCHAR</entry>
<entry>ncharacter</entry>
</row>
<row>
<entry>org.hibernate.type.CharacterArrayNClobType</entry>
<entry>java.lang.Character[]</entry>
<entry>NCLOB</entry>
<entry>Character[], java.lang.Character[]</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section xml:id="value-composite-types">
<title>Composite types</title>
<para>
<firstterm>Composite types</firstterm>, or <firstterm>embedded types</firstterm>, as they are called by the Java
Persistence API, have traditionally been called <firstterm>components</firstterm> in Hibernate. All of these
terms mean the same thing.
</para>
<para>
Components represent aggregations of values into a single Java type. An example is an
<classname>Address</classname> class, which aggregates street, city, state, and postal code. A composite type
behaves in a similar way to an entity. They are each classes written specifically for an application. They may
both include references to other application-specific classes, as well as to collections and simple JDK
types. The only distinguishing factors are that a component does not have its own lifecycle or define an
identifier.
</para>
</section>
<section xml:id="value-collection-types">
<title>Collection types</title>
<para>
A <firstterm>collection</firstterm> type refers to the data type itself, not its contents.
</para>
<para>
A Collection denotes a one-to-one or one-to-many relationship between tables of a database.
</para>
<para>
Refer to the chapter on Collections for more information on collections.
</para>
</section>
</section>
<section xml:id="entity-types">
<title>Entity Types</title>
<para>
Entities are application-specific classes which correlate to rows in a table, using a unique identifier. Because
of the requirement for a unique identifier, ntities exist independently and define their own lifecycle. As an
example, deleting a Membership should not delete the User or the Group. For more information, see the chapter on
Persistent Classes.
</para>
</section>
<section>
<title>Implications of different data categorizations</title>
<para>
NEEDS TO BE WRITTEN
</para>
</section>
</chapter>

View File

@ -1,916 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Database access</title>
<section>
<title>Connecting</title>
<para>
Hibernate connects to databases on behalf of your application. It can connect through a variety of mechanisms,
including:
</para>
<itemizedlist>
<listitem><para>Stand-alone built-in connection pool</para></listitem>
<listitem><para><classname>javax.sql.DataSource</classname></para></listitem>
<listitem><para>Connection pools, including support for two different third-party opensource JDBC connection pools:</para>
<itemizedlist>
<listitem><para>c3p0</para></listitem>
<listitem><para>proxool</para></listitem>
</itemizedlist>
</listitem>
<listitem>
<para>Application-supplied JDBC connections. This is not a recommended approach and exists for legacy reasons</para>
</listitem>
</itemizedlist>
<note>
<para>The built-in connection pool is not intended for production environments.</para>
</note>
<para>
Hibernate obtains JDBC connections as needed though the
<interfacename>ConnectionProvider</interfacename> interface
which is a service contract. Applications may also supply their own
<interfacename>ConnectionProvider</interfacename> implementation
to define a custom approach for supplying connections to Hibernate (from a different connection pool
implementation, for example).
</para>
<!-- todo : discuss servies -->
<section>
<title>Configuration</title>
<para>
You can configure database connections using a properties file, an XML deployment descriptor or
programmatically.
</para>
<example>
<title><filename>hibernate.properties</filename> for a c3p0 connection pool</title>
<programlisting><xi:include href="extras/hibernate.properties" parse="text" /></programlisting>
</example>
<example>
<title><filename>hibernate.cfg.xml</filename> for a connection to the bundled HSQL database</title>
<programlisting language="XML" role="XML"><xi:include href="extras/hibernate.cfg.xml" parse="text" /></programlisting>
</example>
<section>
<title>Programatic configuration</title>
<para>
An instance of object <classname>org.hibernate.cfg.Configuration</classname> represents an entire set of
mappings of an application's Java types to an SQL database. The
<classname>org.hibernate.cfg.Configuration</classname> builds an immutable
<classname>org.hibernate.SessionFactory</classname>, and compiles the mappings from various XML mapping
files. You can specify the mapping files directly, or Hibernate can find them for you.
</para>
<example>
<title>Specifying the mapping files directly</title>
<para>
You can obtain a <classname>org.hibernate.cfg.Configuration</classname> instance by instantiating it
directly and specifying XML mapping documents. If the mapping files are in the classpath, use method
<methodname>addResource()</methodname>.
</para>
<programlisting language="Java" role="JAVA"><xi:include href="extras/specify_mapping_files_directly.java" parse="text" /></programlisting>
</example>
<example>
<title>Letting Hibernate find the mapping files for you</title>
<para>
The <methodname>addClass()</methodname> method directs Hibernate to search the CLASSPATH for the mapping
files, eliminating hard-coded file names. In the following example, it searches for
<filename>org/hibernate/auction/Item.hbm.xml</filename> and
<filename>org/hibernate/auction/Bid.hbm.xml</filename>.
</para>
<programlisting language="Java" role="JAVA"><xi:include href="extras/letting_hibernate_find_mapping_files.java" parse="text" /></programlisting>
</example>
<example>
<title>Specifying configuration properties</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/specifying_configuration_properties_programmatically.java" parse="text" /></programlisting>
</example>
<itemizedlist>
<title>Other ways to configure Hibernate programmatically</title>
<listitem>
<para>
Pass an instance of <classname>java.util.Properties</classname> to
<classname>Configuration.setProperties()</classname>.
</para>
</listitem>
<listitem>
<para>
Set System properties using <command>java
-D<replaceable>property</replaceable>=<replaceable>value</replaceable></command>
</para>
</listitem>
</itemizedlist>
</section>
</section>
<section>
<title>Obtaining a JDBC connection</title>
<para>
After you configure the <xref linkend="hibernate-jdbc-properties" />, you can use method
<methodname>openSession</methodname> of class <classname>org.hibernate.SessionFactory</classname> to open
sessions. Sessions will obtain JDBC connections as needed based on the provided configuration.
</para>
<example>
<title>Specifying configuration properties</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/opening_a_session.java" parse="text" /></programlisting>
</example>
<itemizedlist id="hibernate-jdbc-properties">
<title>Most important Hibernate JDBC properties</title>
<listitem><para>hibernate.connection.driver_class</para></listitem>
<listitem><para>hibernate.connection.url</para></listitem>
<listitem><para>hibernate.connection.username</para></listitem>
<listitem><para>hibernate.connection.password</para></listitem>
<listitem><para>hibernate.connection.pool_size</para></listitem>
</itemizedlist>
<para>
All available Hibernate settings are defined as constants and discussed on the
<interfacename>org.hibernate.cfg.AvailableSettings</interfacename> interface. See its source code or
JavaDoc for details.
</para>
</section>
</section>
<section>
<title>Connection pooling</title>
<para>
Hibernate's internal connection pooling algorithm is rudimentary, and is provided for development and testing
purposes. Use a third-party pool for best performance and stability. To use a third-party pool, replace the
<property>hibernate.connection.pool_size property</property> with settings specific to your connection pool of
choice. This disables Hibernate's internal connection pool.
</para>
<section>
<title>c3p0 connection pool</title>
<para>
C3P0 is an open source JDBC connection pool distributed along with Hibernate in the <filename>lib/</filename>
directory. Hibernate uses its <classname>org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</classname> for
connection pooling if you set the <property>hibernate.c3p0.*</property> properties. properties.
</para>
<itemizedlist>
<title>Important configuration properties for the c3p0 connection pool</title>
<listitem><para>hibernate.c3p0.min_size</para></listitem>
<listitem><para>hibernate.c3p0.max_size</para></listitem>
<listitem><para>hibernate.c3p0.timeout</para></listitem>
<listitem><para>hibernate.c3p0.max_statements</para></listitem>
</itemizedlist>
</section>
<section>
<title>Proxool connection pool</title>
<para>
Proxool is another open source JDBC connection pool distributed along with Hibernate in the
<filename>lib/</filename> directory. Hibernate uses its
<classname>org.hibernate.service.jdbc.connections.internal.ProxoolConnectionProvider</classname> for connection pooling if you set the
<property>hibernate.proxool.*</property> properties. Unlike c3p0, proxool requires some additional configuration
parameters, as described by the Proxool documentation available at <link xlink:href="http://proxool.sourceforge.net/configure.html" />.
</para>
<table>
<title>Important configuration properties for the Proxool connection pool</title>
<tgroup cols="2">
<colspec colwidth="120px" />
<colspec colwidth="320px" />
<thead>
<row>
<entry>Property</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>hibernate.proxool.xml</entry>
<entry>Configure Proxool provider using an XML file (.xml is appended automatically)</entry>
</row>
<row>
<entry>hibernate.proxool.properties</entry>
<entry>Configure the Proxool provider using a properties file (.properties is appended
automatically)</entry>
</row>
<row>
<entry>hibernate.proxool.existing_pool</entry>
<entry>Whether to configure the Proxool provider from an existing pool</entry>
</row>
<row>
<entry>hibernate.proxool.pool_alias</entry>
<entry>Proxool pool alias to use. Required.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section>
<title>Obtaining connections from an application server, using JNDI</title>
<para>
To use Hibernate inside an application server, configure Hibernate to obtain connections from an application
server <classname>javax.sql.Datasource</classname> registered in JNDI, by setting at least one of the following
properties:
</para>
<itemizedlist>
<title>Important Hibernate properties for JNDI datasources</title>
<listitem><para>hibernate.connection.datasource (required)</para></listitem>
<listitem><para>hibernate.jndi.url</para></listitem>
<listitem><para>hibernate.jndi.class</para></listitem>
<listitem><para>hibernate.connection.username</para></listitem>
<listitem><para>hibernate.connection.password</para></listitem>
</itemizedlist>
<para>
JDBC connections obtained from a JNDI datasource automatically participate in the container-managed transactions
of the application server.
</para>
</section>
<section>
<title>Other connection-specific configuration</title>
<para>
You can pass arbitrary connection properties by prepending <literal>hibernate.connection</literal> to the
connection property name. For example, specify a charSet connection property as
<property>hibernate.connection.charSet</property>.
</para>
<para>
You can define your own plugin strategy for obtaining JDBC connections by implementing the interface
<interfacename>ConnectionProvider</interfacename> and specifying your custom
implementation with the <property>hibernate.connection.provider_class</property> property.
</para>
</section>
<section>
<title>Optional configuration properties</title>
<para>
In addition to the properties mentioned in the previous sections, Hibernate includes many other optional
properties. See <xref linkend="appendix-Configuration_Properties" /> for a more complete list.
</para>
</section>
</section>
<section id="configuring-dialects">
<title>Dialects</title>
<para>
Although SQL is relatively standardized, each database vendor uses a subset of supported syntax. This is referred
to as a <firstterm>dialect</firstterm>. Hibernate handles variations across these dialects through its
<classname>org.hibernate.dialect.Dialect</classname> class and the various subclasses for each vendor dialect.
</para>
<table>
<title>Supported database dialects</title>
<tgroup cols="2">
<colspec colwidth="120px" />
<colspec colwidth="320px" />
<thead>
<row>
<entry>Database</entry>
<entry>Dialect</entry>
</row>
</thead>
<tbody>
<row>
<entry>CUBRID 8.3 and later</entry>
<entry>
<literal>org.hibernate.dialect.CUBRIDDialect</literal>
</entry>
</row>
<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>Firebird</entry>
<entry>
<literal>org.hibernate.dialect.FirebirdDialect</literal>
</entry>
</row>
<row>
<entry>FrontBase</entry>
<entry>
<literal>org.hibernate.dialect.FrontbaseDialect</literal>
</entry>
</row>
<row>
<entry>H2</entry>
<entry>
<literal>org.hibernate.dialect.H2Dialect</literal>
</entry>
</row>
<row>
<entry>HyperSQL (HSQL)</entry>
<entry>
<literal>org.hibernate.dialect.HSQLDialect</literal>
</entry>
</row>
<row>
<entry>Informix</entry>
<entry>
<literal>org.hibernate.dialect.InformixDialect</literal>
</entry>
</row>
<row>
<entry>Ingres</entry>
<entry>
<literal>org.hibernate.dialect.IngresDialect</literal>
</entry>
</row>
<row>
<entry>Ingres 9</entry>
<entry>
<literal>org.hibernate.dialect.Ingres9Dialect</literal>
</entry>
</row>
<row>
<entry>Ingres 10</entry>
<entry>
<literal>org.hibernate.dialect.Ingres10Dialect</literal>
</entry>
</row>
<row>
<entry>Interbase</entry>
<entry>
<literal>org.hibernate.dialect.InterbaseDialect</literal>
</entry>
</row>
<row>
<entry>InterSystems Cache 2007.1</entry>
<entry>
<literal>org.hibernate.dialect.Cache71Dialect</literal>
</entry>
</row>
<row>
<entry>JDataStore</entry>
<entry>
<literal>org.hibernate.dialect.JDataStoreDialect</literal>
</entry>
</row>
<row>
<entry>Mckoi SQL</entry>
<entry>
<literal>org.hibernate.dialect.MckoiDialect</literal>
</entry>
</row>
<row>
<entry>Microsoft SQL Server 2000</entry>
<entry>
<literal>org.hibernate.dialect.SQLServerDialect</literal>
</entry>
</row>
<row>
<entry>Microsoft SQL Server 2005</entry>
<entry>
<literal>org.hibernate.dialect.SQLServer2005Dialect</literal>
</entry>
</row>
<row>
<entry>Microsoft SQL Server 2008</entry>
<entry>
<literal>org.hibernate.dialect.SQLServer2008Dialect</literal>
</entry>
</row>
<row>
<entry>Microsoft SQL Server 2012</entry>
<entry>
<literal>org.hibernate.dialect.SQLServer2012Dialect</literal>
</entry>
</row>
<row>
<entry>Mimer SQL</entry>
<entry>
<literal>org.hibernate.dialect.MimerSQLDialect</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>MySQL5</entry>
<entry>
<literal>org.hibernate.dialect.MySQL5Dialect</literal>
</entry>
</row>
<row>
<entry>MySQL5 with InnoDB</entry>
<entry>
<literal>org.hibernate.dialect.MySQL5InnoDBDialect</literal>
</entry>
</row>
<row>
<entry>Oracle 8i</entry>
<entry>
<literal>org.hibernate.dialect.Oracle8iDialect</literal>
</entry>
</row>
<row>
<entry>Oracle 9i</entry>
<entry>
<literal>org.hibernate.dialect.Oracle9iDialect</literal>
</entry>
</row>
<row>
<entry>Oracle 10g and later</entry>
<entry>
<literal>org.hibernate.dialect.Oracle10gDialect</literal>
</entry>
</row>
<row>
<entry>Oracle TimesTen</entry>
<entry>
<literal>org.hibernate.dialect.TimesTenDialect</literal>
</entry>
</row>
<row>
<entry>Pointbase</entry>
<entry>
<literal>org.hibernate.dialect.PointbaseDialect</literal>
</entry>
</row>
<row>
<entry>PostgreSQL 8.1</entry>
<entry>
<literal>org.hibernate.dialect.PostgreSQL81Dialect</literal>
</entry>
</row>
<row>
<entry>PostgreSQL 8.2</entry>
<entry>
<literal>org.hibernate.dialect.PostgreSQL82Dialect</literal>
</entry>
</row>
<row>
<entry>PostgreSQL 9 and later</entry>
<entry>
<literal>org.hibernate.dialect.PostgreSQL9Dialect</literal>
</entry>
</row>
<row>
<entry>Progress</entry>
<entry>
<literal>org.hibernate.dialect.ProgressDialect</literal>
</entry>
</row>
<row>
<entry>SAP DB</entry>
<entry>
<literal>org.hibernate.dialect.SAPDBDialect</literal>
</entry>
</row>
<row>
<entry>SAP HANA (column store)</entry>
<entry>
<literal>org.hibernate.dialect.HANAColumnStoreDialect</literal>
</entry>
</row>
<row>
<entry>SAP HANA (row store)</entry>
<entry>
<literal>org.hibernate.dialect.HANARowStoreDialect</literal>
</entry>
</row>
<row>
<entry>Sybase</entry>
<entry>
<literal>org.hibernate.dialect.SybaseDialect</literal>
</entry>
</row>
<row>
<entry>Sybase 11</entry>
<entry>
<literal>org.hibernate.dialect.Sybase11Dialect</literal>
</entry>
</row>
<row>
<entry>Sybase ASE 15.5</entry>
<entry>
<literal>org.hibernate.dialect.SybaseASE15Dialect</literal>
</entry>
</row>
<row>
<entry>Sybase ASE 15.7</entry>
<entry>
<literal>org.hibernate.dialect.SybaseASE157Dialect</literal>
</entry>
</row>
<row>
<entry>Sybase Anywhere</entry>
<entry>
<literal>org.hibernate.dialect.SybaseAnywhereDialect</literal>
</entry>
</row>
<row>
<entry>Teradata</entry>
<entry>
<literal>org.hibernate.dialect.TeradataDialect</literal>
</entry>
</row>
<row>
<entry>Unisys OS 2200 RDMS</entry>
<entry>
<literal>org.hibernate.dialect.RDMSOS2200Dialect</literal>
</entry>
</row>
</tbody>
</tgroup>
</table>
<section>
<title>Specifying the Dialect to use</title>
<para>
The developer may manually specify the Dialect to use by setting the
<property>hibernate.dialect</property> configuration property to the name of a specific
<classname>org.hibernate.dialect.Dialect</classname> class to use.
</para>
</section>
<section>
<title>Dialect resolution</title>
<para>
Assuming a <interfacename>ConnectionProvider</interfacename> has been
set up, Hibernate will attempt to automatically determine the Dialect to use based on the
<interfacename>java.sql.DatabaseMetaData</interfacename> reported by a
<interfacename>java.sql.Connection</interfacename> obtained from that
<interfacename>ConnectionProvider</interfacename>.
</para>
<para>
This functionality is provided by a series of
<interfacename>org.hibernate.engine.jdbc.dialect.spi.DialectResolver</interfacename> instances registered
with Hibernate internally. Hibernate comes with a standard set of recognitions. If your application
requires extra Dialect resolution capabilities, it would simply register a custom implementation
of <interfacename>org.hibernate.engine.jdbc.dialect.spi.DialectResolver</interfacename> as follows:
</para>
<!-- document an example using the service registry -->
<para>
Registered <interfacename>org.hibernate.engine.jdbc.dialect.spi.DialectResolver</interfacename> are
<emphasis>prepended</emphasis> to an internal list of resolvers, so they take precedence
before any already registered resolvers including the standard one.
</para>
</section>
</section>
<section>
<title>Automatic schema generation with SchemaExport</title>
<para>
SchemaExport is a Hibernate utility which generates DDL from your mapping files. The generated schema includes
referential integrity constraints, primary and foreign keys, for entity and collection tables. It also creates
tables and sequences for mapped identifier generators.
</para>
<note>
<para>
You must specify a SQL Dialect via the <property>hibernate.dialect</property> property when using this tool,
because DDL is highly vendor-specific. See <xref linkend="configuring-dialects" /> for information.
</para>
</note>
<para>
Before Hibernate can generate your schema, you must customize your mapping files.
</para>
<section>
<title>Customizing the mapping files</title>
<para>
Hibernate provides several elements and attributes to customize your mapping files. They are listed in <xref
linkend="tab-customizing-schema" />, and a logical order of customization is presented in <xref
linkend="proc-customizing-schema" />.
</para>
<table id="tab-customizing-schema">
<title>Elements and attributes provided for customizing mapping files</title>
<tgroup cols="3">
<colspec colwidth="80px" />
<colspec colwidth="80px" />
<colspec colwidth="280px" />
<thead>
<row>
<entry>Name</entry>
<entry>Type of value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>length</entry>
<entry>number</entry>
<entry>Column length</entry>
</row>
<row>
<entry>precision</entry>
<entry>number</entry>
<entry>Decimal precision of column</entry>
</row>
<row>
<entry>scale</entry>
<entry>number</entry>
<entry>Decimal scale of column</entry>
</row>
<row>
<entry>not-null</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Whether a column is allowed to hold null values</entry>
</row>
<row>
<entry>unique</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Whether values in the column must be unique</entry>
</row>
<row>
<entry>index</entry>
<entry>string</entry>
<entry>The name of a multi-column index</entry>
</row>
<row>
<entry>unique-key</entry>
<entry>string</entry>
<entry>The name of a multi-column unique constraint</entry>
</row>
<row>
<entry>foreign-key</entry>
<entry>string</entry>
<entry>The name of the foreign key constraint generated for an association. This applies to
&lt;one-to-one&gt;, &lt;many-to-one&gt;, &lt;key&gt;, and &lt;many-to-many&gt; mapping
elements. <literal>inverse="true"</literal> sides are skipped by SchemaExport.</entry>
</row>
<row>
<entry>sql-type</entry>
<entry>string</entry>
<entry>Overrides the default column type. This applies to the &lt;column&gt; element only.</entry>
</row>
<row>
<entry>default</entry>
<entry>string</entry>
<entry>Default value for the column</entry>
</row>
<row>
<entry>check</entry>
<entry>string</entry>
<entry>An SQL check constraint on either a column or atable</entry>
</row>
</tbody>
</tgroup>
</table>
<procedure id="proc-customizing-schema">
<title>Customizing the schema</title>
<step>
<title>Set the length, precision, and scale of mapping elements.</title>
<para>
Many Hibernate mapping elements define optional attributes named <option>length</option>,
<option>precision</option>, and <option>scale</option>.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/length-precision-scale.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Set the <option>not-null</option>, <option>UNIQUE</option>, <option>unique-key</option> attributes.</title>
<para>
The <option>not-null</option> and <option>UNIQUE</option> attributes generate constraints on table columns.
</para>
<para>
The unique-key attribute groups columns in a single, unique key constraint. The attribute overrides
the name of any generated unique key constraint.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/notnull-unique.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Set the <option>index</option> and <option>foreign-key</option> attributes.</title>
<para>
The <option>index</option> attribute specifies the name of an index for Hibernate to create using the mapped
column or columns. You can group multiple columns into the same index by assigning them the same index name.
</para>
<para>
A foreign-key attribute overrides the name of any generated foreign key constraint.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/foreign-key.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Set child <option>&lt;column&gt;</option> elements.</title>
<para>
Many mapping elements accept one or more child &lt;column&gt; elements. This is particularly useful for
mapping types involving multiple columns.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/child-column-elements.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Set the <option>default</option> attribute.</title>
<para>
The <option>default</option> attribute represents a default value for a column. Assign the same value to the
mapped property before saving a new instance of the mapped class.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/default-attribute.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Set the <option>sql-type</option> attribure.</title>
<para>
Use the <option>sql-type</option> attribute to override the default mapping of a Hibernate type to SQL
datatype.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/sql-type.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Set the <option>check</option> attribute.</title>
<para>
use the <option>check</option> attribute to specify a <wordasword>check</wordasword> constraint.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/check.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
<step>
<title>Add &lt;comment&gt; elements to your schema.</title>
<para>
Use the &lt;comment&gt; element to specify comments for the generated schema.
</para>
<programlisting language="XML" role="XML"><xi:include href="extras/comments.xml" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</step>
</procedure>
</section>
<section>
<title>Running the SchemaExport tool</title>
<para>
The SchemaExport tool writes a DDL script to standard output, executes the DDL statements, or both.
</para>
<example>
<title>SchemaExport syntax</title>
<screen>
java -cp hibernate_classpaths org.hibernate.tool.hbm2ddl.SchemaExport <replaceable>options</replaceable> <replaceable>mapping_files</replaceable>
</screen>
</example>
<table>
<title>SchemaExport Options</title>
<tgroup cols="2">
<colspec colwidth="120px" />
<colspec colwidth="320px" />
<thead>
<row>
<entry>Option</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>--quiet</entry>
<entry>do not output the script to standard output</entry>
</row>
<row>
<entry>--drop</entry>
<entry>only drop the tables</entry>
</row>
<row>
<entry>--create</entry>
<entry>only create the tables</entry>
</row>
<row>
<entry>--text</entry>
<entry>do not export to the database</entry>
</row>
<row>
<entry><para>--output=<replaceable>my_schema.ddl</replaceable></para></entry>
<entry>output the ddl script to a file</entry>
</row>
<row>
<entry><para>--naming=<replaceable>eg.MyNamingStrategy</replaceable></para></entry>
<entry>select a NamingStrategy</entry>
</row>
<row>
<entry><para>--config=<replaceable>hibernate.cfg.xml</replaceable></para></entry>
<entry>read Hibernate configuration from an XML file</entry>
</row>
<row>
<entry><para>--properties=<replaceable>hibernate.properties</replaceable></para></entry>
<entry>read database properties from a file</entry>
</row>
<row>
<entry>--format</entry>
<entry>format the generated SQL nicely in the script</entry>
</row>
<row>
<entry><para>--delimiter=<replaceable>;</replaceable></para></entry>
<entry>set an end-of-line delimiter for the script</entry>
</row>
</tbody>
</tgroup>
</table>
<example>
<title>Embedding SchemaExport into your application</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/embedding_SchemaExport.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</example>
</section>
</section>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook">
<title>JMX</title>
<para> </para>
</chapter>

View File

@ -1,332 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" >
<title>Locking</title>
<para>
Locking refers to actions taken to prevent data in a relational database from changing between the time it is read
and the time that it is used.
</para>
<para>
Your locking strategy can be either <firstterm>optimistic</firstterm> or <firstterm>pessimistic</firstterm>.
</para>
<variablelist>
<title>Locking strategies</title>
<varlistentry>
<term>Optimistic</term>
<listitem>
<para>
Optimistic locking assumes that multiple transactions can complete without affecting each other, and that
therefore transactions can proceed without locking the data resources that they affect. Before committing,
each transaction verifies that no other transaction has modified its data. If the check reveals conflicting
modifications, the committing transaction rolls back<footnote><para><link xl:href="http://en.wikipedia.org/wiki/Optimistic_locking" /></para></footnote>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Pessimistic</term>
<listitem>
<para>
Pessimistic locking assumes that concurrent transactions will conflict with each other, and requires resources
to be locked after they are read and only unlocked after the application has finished using the data.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Hibernate provides mechanisms for implementing both types of locking in your applications.
</para>
<section>
<title>Optimistic</title>
<para>
When your application uses long transactions or conversations that span several database transactions, you can
store versioning data, so that if the same entity is updated by two conversations, the last to commit changes is
informed of the conflict, and does not override the other conversation's work. This approach guarantees some
isolation, but scales well and works particularly well in <firstterm>Read-Often Write-Sometimes</firstterm>
situations.
</para>
<para>
Hibernate provides two different mechanisms for storing versioning information, a dedicated version number or a
timestamp.
</para>
<variablelist>
<varlistentry>
<term>Version number</term>
<listitem>
<para>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Timestamp</term>
<listitem>
<para>
</para>
</listitem>
</varlistentry>
</variablelist>
<note>
<para>
A version or timestamp property can never be null for a detached instance. Hibernate detects any instance with a
null version or timestamp as transient, regardless of other unsaved-value strategies that you specify. Declaring
a nullable version or timestamp property is an easy way to avoid problems with transitive reattachment in
Hibernate, especially useful if you use assigned identifiers or composite keys.
</para>
</note>
<section>
<title>Dedicated version number</title>
<para>
The version number mechanism for optimistic locking is provided through a <literal>@Version</literal>
annotation.
</para>
<example>
<title>The @Version annotation</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/version_annotation.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
<para>
Here, the version property is mapped to the <literal>OPTLOCK</literal> column, and the entity manager uses it
to detect conflicting updates, and prevent the loss of updates that would be overwritten by a
<firstterm>last-commit-wins</firstterm> strategy.
</para>
</example>
<para>
The version column can be any kind of type, as long as you define and implement the appropriate
<classname>UserVersionType</classname>.
</para>
<para>
Your application is forbidden from altering the version number set by Hibernate. To artificially increase the
version number, see the documentation for properties
<property>LockModeType.OPTIMISTIC_FORCE_INCREMENT</property> or
<property>LockModeType.PESSIMISTIC_FORCE_INCREMENTcheck</property> in the Hibernate Entity Manager reference
documentation.
</para>
<note>
<title>Database-generated version numbers</title>
<para>
If the version number is generated by the database, such as a trigger, use the annotation
<literal>@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)</literal>.
</para>
</note>
<example>
<title>Declaring a version property in <filename>hbm.xml</filename></title>
<programlisting language="XML" role="XML"><xi:include href="extras/version_property.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
<informaltable>
<tgroup cols="2">
<tbody>
<row>
<entry>column</entry>
<entry><para>The name of the column holding the version number. Optional, defaults to the property
name. </para></entry>
</row>
<row>
<entry>name</entry>
<entry><para>The name of a property of the persistent class.</para></entry>
</row>
<row>
<entry>type</entry>
<entry><para>The type of the version number. Optional, defaults to
<literal>integer</literal>.</para></entry>
</row>
<row>
<entry>access</entry>
<entry><para>Hibernate's strategy for accessing the property value. Optional, defaults to
<literal>property</literal>.</para></entry>
</row>
<row>
<entry>unsaved-value</entry>
<entry><para>Indicates that an instance is newly instantiated and thus unsaved. This distinguishes it
from detached instances that were saved or loaded in a previous session. The default value,
<literal>undefined</literal>, indicates that the identifier property value should be
used. Optional.</para></entry>
</row>
<row>
<entry>generated</entry>
<entry><para>Indicates that the version property value is generated by the database. Optional, defaults
to <literal>never</literal>.</para></entry>
</row>
<row>
<entry>insert</entry>
<entry><para>Whether or not to include the <code>version</code> column in SQL <code>insert</code>
statements. Defaults to <literal>true</literal>, but you can set it to <literal>false</literal> if the
database column is defined with a default value of <literal>0</literal>.</para></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</example>
</section>
<section>
<title>Timestamp</title>
<para>
Timestamps are a less reliable way of optimistic locking than version numbers, but can be used by applications
for other purposes as well. Timestamping is automatically used if you the <code>@Version</code> annotation on a
<type>Date</type> or <type>Calendar</type>.
</para>
<example>
<title>Using timestamps for optimistic locking</title>
<programlisting language="Java" role="JAVA"><xi:include href="extras/timestamp_version.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
</example>
<para>
Hibernate can retrieve the timestamp value from the database or the JVM, by reading the value you specify for
the <code>@org.hibernate.annotations.Source</code> annotation. The value can be either
<literal>org.hibernate.annotations.SourceType.DB</literal> or
<literal>org.hibernate.annotations.SourceType.VM</literal>. The default behavior is to use the database, and is
also used if you don't specify the annotation at all.
</para>
<para>
The timestamp can also be generated by the database instead of Hibernate, if you use the
<code>@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)</code> annotation.
</para>
<example>
<title>The timestamp element in <filename>hbm.xml</filename></title>
<programlisting language="XML" role="XML"><xi:include href="extras/timestamp_version.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" /></programlisting>
<informaltable>
<tgroup cols="2">
<tbody>
<row>
<entry>column</entry>
<entry><para>The name of the column which holds the timestamp. Optional, defaults to the property
namel</para></entry>
</row>
<row>
<entry>name</entry>
<entry><para>The name of a JavaBeans style property of Java type Date or Timestamp of the persistent
class.</para></entry>
</row>
<row>
<entry>access</entry>
<entry><para>The strategy Hibernate uses to access the property value. Optional, defaults to
<literal>property</literal>.</para></entry>
</row>
<row>
<entry>unsaved-value</entry> <entry><para>A version property which indicates than instance is newly
instantiated, and unsaved. This distinguishes it from detached instances that were saved or loaded in a
previous session. The default value of <literal>undefined</literal> indicates that Hibernate uses the
identifier property value.</para></entry>
</row>
<row>
<entry>source</entry>
<entry><para>Whether Hibernate retrieves the timestamp from the database or the current
JVM. Database-based timestamps incur an overhead because Hibernate needs to query the database each time
to determine the incremental next value. However, database-derived timestamps are safer to use in a
clustered environment. Not all database dialects are known to support the retrieval of the database's
current timestamp. Others may also be unsafe for locking, because of lack of precision.</para></entry>
</row>
<row>
<entry>generated</entry>
<entry><para>Whether the timestamp property value is generated by the database. Optional, defaults to
<literal>never</literal>.</para></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</example>
</section>
</section>
<section>
<title>Pessimistic</title>
<para>
Typically, you only need to specify an isolation level for the JDBC connections and let the database handle
locking issues. If you do need to obtain exclusive pessimistic locks or re-obtain locks at the start of a new
transaction, Hibernate gives you the tools you need.
</para>
<note>
<para>
Hibernate always uses the locking mechanism of the database, and never lock objects in memory.
</para>
</note>
<section>
<title>The <classname>LockMode</classname> class</title>
<para>
The <classname>LockMode</classname> class defines the different lock levels that Hibernate can acquire.
</para>
<informaltable>
<tgroup cols="2">
<tbody>
<row>
<entry>LockMode.WRITE</entry>
<entry><para>acquired automatically when Hibernate updates or inserts a row.</para></entry>
</row>
<row>
<entry>LockMode.UPGRADE</entry>
<entry><para>acquired upon explicit user request using <code>SELECT ... FOR UPDATE</code> on databases
which support that syntax.</para></entry>
</row>
<row>
<entry>LockMode.UPGRADE_NOWAIT</entry>
<entry><para>acquired upon explicit user request using a <code>SELECT ... FOR UPDATE NOWAIT</code> in
Oracle.</para></entry>
</row>
<row>
<entry>LockMode.UPGRADE_SKIPLOCKED</entry>
<entry><para>acquired upon explicit user request using a <code>SELECT ... FOR UPDATE SKIP LOCKED</code> in
Oracle, or <code>SELECT ... with (rowlock,updlock,readpast) in SQL Server</code>.</para></entry>
</row>
<row>
<entry>LockMode.READ</entry>
<entry><para>acquired automatically when Hibernate reads data under <phrase>Repeatable Read</phrase> or
<phrase>Serializable</phrase> isolation level. It can be re-acquired by explicit user
request.</para></entry>
</row>
<row>
<entry>LockMode.NONE</entry>
<entry><para>The absence of a lock. All objects switch to this lock mode at the end of a
Transaction. Objects associated with the session via a call to <methodname>update()</methodname> or
<methodname>saveOrUpdate()</methodname> also start out in this lock mode. </para></entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The explicit user request mentioned above occurs as a consequence of any of the following actions:
</para>
<itemizedlist>
<listitem>
<para>
A call to <methodname>Session.load()</methodname>, specifying a LockMode.
</para>
</listitem>
<listitem>
<para>
A call to <methodname>Session.lock()</methodname>.
</para>
</listitem>
<listitem>
<para>
A call to <methodname>Query.setLockMode()</methodname>.
</para>
</listitem>
</itemizedlist>
<para>
If you call <methodname>Session.load()</methodname> with option <option>UPGRADE</option>,
<option>UPGRADE_NOWAIT</option> or <option>UPGRADE_SKIPLOCKED</option>, and the requested object is not already
loaded by the session, the object is loaded using <code>SELECT ... FOR UPDATE</code>. If you call
<methodname>load()</methodname> for an object that is already loaded with a less restrictive lock than the one
you request, Hibernate calls <methodname>lock()</methodname> for that object.
</para>
<para>
<methodname>Session.lock()</methodname> performs a version number check if the specified lock mode is
<literal>READ</literal>, <literal>UPGRADE</literal>, <literal>UPGRADE_NOWAIT</literal> or
<literal>UPGRADE_SKIPLOCKED</literal>. In the case of <literal>UPGRADE</literal>,
<literal>UPGRADE_NOWAIT</literal> or <literal>UPGRADE_SKIPLOCKED</literal>, <code>SELECT ... FOR UPDATE</code>
syntax is used.
</para>
<para>
If the requested lock mode is not supported by the database, Hibernate uses an appropriate alternate mode
instead of throwing an exception. This ensures that applications are portable.
</para>
</section>
</section>
</chapter>

View File

@ -1,17 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook" >
<title>Mapping associations</title>
<para>
The most basic form of mapping in Hibernate is mapping a persistent entity class to a database table.
You can expand on this concept by mapping associated classes together. <xref linkend="mapping-person" />
shows a <classname>Person</classname> class with a
</para>
</chapter>

View File

@ -1,15 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook" >
<title>Mapping entities</title>
<section>
<title>Hierarchies</title>
<para></para>
</section>
</chapter>

View File

@ -1,549 +0,0 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<appendix xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink">
<info>
<title>Legacy Hibernate Criteria Queries</title>
</info>
<note>
<para>
This appendix covers the legacy Hibernate <interfacename>org.hibernate.Criteria</interfacename> API, which
should be considered deprecated. New development should focus on the JPA
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename> API. Eventually,
Hibernate-specific criteria features will be ported as extensions to the JPA
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. For details on the JPA APIs, see
<xref linkend="query-criteria"/>.
</para>
<para>
This information is copied as-is from the older Hibernate documentation.
</para>
</note>
<para>
Hibernate features an intuitive, extensible criteria query API.
</para>
<section xml:id="querycriteria-creating">
<title>Creating a <literal>Criteria</literal> instance</title>
<para>
The interface <literal>org.hibernate.Criteria</literal> represents a query against
a particular persistent class. The <literal>Session</literal> is a factory for
<literal>Criteria</literal> instances.
</para>
<programlisting role="JAVA"><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();]]></programlisting>
</section>
<section xml:id="querycriteria-narrowing">
<title>Narrowing the result set</title>
<para>
An individual query criterion is an instance of the interface
<literal>org.hibernate.criterion.Criterion</literal>. The class
<literal>org.hibernate.criterion.Restrictions</literal> defines
factory methods for obtaining certain built-in
<literal>Criterion</literal> types.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();]]></programlisting>
<para>
Restrictions can be grouped logically.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.or(
Restrictions.eq( "age", new Integer(0) ),
Restrictions.isNull("age")
) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
.add( Restrictions.disjunction()
.add( Restrictions.isNull("age") )
.add( Restrictions.eq("age", new Integer(0) ) )
.add( Restrictions.eq("age", new Integer(1) ) )
.add( Restrictions.eq("age", new Integer(2) ) )
) )
.list();]]></programlisting>
<para>
There are a range of built-in criterion types (<literal>Restrictions</literal>
subclasses). One of the most useful allows you to specify SQL directly.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
.list();]]></programlisting>
<para>
The <literal>{alias}</literal> placeholder will be replaced by the row alias
of the queried entity.
</para>
<para>
You can also obtain a criterion from a
<literal>Property</literal> instance. You can create a <literal>Property</literal>
by calling <literal>Property.forName()</literal>:
</para>
<programlisting role="JAVA"><![CDATA[
Property age = Property.forName("age");
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.disjunction()
.add( age.isNull() )
.add( age.eq( new Integer(0) ) )
.add( age.eq( new Integer(1) ) )
.add( age.eq( new Integer(2) ) )
) )
.add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
.list();]]></programlisting>
</section>
<section xml:id="querycriteria-ordering">
<title>Ordering the results</title>
<para>
You can order the results using <literal>org.hibernate.criterion.Order</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name").nulls(NullPrecedence.LAST) )
.addOrder( Order.desc("age") )
.setMaxResults(50)
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Property.forName("name").like("F%") )
.addOrder( Property.forName("name").asc() )
.addOrder( Property.forName("age").desc() )
.setMaxResults(50)
.list();]]></programlisting>
</section>
<section xml:id="querycriteria-associations">
<title>Associations</title>
<para>
By navigating
associations using <literal>createCriteria()</literal> you can specify constraints upon related entities:
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "F%") )
.createCriteria("kittens")
.add( Restrictions.like("name", "F%") )
.list();]]></programlisting>
<para>
The second <literal>createCriteria()</literal> returns a new
instance of <literal>Criteria</literal> that refers to the elements of
the <literal>kittens</literal> collection.
</para>
<para>
There is also an alternate form that is useful in certain circumstances:
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.createAlias("kittens", "kt")
.createAlias("mate", "mt")
.add( Restrictions.eqProperty("kt.name", "mt.name") )
.list();]]></programlisting>
<para>
(<literal>createAlias()</literal> does not create a new instance of
<literal>Criteria</literal>.)
</para>
<para>
The kittens collections held by the <literal>Cat</literal> instances
returned by the previous two queries are <emphasis>not</emphasis> pre-filtered
by the criteria. If you want to retrieve just the kittens that match the
criteria, you must use a <literal>ResultTransformer</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.createCriteria("kittens", "kt")
.add( Restrictions.eq("name", "F%") )
.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)
.list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
Map map = (Map) iter.next();
Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
Cat kitten = (Cat) map.get("kt");
}]]></programlisting>
<para>
Additionally you may manipulate the result set using a left outer join:
</para>
<programlisting><![CDATA[
List cats = session.createCriteria( Cat.class )
.createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") )
.addOrder(Order.asc("mt.age"))
.list();
]]></programlisting>
<para>
This will return all of the <literal>Cat</literal>s with a mate whose name starts with "good"
ordered by their mate's age, and all cats who do not have a mate.
This is useful when there is a need to order or limit in the database
prior to returning complex/large result sets, and removes many instances where
multiple queries would have to be performed and the results unioned
by java in memory.
</para>
<para>
Without this feature, first all of the cats without a mate would need to be loaded in one query.
</para>
<para>
A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age.
</para>
<para>
Thirdly, in memory; the lists would need to be joined manually.
</para>
</section>
<section xml:id="querycriteria-dynamicfetching">
<title>Dynamic association fetching</title>
<para>
You can specify association fetching semantics at runtime using
<literal>setFetchMode()</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.setFetchMode("mate", FetchMode.EAGER)
.setFetchMode("kittens", FetchMode.EAGER)
.list();]]></programlisting>
<para>
This query will fetch both <literal>mate</literal> and <literal>kittens</literal>
by outer join. See <xref linkend="performance-fetching"/> for more information.
</para>
</section>
<section id="querycriteria-components" revision="2">
<title>Components</title>
<para>
To add a restriction against a property of an embedded component, the component property
name should be prepended to the property name when creating the <literal>Restriction</literal>.
The criteria object should be created on the owning entity, and cannot be created on the component
itself. For example, suppose the <literal>Cat</literal> has a component property <literal>fullName</literal>
with sub-properties <literal>firstName</literal> and <literal>lastName</literal>:
</para>
<programlisting><![CDATA[
List cats = session.createCriteria(Cat.class)
.add(Restrictions.eq("fullName.lastName", "Cattington"))
.list();]]>
</programlisting>
<para>
Note: this does not apply when querying collections of components, for that see below
<xref linkend="querycriteria-collections"/>
</para>
</section>
<section id="querycriteria-collections" revision="1">
<title>Collections</title>
<para>
When using criteria against collections, there are two distinct cases. One is if
the collection contains entities (eg. <literal>&lt;one-to-many/&gt;</literal>
or <literal>&lt;many-to-many/&gt;</literal>) or components
(<literal>&lt;composite-element/&gt;</literal> ),
and the second is if the collection contains scalar values
(<literal>&lt;element/&gt;</literal>).
In the first case, the syntax is as given above in the section
<xref linkend="querycriteria-associations"/> where we restrict the <literal>kittens</literal>
collection. Essentially we create a <literal>Criteria</literal> object against the collection
property and restrict the entity or component properties using that instance.
</para>
<para>
For queryng a collection of basic values, we still create the <literal>Criteria</literal>
object against the collection, but to reference the value, we use the special property
&quot;elements&quot;. For an indexed collection, we can also reference the index property using
the special property &quot;indices&quot;.
</para>
<programlisting><![CDATA[
List cats = session.createCriteria(Cat.class)
.createCriteria("nickNames")
.add(Restrictions.eq("elements", "BadBoy"))
.list();]]>
</programlisting>
</section>
<section id="querycriteria-examples">
<title>Example queries</title>
<para>
The class <literal>org.hibernate.criterion.Example</literal> allows
you to construct a query criterion from a given instance.
</para>
<programlisting role="JAVA"><![CDATA[Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.list();]]></programlisting>
<para>
Version properties, identifiers and associations are ignored. By default,
null valued properties are excluded.
</para>
<para>
You can adjust how the <literal>Example</literal> is applied.
</para>
<programlisting role="JAVA"><![CDATA[Example example = Example.create(cat)
.excludeZeroes() //exclude zero valued properties
.excludeProperty("color") //exclude the property named "color"
.ignoreCase() //perform case insensitive string comparisons
.enableLike(); //use like for string comparisons
List results = session.createCriteria(Cat.class)
.add(example)
.list();]]></programlisting>
<para>
You can even use examples to place criteria upon associated objects.
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate() ) )
.list();]]></programlisting>
</section>
<section id="querycriteria-projection">
<title>Projections, aggregation and grouping</title>
<para>
The class <literal>org.hibernate.criterion.Projections</literal> is a
factory for <literal>Projection</literal> instances. You can apply a
projection to a query by calling <literal>setProjection()</literal>.
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.rowCount() )
.add( Restrictions.eq("color", Color.BLACK) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount() )
.add( Projections.avg("weight") )
.add( Projections.max("weight") )
.add( Projections.groupProperty("color") )
)
.list();]]></programlisting>
<para>
There is no explicit "group by" necessary in a criteria query. Certain
projection types are defined to be <emphasis>grouping projections</emphasis>,
which also appear in the SQL <literal>group by</literal> clause.
</para>
<para>
An alias can be assigned to a projection so that the projected value
can be referred to in restrictions or orderings. Here are two different ways to
do this:
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
.addOrder( Order.asc("colr") )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.groupProperty("color").as("colr") )
.addOrder( Order.asc("colr") )
.list();]]></programlisting>
<para>
The <literal>alias()</literal> and <literal>as()</literal> methods simply wrap a
projection instance in another, aliased, instance of <literal>Projection</literal>.
As a shortcut, you can assign an alias when you add the projection to a
projection list:
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount(), "catCountByColor" )
.add( Projections.avg("weight"), "avgWeight" )
.add( Projections.max("weight"), "maxWeight" )
.add( Projections.groupProperty("color"), "color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder( Order.desc("avgWeight") )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
.createAlias("kittens", "kit")
.setProjection( Projections.projectionList()
.add( Projections.property("cat.name"), "catName" )
.add( Projections.property("kit.name"), "kitName" )
)
.addOrder( Order.asc("catName") )
.addOrder( Order.asc("kitName") )
.list();]]></programlisting>
<para>
You can also use <literal>Property.forName()</literal> to express projections:
</para>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Property.forName("name") )
.add( Property.forName("color").eq(Color.BLACK) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[List results = session.createCriteria(Cat.class)
.setProjection( Projections.projectionList()
.add( Projections.rowCount().as("catCountByColor") )
.add( Property.forName("weight").avg().as("avgWeight") )
.add( Property.forName("weight").max().as("maxWeight") )
.add( Property.forName("color").group().as("color" )
)
.addOrder( Order.desc("catCountByColor") )
.addOrder( Order.desc("avgWeight") )
.list();]]></programlisting>
</section>
<section id="querycriteria-detachedqueries">
<title>Detached queries and subqueries</title>
<para>
The <literal>DetachedCriteria</literal> class allows you to create a query outside the scope
of a session and then execute it using an arbitrary <literal>Session</literal>.
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
.add( Property.forName("sex").eq('F') );
Session session = ....;
Transaction txn = session.beginTransaction();
List results = query.getExecutableCriteria(session).setMaxResults(100).list();
txn.commit();
session.close();]]></programlisting>
<para>
A <literal>DetachedCriteria</literal> can also be used to express a subquery. Criterion
instances involving subqueries can be obtained via <literal>Subqueries</literal> or
<literal>Property</literal>.
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight").avg() );
session.createCriteria(Cat.class)
.add( Property.forName("weight").gt(avgWeight) )
.list();]]></programlisting>
<programlisting role="JAVA"><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
.setProjection( Property.forName("weight") );
session.createCriteria(Cat.class)
.add( Subqueries.geAll("weight", weights) )
.list();]]></programlisting>
<para>
Correlated subqueries are also possible:
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
.setProjection( Property.forName("weight").avg() )
.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat.class, "cat")
.add( Property.forName("weight").gt(avgWeightForSex) )
.list();]]></programlisting>
<para>
Example of multi-column restriction based on a subquery:
</para>
<programlisting role="JAVA"><![CDATA[DetachedCriteria sizeQuery = DetachedCriteria.forClass( Man.class )
.setProjection( Projections.projectionList().add( Projections.property( "weight" ) )
.add( Projections.property( "height" ) ) )
.add( Restrictions.eq( "name", "John" ) );
session.createCriteria( Woman.class )
.add( Subqueries.propertiesEq( new String[] { "weight", "height" }, sizeQuery ) )
.list();]]></programlisting>
</section>
<!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
user objects - similar to setResultClass in JDO2. General use of ResultTransformer
could also be explained. -->
<section id="query-criteria-naturalid">
<title>Queries by natural identifier</title>
<para>
For most queries, including criteria queries, the query cache is not efficient
because query cache invalidation occurs too frequently. However, there is a special
kind of query where you can optimize the cache invalidation algorithm: lookups by a
constant natural key. In some applications, this kind of query occurs frequently.
The criteria API provides special provision for this use case.
</para>
<para>
First, map the natural key of your entity using
<literal>&lt;natural-id&gt;</literal> and enable use of the second-level cache.
</para>
<programlisting role="XML"><![CDATA[<class name="User">
<cache usage="read-write"/>
<id name="id">
<generator class="increment"/>
</id>
<natural-id>
<property name="name"/>
<property name="org"/>
</natural-id>
<property name="password"/>
</class>]]></programlisting>
<para>
This functionality is not intended for use with entities with
<emphasis>mutable</emphasis> natural keys.
</para>
<para>
Once you have enabled the Hibernate query cache,
the <literal>Restrictions.naturalId()</literal> allows you to make use of
the more efficient cache algorithm.
</para>
<programlisting role="JAVA"><![CDATA[session.createCriteria(User.class)
.add( Restrictions.naturalId()
.set("name", "gavin")
.set("org", "hb")
).setCacheable(true)
.uniqueResult();]]></programlisting>
</section>
</appendix>

View File

@ -1,441 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Configuration properties</title>
<section xml:id="config-strategy">
<title>Strategy configurations</title>
<para>
Many configuration settings define pluggable strategies that Hibernate uses for various purposes.
The configuration of many of these strategy type settings accept definition in various forms. The
documentation of such configuration settings refer here. The types of forms available in such cases
include:
</para>
<variablelist>
<varlistentry>
<term>short name (if defined)</term>
<listitem>
<para>
Certain built-in strategy implementations have a corresponding short name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>strategy instance</term>
<listitem>
<para>
An instance of the strategy implementation to use can be specified
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>strategy Class reference</term>
<listitem>
<para>
A <classname>java.lang.Class</classname> reference of the strategy implementation to use can
be specified
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>strategy Class name</term>
<listitem>
<para>
The class name (<classname>java.lang.String</classname>) of the strategy implementation to
use can be specified
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section>
<title>General Configuration</title>
<informaltable>
<tgroup cols="3">
<colspec colwidth="100px" />
<colspec colwidth="120px" />
<colspec colwidth="250px" />
<tbody>
<row>
<entry>hibernate.dialect</entry>
<entry>A fully-qualified classname</entry>
<entry>
<para>
The classname of a Hibernate <classname>org.hibernate.dialect.Dialect</classname> from which Hibernate
can generate SQL optimized for a particular relational database.
</para>
<para>
In most cases Hibernate can choose the correct <classname>org.hibernate.dialect.Dialect</classname>
implementation based on the JDBC metadata returned by the JDBC driver.
</para>
</entry>
</row>
<row>
<entry>hibernate.show_sql</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Write all SQL statements to the console. This is an alternative to setting the log category
<property>org.hibernate.SQL</property> to debug.</entry>
</row>
<row>
<entry>hibernate.format_sql</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Pretty-print the SQL in the log and console.</entry>
</row>
<row>
<entry>hibernate.default_schema</entry>
<entry>A schema name</entry>
<entry>Qualify unqualified table names with the given schema or tablespace in generated SQL.</entry>
</row>
<row>
<entry>hibernate.default_catalog</entry>
<entry>A catalog name</entry>
<entry>Qualifies unqualified table names with the given catalog in generated SQL.</entry>
</row>
<row>
<entry>hibernate.session_factory_name</entry>
<entry>A JNDI name</entry>
<entry>The <classname>org.hibernate.SessionFactory</classname> is automatically bound to this name in JNDI
after it is created.</entry>
</row>
<row>
<entry>hibernate.max_fetch_depth</entry>
<entry>A value between <literal>0</literal> and <literal>3</literal></entry>
<entry>Sets a maximum depth for the outer join fetch tree for single-ended associations. A single-ended
assocation is a one-to-one or many-to-one assocation. A value of <literal>0</literal> disables default outer
join fetching.</entry>
</row>
<row>
<entry>hibernate.default_batch_fetch_size</entry>
<entry><para><literal>4</literal>,<literal>8</literal>, or <literal>16</literal></para></entry>
<entry>Default size for Hibernate batch fetching of associations.</entry>
</row>
<row>
<entry>hibernate.default_entity_mode</entry>
<entry><para><literal>dynamic-map</literal> or <literal>pojo</literal></para></entry>
<entry>Default mode for entity representation for all sessions opened from this
<classname>SessionFactory</classname>, defaults to <literal>pojo</literal>.</entry>
</row>
<row>
<entry>hibernate.order_updates</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Forces Hibernate to order SQL updates by the primary key value of the items being updated. This
reduces the likelihood of transaction deadlocks in highly-concurrent systems.</entry>
</row>
<row>
<entry>hibernate.order_by.default_null_ordering</entry>
<entry><para><literal>none</literal>, <literal>first</literal> or <literal>last</literal></para></entry>
<entry>Defines precedence of null values in <literal>ORDER BY</literal> clause. Defaults to
<literal>none</literal> which varies between RDBMS implementation.</entry>
</row>
<row>
<entry>hibernate.generate_statistics</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Causes Hibernate to collect statistics for performance tuning.</entry>
</row>
<row>
<entry>hibernate.use_identifier_rollback</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>If true, generated identifier properties are reset to default values when objects are
deleted.</entry>
</row>
<row>
<entry>hibernate.use_sql_comments</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>If true, Hibernate generates comments inside the SQL, for easier debugging.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title>Database configuration</title>
<table>
<title>JDBC properties</title>
<tgroup cols="3">
<thead>
<row>
<entry>Property</entry>
<entry>Example</entry>
<entry>Purpose</entry>
</row>
</thead>
<tbody>
<row>
<entry>hibernate.jdbc.fetch_size</entry>
<entry><literal>0</literal> or an integer</entry>
<entry>A non-zero value determines the JDBC fetch size, by calling
<methodname>Statement.setFetchSize()</methodname>.</entry>
</row>
<row>
<entry>hibernate.jdbc.batch_size</entry>
<entry><para>A value between <literal>5</literal> and <literal>30</literal></para></entry>
<entry>A non-zero value causes Hibernate to use JDBC2 batch updates.</entry>
</row>
<row>
<entry>hibernate.jdbc.batch_versioned_data</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry><para>Set this property to <literal>true</literal> if your JDBC driver returns correct row counts
from <methodname>executeBatch()</methodname>. This option is usually safe, but is disabled by default. If
enabled, Hibernate uses batched DML for automatically versioned data.</para></entry>
</row>
<row>
<entry>hibernate.jdbc.factory_class</entry>
<entry>The fully-qualified class name of the factory</entry>
<entry><para>Select a custom <classname>org.hibernate.jdbc.Batcher</classname>. Irrelevant for most
applications.</para></entry>
</row>
<row>
<entry>hibernate.jdbc.use_scrollable_resultset</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Enables Hibernate to use JDBC2 scrollable resultsets. This property is only relevant for
user-supplied JDBC connections. Otherwise, Hibernate uses connection metadata.</entry>
</row>
<row>
<entry>hibernate.jdbc.use_streams_for_binary</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry><para>Use streams when writing or reading <type>binary</type> or <type>serializable</type> types to
or from JDBC. This is a system-level property.</para></entry>
</row>
<row>
<entry>hibernate.jdbc.use_get_generated_keys</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry><para>Allows Hibernate to use JDBC3 <classname>PreparedStatement.getGeneratedKeys()</classname> to
retrieve natively-generated keys after insert. You need the JDBC3+ driver and JRE1.4+. Disable this property
if your driver has problems with the Hibernate identifier generators. By default, it tries to detect the
driver capabilities from connection metadata.</para></entry>
</row>
</tbody>
</tgroup>
</table>
<table>
<title>Cache Properties</title>
<tgroup cols="3">
<colspec colwidth="100px" />
<colspec colwidth="100px" />
<colspec colwidth="240px" />
<thead>
<row>
<entry>Property</entry>
<entry>Example</entry>
<entry>Purpose</entry>
</row>
</thead>
<tbody>
<row>
<entry>hibernate.cache.provider_class</entry>
<entry>Fully-qualified classname</entry>
<entry>The classname of a custom CacheProvider.</entry>
</row>
<row>
<entry>hibernate.cache.use_minimal_puts</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Optimizes second-level cache operation to minimize writes, at the cost of more frequent reads. This
is most useful for clustered caches and is enabled by default for clustered cache implementations.</entry>
</row>
<row>
<entry>hibernate.cache.use_query_cache</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Enables the query cache. You still need to set individual queries to be cachable.</entry>
</row>
<row>
<entry>hibernate.cache.use_second_level_cache</entry> <entry><para><literal>true</literal> or
<literal>false</literal></para></entry> <entry>Completely disable the second level cache, which is enabled
by default for classes which specify a &lt;cache&gt; mapping.</entry>
</row>
<row>
<entry>hibernate.cache.query_cache_factory</entry>
<entry>Fully-qualified classname</entry>
<entry>A custom <interfacename>QueryCache</interfacename> interface. The default is the built-in
<interfacename>StandardQueryCache</interfacename>.</entry>
</row>
<row>
<entry>hibernate.cache.region_prefix</entry>
<entry>A string</entry>
<entry>A prefix for second-level cache region names.</entry>
</row>
<row>
<entry>hibernate.cache.use_structured_entries</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Forces Hibernate to store data in the second-level cache in a more human-readable format.</entry>
</row>
<row>
<entry>hibernate.cache.auto_evict_collection_cache</entry>
<entry><para><literal>true</literal> or <literal>false</literal> (default: false)</para></entry>
<entry>Enables the automatic eviction of a bi-directional association's collection cache when an element
in the ManyToOne collection is added/updated/removed without properly managing the change on the OneToMany
side.</entry>
</row>
<row>
<entry>hibernate.cache.use_reference_entries</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Optimizes second-level cache operation to store immutable entities (aka "reference") which do
not have associations into cache directly, this case, lots of disasseble and deep copy operations
can be avoid.
Default value of this property is <literal>false</literal>.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table>
<title>Transactions properties</title>
<tgroup cols="3">
<colspec colwidth="100px" />
<colspec colwidth="100px" />
<colspec colwidth="240px" />
<thead>
<row>
<entry>Property</entry>
<entry>Example</entry>
<entry>Purpose</entry>
</row>
</thead>
<tbody>
<row>
<entry>hibernate.transaction.factory_class</entry>
<entry>
<para><property>jdbc</property> or <property></property></para>
</entry>
<entry>
<para>
Names the <interfacename>org.hibernate.engine.transaction.spi.TransactionFactory</interfacename>
strategy implementation to use. See <xref linkend="config-strategy"/> and
<xref linkend="services-TransactionFactory"/>
</para>
</entry>
</row>
<row>
<entry>jta.UserTransaction</entry>
<entry>A JNDI name</entry>
<entry><para>The <classname>JTATransactionFactory</classname> needs a JNDI name to obtain the JTA
UserTransaction from the application server.</para></entry>
</row>
<row>
<entry>hibernate.transaction.manager_lookup_class</entry>
<entry>A fully-qualified classname</entry>
<entry><para>The classname of a <classname>TransactionManagerLookup</classname>, which is used in
conjunction with JVM-level or the hilo generator in a JTA environment.</para></entry>
</row>
<row>
<entry>hibernate.transaction.flush_before_completion</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Causes the session be flushed during the <phrase>before completion</phrase> phase of the
transaction. If possible, use built-in and automatic session context management instead.</entry>
</row>
<row>
<entry>hibernate.transaction.auto_close_session</entry>
<entry><para><literal>true</literal> or <literal>false</literal></para></entry>
<entry>Causes the session to be closed during the <phrase>after completion</phrase> phase of the
transaction. If possible, use built-in and automatic session context management instead.</entry>
</row>
</tbody>
</tgroup>
</table>
<note>
<para>
Each of the properties in the following table are prefixed by <literal>hibernate.</literal>. It has been removed
in the table to conserve space.
</para>
</note>
<table>
<title>Miscellaneous properties</title>
<tgroup cols="3">
<thead>
<row>
<entry>Property</entry>
<entry>Example</entry>
<entry>Purpose</entry>
</row>
</thead>
<tbody>
<row>
<entry>current_session_context_class</entry>
<entry><para>One of <literal>jta</literal>, <literal>thread</literal>, <literal>managed</literal>, or
<literal>custom.Class</literal></para></entry>
<entry><para>Supply a custom strategy for the scoping of the <classname>Current</classname>
Session.</para></entry>
</row>
<row>
<entry>factory_class</entry>
<entry><para><literal>org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory</literal> or
<literal>org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory</literal></para></entry>
<entry>Chooses the HQL parser implementation.</entry>
</row>
<row>
<entry>query.substitutions</entry>
<entry><para><literal>hqlLiteral=SQL_LITERAL</literal> or <literal>hqlFunction=SQLFUNC</literal>
</para></entry>
<entry>Map from tokens in Hibernate queries to SQL tokens, such as function or literal names.</entry>
</row>
<row>
<entry>hbm2ddl.auto</entry>
<entry><para><literal>validate</literal>, <literal>update</literal>, <literal>create</literal>,
<literal>create-drop</literal></para></entry>
<entry>Validates or exports schema DDL to the database when the <classname>SessionFactory</classname> is
created. With <command>create-drop</command>, the database schema is dropped when the
<classname>SessionFactory</classname> is closed explicitly.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section>
<title>Connection pool properties</title>
<itemizedlist>
<title>c3p0 connection pool properties</title>
<listitem><para>hibernate.c3p0.min_size</para></listitem>
<listitem><para>hibernate.c3p0.max_size</para></listitem>
<listitem><para>hibernate.c3p0.timeout</para></listitem>
<listitem><para>hibernate.c3p0.max_statements</para></listitem>
</itemizedlist>
<table>
<title>Proxool connection pool properties</title>
<tgroup cols="2">
<colspec colwidth="100px" />
<colspec colwidth="340px" />
<thead>
<row>
<entry>Property</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>hibernate.proxool.xml</entry>
<entry>Configure Proxool provider using an XML file (.xml is appended automatically)</entry>
</row>
<row>
<entry>hibernate.proxool.properties</entry>
<entry>Configure the Proxool provider using a properties file (.properties is appended
automatically)</entry>
</row>
<row>
<entry>hibernate.proxool.existing_pool</entry>
<entry>Whether to configure the Proxool provider from an existing pool</entry>
</row>
<row>
<entry>hibernate.proxool.pool_alias</entry>
<entry>Proxool pool alias to use. Required.</entry>
</row>
</tbody>
</tgroup>
</table>
<note>
<para>
For information on specific configuration of Proxool, refer to the Proxool documentation available from
<link xlink:href="http://proxool.sourceforge.net/" />.
</para>
</note>
</section>
</appendix>

View File

@ -1,63 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<appendix xmlns="http://docbook.org/ns/docbook">
<title>Troubleshooting</title>
<section>
<title>Log messages</title>
<para>
This section discusses certain log messages you might see from Hibernate and the "meaning" of those
messages. Specifically, it will discuss certain messages having a "message id", which for Hibernate
is always the code <literal>HHH</literal> followed by a numeric code. The table below is ordered
by this code.
</para>
<table>
<title>Explanation of identified log messages</title>
<tgroup cols="2">
<thead>
<row>
<entry>Key</entry>
<entry>Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry>HHH000002</entry>
<entry>
<para>
Indicates that a session was left associated with the
<classname>org.hibernate.context.internal.ThreadLocalSessionContext</classname> that is used
to implement thread-based current session management. Internally that class uses a
ThreadLocal, and in environments where Threads are pooled this could represent a
potential "bleed through" situation. Consider using a different
<interfacename>org.hibernate.context.spi.CurrentSessionContext</interfacename>
implementation. Otherwise, make sure the sessions always get unbound properly.
</para>
</entry>
</row>
<row>
<entry>HHH000408</entry>
<entry>
<para>
Using workaround for JVM bug in <classname>java.sql.Timestamp</classname>. Certain
JVMs are known to have a bug in the implementation of
<classname>java.sql.Timestamp</classname> that causes the following condition to
evaluate to <literal>false</literal>: <code>new Timestamp(x).getTime() != x</code>.
A huge concern here is to make sure you are not using temporal based optimistic
locking on such JVMs.
</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
</appendix>

View File

@ -1,300 +0,0 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xml:id="events"
xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
>
<title>Interceptors and events</title>
<para>
It is useful for the application to react to certain events that occur inside Hibernate. This allows for the
implementation of generic functionality and the extension of Hibernate functionality.
</para>
<section>
<title>Interceptors</title>
<para>
The <interfacename>org.hibernate.Interceptor</interfacename> interface provides callbacks from the session
to the application, allowing the application to inspect and/or manipulate properties of a persistent object
before it is saved, updated, deleted or loaded. One possible use for this is to track auditing information.
For example, the following example shows an <interfacename>Interceptor</interfacename> implementation
that automatically sets the <literal>createTimestamp</literal> property when an
<interfacename>Auditable</interfacename> entity is created and updates the
<literal>lastUpdateTimestamp</literal> property when an <interfacename>Auditable</interfacename> entity is
updated.
</para>
<note>
<para>
You can either implement <interfacename>Interceptor</interfacename> directly or extend
<classname>org.hibernate.EmptyInterceptor</classname>.
</para>
</note>
<para>
An Interceptor can be either Session-scoped or SessionFactory-scoped.
</para>
<para>
A Session-scoped interceptor is specified when a session is opened.
</para>
<programlisting role="JAVA"><xi:include href="extras/SessionScopedExample.java" parse="text"/></programlisting>
<para>
A SessionFactory-scoped interceptor is registered with the <classname>Configuration</classname> object
prior to building the SessionFactory. Unless a session is opened explicitly specifying the interceptor to
use, the SessionFactory-scoped interceptor will be applied to all sessions opened from that SessionFactory.
SessionFactory-scoped interceptors must be thread safe. Ensure that you do not store session-specific
states, since multiple sessions will use this interceptor potentially concurrently.
</para>
<programlisting role="JAVA"><xi:include href="extras/SessionFactoryScopedExample.java" parse="text"/></programlisting>
</section>
<section>
<title>Native Event system</title>
<para>
If you have to react to particular events in the persistence layer, you can also use the Hibernate
<emphasis>event</emphasis> architecture. The event system can be used in place of or in addition to
interceptors.
</para>
<para>
Many methods of the <interfacename>Session</interfacename> interface correlate to an event type. The
full range of defined event types is declared as enum values on
<classname>org.hibernate.event.spi.EventType</classname>. When a request is made of one of these methods,
the Session generates an appropriate event and passes it to the configured event listener(s) for that type.
Applications are free to implement a customization of one of the listener interfaces
(i.e., the <literal>LoadEvent</literal> is processed by the registered implementation
of the <literal>LoadEventListener</literal> interface), in which case their
implementation would be responsible for processing any <literal>load()</literal> requests
made of the <literal>Session</literal>.
</para>
<note>
<para>
See <xref linkend="registering-listeners-example"/> for information on registering custom event
listeners.
</para>
</note>
<para>
The listeners should be considered stateless; they are shared between requests, and should not save any
state as instance variables.
</para>
<para>
A custom listener implements the appropriate interface for the event it wants to process and/or extend one
of the convenience base classes (or even the default event listeners used by Hibernate out-of-the-box as
these are declared non-final for this purpose). Here is an example of a custom load event listener:
</para>
<example>
<info>
<title>Custom LoadListener example</title>
</info>
<programlisting role="JAVA"><xi:include href="extras/LoadListenerExample.java" parse="text"/></programlisting>
</example>
<section>
<title>Hibernate declarative security</title>
<para>
Usually, declarative security in Hibernate applications is managed in a session facade
layer. Hibernate allows certain actions to be permissioned via JACC, and authorized
via JAAS. This is an optional functionality that is built on top of the event architecture.
</para>
<para>
First, you must configure the appropriate event listeners, to enable the use of JACC authorization.
Again, see <xref linkend="registering-listeners-example"/> for the details. Below is an example of an
appropriate <interfacename>org.hibernate.integrator.spi.Integrator</interfacename> implementation for
this purpose.
</para>
<example>
<info>
<title>JACC listener registration example</title>
</info>
<programlisting role="JAVA"><xi:include href="extras/jacc-event-reg-example.java" parse="text" xmlns:xi="http://www.w3.org/2001/XInclude" /></programlisting>
</example>
<para>
You must also decide how to configure your JACC provider. Consult your JACC provider documentation.
</para>
</section>
</section>
<section>
<title>JPA Callbacks</title>
<para>
JPA also defines a more limited set of callbacks through annotations.
</para>
<table>
<title>Callback annotations</title>
<tgroup cols="2">
<thead>
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="3*" />
<row>
<entry align="center">Type</entry>
<entry align="center">Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
@PrePersist
</entry>
<entry>
Executed before the entity manager persist operation is actually executed or cascaded.
This call is synchronous with the persist operation.
</entry>
</row>
<row>
<entry>
@PreRemove
</entry>
<entry>
Executed before the entity manager remove operation is actually executed or cascaded.
This call is synchronous with the remove operation.
</entry>
</row>
<row>
<entry>
@PostPersist
</entry>
<entry>
Executed after the entity manager persist operation is actually executed or cascaded.
This call is invoked after the database INSERT is executed.
</entry>
</row>
<row>
<entry>
@PostRemove
</entry>
<entry>
Executed after the entity manager remove operation is actually executed or cascaded.
This call is synchronous with the remove operation.
</entry>
</row>
<row>
<entry>
@PreUpdate
</entry>
<entry>
Executed before the database UPDATE operation.
</entry>
</row>
<row>
<entry>
@PostUpdate
</entry>
<entry>
Executed after the database UPDATE operation.
</entry>
</row>
<row>
<entry>
@PostLoad
</entry>
<entry>
Executed after an entity has been loaded into the current persistence context or an entity
has been refreshed.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
There are 2 available approaches defined for specifying callback handling:
</para>
<itemizedlist>
<listitem>
<para>
The first approach is to annotate methods on the entity itself to receive notification of
particular entity life cycle event(s).
</para>
</listitem>
<listitem>
<para>
The second is to use a separate entity listener class. An entity listener is a stateless class
with a no-arg constructor. The callback annotations are placed on a method of this class instead
of the entity class. The entity listener class is then associated with the entity using the
<interfacename>javax.persistence.EntityListeners</interfacename> annotation
</para>
</listitem>
</itemizedlist>
<example>
<info>
<title>Example of specifying JPA callbacks</title>
</info>
<programlisting role="JAVA"><xi:include href="extras/JpaCallbacksExample.java" parse="text"/></programlisting>
</example>
<para>
These approaches can be mixed, meaning you can use both together.
</para>
<para>
Regardless of whether the callback method is defined on the entity or on an entity listener, it must have
a void-return signature. The name of the method is irrelevant as it is the placement of the callback
annotations that makes the method a callback. In the case of callback methods defined on the
entity class, the method must additionally have a no-argument signature. For callback methods defined on
an entity listener class, the method must have a single argument signature; the type of that argument can
be either <classname>java.lang.Object</classname> (to facilitate attachment to multiple entities) or the
specific entity type.
</para>
<para>
A callback method can throw a <classname>RuntimeException</classname>. If the callback method does
throw a <classname>RuntimeException</classname>, then the current transaction, if any, must be rolled back.
</para>
<para>
A callback method must not invoke <interfacename>EntityManager</interfacename> or
<interfacename>Query</interfacename> methods!
</para>
<para>
It is possible that multiple callback methods are defined for a particular lifecycle event. When that
is the case, the defined order of execution is well defined by the JPA spec (specifically section 3.5.4):
</para>
<itemizedlist>
<listitem>
<para>
Any default listeners associated with the entity are invoked first, in the order they were
specified in the XML. See the <interfacename>javax.persistence.ExcludeDefaultListeners</interfacename>
annotation.
</para>
</listitem>
<listitem>
<para>
Next, entity listener class callbacks associated with the entity hierarchy are invoked, in the order
they are defined in the <interfacename>EntityListeners</interfacename>. If multiple classes in the
entity hierarchy define entity listeners, the listeners defined for a superclass are invoked before
the listeners defined for its subclasses. See the
<interfacename>javax.persistence.ExcludeSuperclassListeners</interfacename> annotation.
</para>
</listitem>
<listitem>
<para>
Lastly, callback methods defined on the entity hierarchy are invoked. If a callback type is
annotated on both an entity and one or more of its superclasses without method overriding, both
would be called, the most general superclass first. An entity class is also allowed to override
a callback method defined in a superclass in which case the super callback would not get invoked;
the overriding method would get invoked provided it is annotated.
</para>
</listitem>
</itemizedlist>
</section>
</chapter>

View File

@ -1,79 +0,0 @@
import java.io.Serializable;
import java.util.Date;
import org.hibernate.EmptyInterceptor;
import org.hibernate.Transaction;
import org.hibernate.type.Type;
public class AuditInterceptor extends EmptyInterceptor {
private int updates;
private int creates;
private int loads;
public void onDelete(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
// do nothing
}
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if ( entity instanceof Auditable ) {
updates++;
for ( int i=0; i < propertyNames.length; i++ ) {
if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
currentState[i] = new Date();
return true;
}
}
}
return false;
}
public boolean onLoad(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if ( entity instanceof Auditable ) {
loads++;
}
return false;
}
public boolean onSave(Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types) {
if ( entity instanceof Auditable ) {
creates++;
for ( int i=0; i<propertyNames.length; i++ ) {
if ( "createTimestamp".equals( propertyNames[i] ) ) {
state[i] = new Date();
return true;
}
}
}
return false;
}
public void afterTransactionCompletion(Transaction tx) {
if ( tx.wasCommitted() ) {
System.out.println("Creations: " + creates + ", Updates: " + updates + "Loads: " + loads);
}
updates=0;
creates=0;
loads=0;
}
}

View File

@ -1,38 +0,0 @@
@Entity
@EntityListeners( LastUpdateListener.class )
public class Cat {
@Id private Integer id;
private String name;
private Calendar dateOfBirth;
@Transient private int age;
private Date lastUpdate;
//getters and setters
/**
* Set my transient property at load time based on a calculation,
* note that a native Hibernate formula mapping is better for this purpose.
*/
@PostLoad
public void calculateAge() {
Calendar birth = new GregorianCalendar();
birth.setTime(dateOfBirth);
Calendar now = new GregorianCalendar();
now.setTime( new Date() );
int adjust = 0;
if ( now.get(Calendar.DAY_OF_YEAR) - birth.get(Calendar.DAY_OF_YEAR) &lt; 0) {
adjust = -1;
}
age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR) + adjust;
}
}
public class LastUpdateListener {
/**
* automatic property set before any database persistence
*/
@PreUpdate
@PrePersist
public void setLastUpdate(Cat o) {
o.setLastUpdate( new Date() );
}
}

View File

@ -1,9 +0,0 @@
public class LoadListenerExample implements LoadEventListener {
// this is the single method defined by the LoadEventListener interface
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
throws HibernateException {
if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
throw MySecurityException("Unauthorized access");
}
}
}

View File

@ -1,4 +0,0 @@
SessionFactory sessionFactory = new Configuration()
.setInterceptor( new AuditInterceptor() )
...
.buildSessionFactory();

View File

@ -1 +0,0 @@
Session session = sf.withOptions().interceptor( new AuditInterceptor() ).openSession();

View File

@ -1,68 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
import org.hibernate.event.service.spi.DuplicationStrategy;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.secure.internal.JACCPreDeleteEventListener;
import org.hibernate.secure.internal.JACCPreInsertEventListener;
import org.hibernate.secure.internal.JACCPreLoadEventListener;
import org.hibernate.secure.internal.JACCPreUpdateEventListener;
import org.hibernate.secure.internal.JACCSecurityListener;
public class JaccEventListenerIntegrator implements Integrator {
private static final DuplicationStrategy JACC_DUPLICATION_STRATEGY = new DuplicationStrategy() {
@Override
public boolean areMatch(Object listener, Object original) {
return listener.getClass().equals( original.getClass() ) &&
JACCSecurityListener.class.isInstance( original );
}
@Override
public Action getAction() {
return Action.KEEP_ORIGINAL;
}
};
@Override
@SuppressWarnings( {"unchecked"})
public void integrate(
Configuration configuration,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
boolean isSecurityEnabled = configuration.getProperties().containsKey( AvailableSettings.JACC_ENABLED );
if ( !isSecurityEnabled ) {
return;
}
final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
eventListenerRegistry.addDuplicationStrategy( JACC_DUPLICATION_STRATEGY );
final String jaccContextId = configuration.getProperty( Environment.JACC_CONTEXTID );
eventListenerRegistry.prependListeners( EventType.PRE_DELETE, new JACCPreDeleteEventListener(jaccContextId) );
eventListenerRegistry.prependListeners( EventType.PRE_INSERT, new JACCPreInsertEventListener(jaccContextId) );
eventListenerRegistry.prependListeners( EventType.PRE_UPDATE, new JACCPreUpdateEventListener(jaccContextId) );
eventListenerRegistry.prependListeners( EventType.PRE_LOAD, new JACCPreLoadEventListener(jaccContextId) );
}
}

View File

@ -1,234 +0,0 @@
<?xml version='1.0' encoding="UTF-8"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xml:id="fetching"
xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xl="http://www.w3.org/1999/xlink">
<title>Fetching</title>
<para>
Fetching, essentially, is the process of grabbing data from the database and making it available to the
application. Tuning how an application does fetching is one of the biggest factors in determining how an
application will perform. Fetching too much data, in terms of width (values/columns) and/or
depth (results/rows), adds unnecessary overhead in terms of both JDBC communication and ResultSet processing.
Fetching too little data causes additional fetches to be needed. Tuning how an application
fetches data presents a great opportunity to influence the application's overall performance.
</para>
<section>
<title>The basics</title>
<para>
The concept of fetching breaks down into two different questions.
<itemizedlist>
<listitem>
<para>
When should the data be fetched? Now? Later?
</para>
</listitem>
<listitem>
<para>
How should the data be fetched?
</para>
</listitem>
</itemizedlist>
</para>
<note>
<para>
"now" is generally termed <phrase>eager</phrase> or <phrase>immediate</phrase>. "later" is
generally termed <phrase>lazy</phrase> or <phrase>delayed</phrase>.
</para>
</note>
<para>
There are a number of scopes for defining fetching:
<itemizedlist>
<listitem>
<para>
<emphasis>static</emphasis> - Static definition of fetching strategies is done in the
mappings. The statically-defined fetch strategies is used in the absence of any dynamically
defined strategies <footnote><para>Except in the case of HQL/JPQL; see xyz</para></footnote>.
</para>
</listitem>
<listitem>
<para>
<emphasis>dynamic</emphasis> (sometimes referred to as runtime) - Dynamic definition is
really use-case centric. There are 2 main ways to define dynamic fetching:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>fetch profiles</emphasis> - defined in mappings, but can be
enabled/disabled on the Session.
</para>
</listitem>
<listitem>
<para>
HQL/JPQL and both Hibernate and JPA Criteria queries have the ability to specify
fetching, specific to said query.
</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
</para>
<variablelist>
<title>The strategies</title>
<varlistentry>
<term>SELECT</term>
<listitem>
<para>
Performs a separate SQL select to load the data. This can either be EAGER (the second select
is issued immediately) or LAZY (the second select is delayed until the data is needed). This
is the strategy generally termed <phrase>N+1</phrase>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>JOIN</term>
<listitem>
<para>
Inherently an EAGER style of fetching. The data to be fetched is obtained through the use of
an SQL join.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>BATCH</term>
<listitem>
<para>
Performs a separate SQL select to load a number of related data items using an
IN-restriction as part of the SQL WHERE-clause based on a batch size. Again, this can either
be EAGER (the second select is issued immediately) or LAZY (the second select is delayed until
the data is needed).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>SUBSELECT</term>
<listitem>
<para>
Performs a separate SQL select to load associated data based on the SQL restriction used to
load the owner. Again, this can either be EAGER (the second select is issued immediately)
or LAZY (the second select is delayed until the data is needed).
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section>
<title>Applying fetch strategies</title>
<para>
Let's consider these topics as it relates to an simple domain model and a few use cases.
</para>
<example>
<title>Sample domain model</title>
<programlisting role="JAVA"><xi:include href="extras/Employee.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/Department.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/Project.java" parse="text"/></programlisting>
</example>
<important>
<para>
The Hibernate recommendation is to statically mark all associations lazy and to use dynamic fetching
strategies for eagerness. This is unfortunately at odds with the JPA specification which defines that
all one-to-one and many-to-one associations should be eagerly fetched by default. Hibernate, as a JPA
provider honors that default.
</para>
</important>
<section>
<title>No fetching</title>
<subtitle>The login use-case</subtitle>
<para>
For the first use case, consider the application's login process for an Employee. Lets assume that
login only requires access to the Employee information, not Project nor Department information.
</para>
<example>
<title>No fetching example</title>
<programlisting role="JAVA"><xi:include href="extras/Login.java" parse="text"/></programlisting>
</example>
<para>
In this example, the application gets the Employee data. However, because all associations from
Employee are declared as LAZY (JPA defines the default for collections as LAZY) no other data is
fetched.
</para>
<para>
If the login process does not need access to the Employee information specifically, another
fetching optimization here would be to limit the width of the query results.
</para>
<example>
<title>No fetching (scalar) example</title>
<programlisting role="JAVA"><xi:include href="extras/LoginScalar.java" parse="text"/></programlisting>
</example>
</section>
<section>
<title>Dynamic fetching via queries</title>
<subtitle>The projects for an employee use-case</subtitle>
<para>
For the second use case, consider a screen displaying the Projects for an Employee. Certainly access
to the Employee is needed, as is the collection of Projects for that Employee. Information
about Departments, other Employees or other Projects is not needed.
</para>
<example>
<title>Dynamic query fetching example</title>
<programlisting role="JAVA"><xi:include href="extras/ProjectsForAnEmployeeHql.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/ProjectsForAnEmployeeCriteria.java" parse="text"/></programlisting>
</example>
<para>
In this example we have an Employee and their Projects loaded in a single query shown both as an HQL
query and a JPA Criteria query. In both cases, this resolves to exactly one database query to get
all that information.
</para>
</section>
<section>
<title>Dynamic fetching via profiles</title>
<subtitle>The projects for an employee use-case using natural-id</subtitle>
<para>
Suppose we wanted to leverage loading by natural-id to obtain the Employee information in the
"projects for and employee" use-case. Loading by natural-id uses the statically defined fetching
strategies, but does not expose a means to define load-specific fetching. So we would leverage a
fetch profile.
</para>
<example>
<title>Fetch profile example</title>
<programlisting role="JAVA"><xi:include href="extras/FetchOverrides.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/ProjectsForAnEmployeeFetchProfile.java" parse="text"/></programlisting>
</example>
<para>
Here the Employee is obtained by natural-id lookup and the Employee's Project data is fetched eagerly.
If the Employee data is resolved from cache, the Project data is resolved on its own. However,
if the Employee data is not resolved in cache, the Employee and Project data is resolved in one
SQL query via join as we saw above.
</para>
</section>
</section>
<!-- todo : document special fetching considerations such as batch fetching, subselect fetching and extra laziness -->
</chapter>

View File

@ -1,10 +0,0 @@
@Entity
public class Department {
@Id
private Long id;
@OneToMany(mappedBy="department")
private List<Employees> employees;
...
}

View File

@ -1,24 +0,0 @@
@Entity
public class Employee {
@Id
private Long id;
@NaturalId
private String userid;
@Column( name="pswd" )
@ColumnTransformer( read="decrypt(pswd)" write="encrypt(?)" )
private String password;
private int accessLevel;
@ManyToOne( fetch=LAZY )
@JoinColumn
private Department department;
@ManyToMany(mappedBy="employees")
@JoinColumn
private Set<Project> projects;
...
}

View File

@ -1,10 +0,0 @@
@FetchProfile(
name="employee.projects",
fetchOverrides={
@FetchOverride(
entity=Employee.class,
association="projects",
mode=JOIN
)
}
)

View File

@ -1,4 +0,0 @@
String loginHql = "select e from Employee e where e.userid = :userid and e.password = :password";
Employee employee = (Employee) session.createQuery( loginHql )
...
.uniqueResult();

View File

@ -1,4 +0,0 @@
String loginHql = "select e.accessLevel from Employee e where e.userid = :userid and e.password = :password";
Employee employee = (Employee) session.createQuery( loginHql )
...
.uniqueResult();

View File

@ -1,10 +0,0 @@
@Entity
public class Project {
@Id
private Long id;
@ManyToMany
private Set<Employee> employees;
...
}

View File

@ -1,10 +0,0 @@
String userid = ...;
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> criteria = cb.createQuery( Employee.class );
Root<Employee> root = criteria.from( Employee.class );
root.fetch( Employee_.projects );
criteria.select( root );
criteria.where(
cb.equal( root.get( Employee_.userid ), cb.literal( userid ) )
);
Employee e = entityManager.createQuery( criteria ).getSingleResult();

View File

@ -1,4 +0,0 @@
String userid = ...;
session.enableFetchProfile( "employee.projects" );
Employee e = (Employee) session.bySimpleNaturalId( Employee.class )
.load( userid );

View File

@ -1,5 +0,0 @@
String userid = ...;
String hql = "select e from Employee e join fetch e.projects where e.userid = :userid";
Employee e = (Employee) session.createQuery( hql )
.setParameter( "userid", userid )
.uniqueResult();

View File

@ -1,313 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Multi-tenancy</title>
<section>
<title>What is multi-tenancy?</title>
<para>
The term multi-tenancy in general is applied to software development to indicate an architecture in which
a single running instance of an application simultaneously serves multiple clients (tenants). This is
highly common in SaaS solutions. Isolating information (data, customizations, etc) pertaining to the
various tenants is a particular challenge in these systems. This includes the data owned by each tenant
stored in the database. It is this last piece, sometimes called multi-tenant data, on which we will focus.
</para>
</section>
<section>
<title>Multi-tenant data approaches</title>
<para>
There are 3 main approaches to isolating information in these multi-tenant systems which goes hand-in-hand
with different database schema definitions and JDBC setups.
</para>
<note>
<para>
Each approach has pros and cons as well as specific techniques and considerations. Such
topics are beyond the scope of this documentation. Many resources exist which delve into these
other topics. One example is <link xl:href="http://msdn.microsoft.com/en-us/library/aa479086.aspx"/>
which does a great job of covering these topics.
</para>
</note>
<section>
<title>Separate database</title>
<mediaobject>
<imageobject role="html">
<imagedata fileref="chapters/multitenancy/images/multitenacy_database.png" format="PNG" align="center" />
</imageobject>
<imageobject role="fo">
<imagedata fileref="chapters/multitenancy/images/multitenacy_database.svg" format="SVG" align="center" width="17cm" />
</imageobject>
</mediaobject>
<para>
Each tenant's data is kept in a physically separate database instance. JDBC Connections would point
specifically to each database, so any pooling would be per-tenant. A general application approach
here would be to define a JDBC Connection pool per-tenant and to select the pool to use based on the
<quote>tenant identifier</quote> associated with the currently logged in user.
</para>
</section>
<section>
<title>Separate schema</title>
<mediaobject>
<imageobject role="html">
<imagedata fileref="chapters/multitenancy/images/multitenacy_schema.png" format="PNG" align="center" />
</imageobject>
<imageobject role="fo">
<imagedata fileref="chapters/multitenancy/images/multitenacy_schema.svg" format="SVG" align="center" width="17cm" />
</imageobject>
</mediaobject>
<para>
Each tenant's data is kept in a distinct database schema on a single database instance. There are 2
different ways to define JDBC Connections here:
<itemizedlist>
<listitem>
<para>
Connections could point specifically to each schema, as we saw with the
<literal>Separate database</literal> approach. This is an option provided that
the driver supports naming the default schema in the connection URL or if the
pooling mechanism supports naming a schema to use for its Connections. Using this
approach, we would have a distinct JDBC Connection pool per-tenant where the pool to use
would be selected based on the <quote>tenant identifier</quote> associated with the
currently logged in user.
</para>
</listitem>
<listitem>
<para>
Connections could point to the database itself (using some default schema) but
the Connections would be altered using the SQL <literal>SET SCHEMA</literal> (or similar)
command. Using this approach, we would have a single JDBC Connection pool for use to
service all tenants, but before using the Connection it would be altered to reference
the schema named by the <quote>tenant identifier</quote> associated with the currently
logged in user.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Partitioned (discriminator) data</title>
<mediaobject>
<imageobject role="html">
<imagedata fileref="chapters/multitenancy/images/multitenacy_discriminator.png" format="PNG" align="center" />
</imageobject>
<imageobject role="fo">
<imagedata fileref="chapters/multitenancy/images/multitenacy_discriminator.svg" format="SVG" align="center" width="17cm" />
</imageobject>
</mediaobject>
<para>
All data is kept in a single database schema. The data for each tenant is partitioned by the use of
partition value or discriminator. The complexity of this discriminator might range from a simple
column value to a complex SQL formula. Again, this approach would use a single Connection pool
to service all tenants. However, in this approach the application needs to alter each and every
SQL statement sent to the database to reference the <quote>tenant identifier</quote> discriminator.
</para>
</section>
</section>
<section>
<title>Multi-tenancy in Hibernate</title>
<para>
Using Hibernate with multi-tenant data comes down to both an API and then integration piece(s). As
usual Hibernate strives to keep the API simple and isolated from any underlying integration complexities.
The API is really just defined by passing the tenant identifier as part of opening any session.
</para>
<example id="specifying-tenant-ex">
<title>Specifying tenant identifier from <interfacename>SessionFactory</interfacename></title>
<programlisting role="JAVA"><xi:include href="extras/tenant-identifier-from-SessionFactory.java" parse="text"/></programlisting>
</example>
<para>
Additionally, when specifying configuration, a <classname>org.hibernate.MultiTenancyStrategy</classname>
should be named using the <property>hibernate.multiTenancy</property> setting. Hibernate will perform
validations based on the type of strategy you specify. The strategy here correlates to the isolation
approach discussed above.
</para>
<variablelist>
<varlistentry>
<term>NONE</term>
<listitem>
<para>
(the default) No multi-tenancy is expected. In fact, it is considered an error if a tenant
identifier is specified when opening a session using this strategy.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>SCHEMA</term>
<listitem>
<para>
Correlates to the separate schema approach. It is an error to attempt to open a session without
a tenant identifier using this strategy. Additionally, a
<interfacename>MultiTenantConnectionProvider</interfacename>
must be specified.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>DATABASE</term>
<listitem>
<para>
Correlates to the separate database approach. It is an error to attempt to open a session without
a tenant identifier using this strategy. Additionally, a
<interfacename>MultiTenantConnectionProvider</interfacename>
must be specified.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>DISCRIMINATOR</term>
<listitem>
<para>
Correlates to the partitioned (discriminator) approach. It is an error to attempt to open a
session without a tenant identifier using this strategy. This strategy is not yet implemented
in Hibernate as of 4.0 and 4.1. Its support is planned for 5.0.
</para>
</listitem>
</varlistentry>
</variablelist>
<section>
<title><interfacename>MultiTenantConnectionProvider</interfacename></title>
<para>
When using either the DATABASE or SCHEMA approach, Hibernate needs to be able to obtain Connections
in a tenant specific manner. That is the role of the
<interfacename>MultiTenantConnectionProvider</interfacename>
contract. Application developers will need to provide an implementation of this
contract. Most of its methods are extremely self-explanatory. The only ones which might not be are
<methodname>getAnyConnection</methodname> and <methodname>releaseAnyConnection</methodname>. It is
important to note also that these methods do not accept the tenant identifier. Hibernate uses these
methods during startup to perform various configuration, mainly via the
<classname>java.sql.DatabaseMetaData</classname> object.
</para>
<para>
The <interfacename>MultiTenantConnectionProvider</interfacename> to use can be specified in a number of
ways:
</para>
<itemizedlist>
<listitem>
<para>
Use the <property>hibernate.multi_tenant_connection_provider</property> setting. It could
name a <interfacename>MultiTenantConnectionProvider</interfacename> instance, a
<interfacename>MultiTenantConnectionProvider</interfacename> implementation class reference or
a <interfacename>MultiTenantConnectionProvider</interfacename> implementation class name.
</para>
</listitem>
<listitem>
<para>
Passed directly to the <classname>org.hibernate.boot.registry.StandardServiceRegistryBuilder</classname>.
</para>
</listitem>
<listitem>
<para>
If none of the above options match, but the settings do specify a
<property>hibernate.connection.datasource</property> value, Hibernate will assume it should
use the specific
<classname>DataSourceBasedMultiTenantConnectionProviderImpl</classname>
implementation which works on a number of pretty reasonable assumptions when running inside of
an app server and using one <interfacename>javax.sql.DataSource</interfacename> per tenant.
See its javadocs for more details.
</para>
</listitem>
</itemizedlist>
</section>
<section>
<title><interfacename>CurrentTenantIdentifierResolver</interfacename></title>
<para>
<interfacename>org.hibernate.context.spi.CurrentTenantIdentifierResolver</interfacename> is a contract
for Hibernate to be able to resolve what the application considers the current tenant identifier.
The implementation to use is either passed directly to <classname>Configuration</classname> via its
<methodname>setCurrentTenantIdentifierResolver</methodname> method. It can also be specified via
the <property>hibernate.tenant_identifier_resolver</property> setting.
</para>
<para>
There are 2 situations where <interfacename>CurrentTenantIdentifierResolver</interfacename> is used:
</para>
<itemizedlist>
<listitem>
<para>
The first situation is when the application is using the
<interfacename>org.hibernate.context.spi.CurrentSessionContext</interfacename> feature in
conjunction with multi-tenancy. In the case of the current-session feature, Hibernate will
need to open a session if it cannot find an existing one in scope. However, when a session
is opened in a multi-tenant environment the tenant identifier has to be specified. This is
where the <interfacename>CurrentTenantIdentifierResolver</interfacename> comes into play;
Hibernate will consult the implementation you provide to determine the tenant identifier to use
when opening the session. In this case, it is required that a
<interfacename>CurrentTenantIdentifierResolver</interfacename> be supplied.
</para>
</listitem>
<listitem>
<para>
The other situation is when you do not want to have to explicitly specify the tenant
identifier all the time as we saw in <xref linkend="specifying-tenant-ex"/>. If a
<interfacename>CurrentTenantIdentifierResolver</interfacename> has been specified, Hibernate
will use it to determine the default tenant identifier to use when opening the session.
</para>
</listitem>
</itemizedlist>
<para>
Additionally, if the <interfacename>CurrentTenantIdentifierResolver</interfacename> implementation
returns <literal>true</literal> for its <methodname>validateExistingCurrentSessions</methodname>
method, Hibernate will make sure any existing sessions that are found in scope have a matching
tenant identifier. This capability is only pertinent when the
<interfacename>CurrentTenantIdentifierResolver</interfacename> is used in current-session settings.
</para>
</section>
<section>
<title>Caching</title>
<para>
Multi-tenancy support in Hibernate works seamlessly with the Hibernate second level cache. The key
used to cache data encodes the tenant identifier.
</para>
</section>
<section>
<title>Odds and ends</title>
<para>
Currently schema export will not really work with multi-tenancy. That may not change.
</para>
<para>
The JPA expert group is in the process of defining multi-tenancy support for the upcoming 2.1
version of the specification.
</para>
</section>
</section>
<section>
<title>Strategies for <interfacename>MultiTenantConnectionProvider</interfacename> implementors</title>
<example>
<title>Implementing MultiTenantConnectionProvider using different connection pools</title>
<programlisting role="JAVA"><xi:include href="extras/MultiTenantConnectionProviderImpl-multi-cp.java" parse="text"/></programlisting>
</example>
<para>
The approach above is valid for the DATABASE approach. It is also valid for the SCHEMA approach
provided the underlying database allows naming the schema to which to connect in the connection URL.
</para>
<example>
<title>Implementing MultiTenantConnectionProvider using single connection pool</title>
<programlisting role="JAVA"><xi:include href="extras/MultiTenantConnectionProviderImpl-single-cp.java" parse="text"/></programlisting>
</example>
<para>
This approach is only relevant to the SCHEMA approach.
</para>
</section>
</chapter>

View File

@ -1,24 +0,0 @@
/**
* Simplisitc implementation for illustration purposes supporting 2 hard coded providers (pools) and leveraging
* the support class {@link org.hibernate.service.jdbc.connections.spi.AbstractMultiTenantConnectionProvider}
*/
public class MultiTenantConnectionProviderImpl extends AbstractMultiTenantConnectionProvider {
private final ConnectionProvider acmeProvider = ConnectionProviderUtils.buildConnectionProvider( "acme" );
private final ConnectionProvider jbossProvider = ConnectionProviderUtils.buildConnectionProvider( "jboss" );
@Override
protected ConnectionProvider getAnyConnectionProvider() {
return acmeProvider;
}
@Override
protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) {
if ( "acme".equals( tenantIdentifier ) ) {
return acmeProvider;
}
else if ( "jboss".equals( tenantIdentifier ) ) {
return jbossProvider;
}
throw new HibernateException( "Unknown tenant identifier" );
}
}

View File

@ -1,54 +0,0 @@
/**
* Simplisitc implementation for illustration purposes showing a single connection pool used to serve
* multiple schemas using "connection altering". Here we use the T-SQL specific USE command; Oracle
* users might use the ALTER SESSION SET SCHEMA command; etc.
*/
public class MultiTenantConnectionProviderImpl
implements MultiTenantConnectionProvider, Stoppable {
private final ConnectionProvider connectionProvider = ConnectionProviderUtils.buildConnectionProvider( "master" );
@Override
public Connection getAnyConnection() throws SQLException {
return connectionProvider.getConnection();
}
@Override
public void releaseAnyConnection(Connection connection) throws SQLException {
connectionProvider.closeConnection( connection );
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
final Connection connection = getAnyConnection();
try {
connection.createStatement().execute( "USE " + tenanantIdentifier );
}
catch ( SQLException e ) {
throw new HibernateException(
"Could not alter JDBC connection to specified schema [" +
tenantIdentifier + "]",
e
);
}
return connection;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
try {
connection.createStatement().execute( "USE master" );
}
catch ( SQLException e ) {
// on error, throw an exception to make sure the connection is not returned to the pool.
// your requirements may differ
throw new HibernateException(
"Could not alter JDBC connection to specified schema [" +
tenantIdentifier + "]",
e
);
}
connectionProvider.closeConnection( connection );
}
...
}

View File

@ -1,4 +0,0 @@
Session session = sessionFactory.withOptions()
.tenantIdentifier( yourTenantIdentifier )
...
.openSession();

View File

@ -1,130 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="400px" height="400px" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="451.2393" y1="550.3125" x2="584.1797" y2="550.3125" gradientTransform="matrix(1 0 0 1 -192 -211)">
<stop offset="0" style="stop-color:#F3D99F"/>
<stop offset="0.459" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</linearGradient>
<path fill="url(#SVGID_1_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M392.177,285.951c-0.177-0.01-0.401-0.021-0.597-0.031c-0.039,0.734-0.175,1.463-0.387,2.165c-0.064,0.217-0.139,0.427-0.215,0.638
c-0.065,0.18-0.142,0.356-0.217,0.534c0.021,0.048,0.002,0-0.098,0.21c-0.098,0.21-0.203,0.42-0.312,0.624
c-0.25,0.462-0.528,0.912-0.834,1.345c-0.504,0.717-1.074,1.392-1.683,2.021c-0.771,0.804-1.608,1.552-2.494,2.23
c-0.472,0.363-0.95,0.719-1.44,1.062c-0.353,0.245-0.709,0.481-1.067,0.713c-0.324,0.208-0.396,0.25-0.646,0.399
c-0.385,0.238-0.776,0.468-1.17,0.69c-0.574,0.327-1.151,0.644-1.736,0.944c-1.301,0.673-2.635,1.286-3.98,1.857
c-2.719,1.147-5.507,2.106-8.334,2.957c-4.572,1.368-9.24,2.381-13.945,3.191c-12.86,2.218-26.09,2.678-39.101,1.81
c-12.298-0.819-24.896-2.78-36.396-7.385c-4.02-1.604-7.938-3.549-11.379-6.19c-1.338-1.026-2.588-2.188-3.646-3.502
c-0.54-0.672-1.026-1.385-1.437-2.144c-0.217-0.401-0.408-0.815-0.578-1.244c-0.107-0.272-0.135-0.932-0.531-0.677
c0.059-0.049,0.135-0.104,0.201-0.146c0.082-0.058-0.098-0.535-0.119-0.646c-0.105-0.479-0.18-0.971-0.204-1.46
c-0.697,0.037-0.604-0.021-0.57,0.578c0.036,0.647,0.07,1.299,0.105,1.948c0.13,2.438,0.261,4.875,0.393,7.312
c0.398,7.426,2.526,65.109,2.63,67.02c0.152,2.86,0.821,5.536,2.285,8.043c1.827,3.123,4.448,5.606,7.28,7.813
c1.485,1.16,3.103,2.174,4.729,3.117c0.844,0.487,1.709,0.938,2.569,1.396c0.368,0.196,0.748,0.371,1.124,0.556
c0.289,0.144,0.294,0.146,0.602,0.292c0.437,0.205,0.871,0.407,1.311,0.598c0.557,0.241,1.109,0.487,1.672,0.718
c1.211,0.495,2.434,0.958,3.664,1.405c2.477,0.897,5.012,1.623,7.557,2.308c0.099,0.025,0.099,0.025,0.459,0.119
c0.39,0.099,0.774,0.195,1.164,0.288c0.493,0.12,0.989,0.233,1.486,0.349c0.902,0.205,1.811,0.394,2.718,0.577
c2.568,0.524,5.162,0.938,7.761,1.275c4.52,0.589,9.062,0.93,13.617,1.038c9.441,0.227,18.909-0.502,28.18-2.346
c9.291-1.848,18.74-4.875,26.695-10.127c5.562-3.671,11.322-9.271,11.703-16.37c0.219-4.078,2.598-66.387,2.953-73.012
c0.085-1.609,0.082-3.254,0.26-4.855c-0.1-0.006-0.195-0.012-0.296-0.018C391.975,285.947,392.102,285.95,392.177,285.951
L392.177,285.951z"/>
<g>
<radialGradient id="SVGID_2_" cx="443.2275" cy="472.4014" r="113.4365" gradientTransform="matrix(1 0 0 1 -192 -211)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</radialGradient>
<path fill="url(#SVGID_2_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M325.708,260.852c8.188,0,16.041,0.559,23.281,1.57c7.312,1.023,14.065,2.525,19.94,4.407c5.979,1.918,11.096,4.245,14.965,6.89
c3.967,2.709,6.648,5.768,7.608,9.067c0.99,3.399,0.062,6.737-2.532,9.858c-2.666,3.207-7.08,6.174-12.937,8.725
c-5.979,2.604-13.416,4.751-21.929,6.26c-8.614,1.523-18.236,2.376-28.399,2.376s-19.785-0.853-28.401-2.376
c-8.511-1.509-15.947-3.656-21.929-6.26c-5.854-2.551-10.269-5.518-12.937-8.725c-2.594-3.121-3.521-6.459-2.532-9.858
c0.961-3.302,3.645-6.358,7.608-9.067c3.871-2.645,8.985-4.972,14.967-6.89c5.873-1.882,12.627-3.384,19.939-4.407
C309.665,261.408,317.52,260.852,325.708,260.852z"/>
</g>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="421.2871" y1="-4.5" x2="421.2871" y2="-123.5384" gradientTransform="matrix(1 0 0 -1 -96 195)">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon fill="url(#SVGID_3_)" points="343.225,234.604 343.225,178.389 307.352,178.389 307.352,234.604 279.354,234.604
325.289,280.538 371.223,234.604 "/>
<polygon fill="#94AEBD" points="363.512,152.833 288.564,152.833 260.075,204.552 391.346,204.552 "/>
<rect x="181.857" y="40.9" fill="#86BF40" width="35.872" height="78.404"/>
<g>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="200.749" y1="550.3125" x2="333.6875" y2="550.3125" gradientTransform="matrix(1 0 0 1 -192 -211)">
<stop offset="0" style="stop-color:#F3D99F"/>
<stop offset="0.459" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</linearGradient>
<path fill="url(#SVGID_4_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M141.682,285.951c-0.175-0.01-0.401-0.021-0.596-0.031c-0.036,0.734-0.174,1.463-0.385,2.165c-0.065,0.217-0.14,0.427-0.216,0.638
c-0.065,0.18-0.139,0.356-0.217,0.534c0.022,0.048,0,0-0.096,0.21c-0.098,0.21-0.203,0.42-0.314,0.624
c-0.248,0.462-0.527,0.912-0.83,1.345c-0.505,0.717-1.075,1.392-1.684,2.021c-0.771,0.804-1.61,1.552-2.494,2.23
c-0.474,0.363-0.949,0.719-1.439,1.062c-0.354,0.245-0.709,0.481-1.07,0.713c-0.324,0.208-0.394,0.25-0.645,0.399
c-0.385,0.238-0.777,0.468-1.172,0.69c-0.571,0.327-1.149,0.644-1.733,0.944c-1.301,0.673-2.634,1.286-3.982,1.857
c-2.718,1.147-5.507,2.106-8.335,2.957c-4.573,1.368-9.243,2.381-13.945,3.191c-12.862,2.218-26.09,2.678-39.099,1.81
c-12.298-0.819-24.897-2.78-36.396-7.385c-4.02-1.604-7.937-3.549-11.38-6.19c-1.339-1.026-2.588-2.188-3.646-3.502
c-0.537-0.672-1.025-1.385-1.432-2.144c-0.219-0.401-0.41-0.815-0.579-1.244c-0.108-0.272-0.136-0.932-0.531-0.677
c0.057-0.049,0.136-0.104,0.201-0.146c0.081-0.058-0.097-0.535-0.121-0.646c-0.105-0.479-0.178-0.971-0.203-1.46
c-0.699,0.037-0.604-0.021-0.57,0.578c0.035,0.647,0.069,1.299,0.105,1.948c0.13,2.438,0.261,4.875,0.392,7.312
c0.398,7.426,2.527,65.109,2.631,67.02c0.151,2.86,0.821,5.536,2.284,8.043c1.828,3.123,4.448,5.606,7.28,7.813
c1.486,1.16,3.101,2.174,4.73,3.117c0.844,0.487,1.706,0.938,2.567,1.396c0.369,0.196,0.75,0.371,1.125,0.556
c0.289,0.144,0.295,0.146,0.603,0.292c0.434,0.205,0.868,0.407,1.308,0.598c0.557,0.241,1.11,0.487,1.673,0.718
c1.21,0.495,2.433,0.958,3.663,1.405c2.478,0.897,5.012,1.623,7.556,2.308c0.099,0.025,0.099,0.025,0.462,0.119
c0.386,0.099,0.773,0.195,1.161,0.288c0.496,0.12,0.992,0.233,1.489,0.349c0.903,0.205,1.809,0.394,2.717,0.577
c2.567,0.524,5.16,0.938,7.761,1.275c4.516,0.589,9.062,0.93,13.615,1.038c9.442,0.227,18.91-0.502,28.178-2.346
c9.292-1.848,18.743-4.875,26.698-10.127c5.559-3.671,11.322-9.271,11.703-16.37c0.219-4.078,2.597-66.387,2.953-73.012
c0.086-1.609,0.082-3.254,0.261-4.855c-0.1-0.006-0.199-0.012-0.297-0.018C141.481,285.947,141.607,285.95,141.682,285.951
L141.682,285.951z"/>
<g>
<radialGradient id="SVGID_5_" cx="192.7339" cy="472.4014" r="113.4383" gradientTransform="matrix(1 0 0 1 -192 -211)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</radialGradient>
<path fill="url(#SVGID_5_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M75.216,260.852c8.188,0,16.041,0.559,23.279,1.57c7.312,1.023,14.066,2.525,19.94,4.407c5.982,1.918,11.097,4.245,14.967,6.89
c3.967,2.709,6.65,5.768,7.612,9.067c0.987,3.399,0.061,6.737-2.535,9.858c-2.667,3.207-7.081,6.174-12.937,8.725
c-5.979,2.604-13.417,4.751-21.928,6.26c-8.616,1.523-18.237,2.376-28.399,2.376c-10.166,0-19.787-0.853-28.401-2.376
c-8.512-1.509-15.948-3.656-21.929-6.26c-5.855-2.551-10.269-5.518-12.935-8.725c-2.596-3.121-3.524-6.459-2.534-9.858
c0.962-3.302,3.644-6.358,7.609-9.067c3.871-2.645,8.985-4.972,14.968-6.89c5.874-1.882,12.627-3.384,19.938-4.407
C59.173,261.408,67.025,260.852,75.216,260.852z"/>
</g>
</g>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="170.313" y1="-4.5" x2="170.313" y2="-123.5384" gradientTransform="matrix(1 0 0 -1 -96 195)">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon fill="url(#SVGID_6_)" points="92.247,234.604 92.247,178.389 56.375,178.389 56.375,234.604 28.379,234.604
74.313,280.538 120.246,234.604 "/>
<polygon fill="#94AEBD" points="113.021,152.833 38.071,152.833 9.583,204.552 140.853,204.552 "/>
<polygon fill="#86BF40" points="56.361,99.985 56.361,178.389 92.234,178.389 92.234,135.858 307.352,135.858 307.352,178.389
343.227,178.389 343.227,99.985 "/>
<path fill="#424242" d="M275.075,51.364c0,1.99-1.614,3.604-3.603,3.604H127.312c-1.989,0-3.604-1.613-3.604-3.604V11.719
c0-1.99,1.614-3.604,3.604-3.604h144.161c1.988,0,3.604,1.614,3.604,3.604L275.075,51.364L275.075,51.364z"/>
<text transform="matrix(1 0 0 1 39.5 327.5)" font-family="'Frutiger-BoldCn'" font-size="12">CUSTOMER (</text>
<text transform="matrix(1 0 0 1 39.5 339.9004)" font-family="'Frutiger-BoldCn'" font-size="12">ID BIGINT,</text>
<text transform="matrix(1 0 0 1 39.5 352.2998)" font-family="'Frutiger-BoldCn'" font-size="12">NAME VARCHAR,</text>
<text transform="matrix(1 0 0 1 39.5 364.7002)" font-family="'Frutiger-BoldCn'" font-size="12">...</text>
<text transform="matrix(1 0 0 1 39.5 377.0996)" font-family="'Frutiger-BoldCn'" font-size="12">)</text>
<text transform="matrix(1 0 0 1 292.5 327.5)" font-family="'Frutiger-BoldCn'" font-size="12">CUSTOMER (</text>
<text transform="matrix(1 0 0 1 292.5 339.9004)" font-family="'Frutiger-BoldCn'" font-size="12">ID BIGINT,</text>
<text transform="matrix(1 0 0 1 292.5 352.2998)" font-family="'Frutiger-BoldCn'" font-size="12">NAME VARCHAR,</text>
<text transform="matrix(1 0 0 1 292.5 364.7002)" font-family="'Frutiger-BoldCn'" font-size="12">...</text>
<text transform="matrix(1 0 0 1 292.5 377.0996)" font-family="'Frutiger-BoldCn'" font-size="12">)</text>
<text transform="matrix(1 0 0 1 142.875 40.5801)" fill="#FFFFFF" font-family="'Frutiger-BoldCn'" font-size="24">Application</text>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="74.3188" y1="164.2451" x2="74.3188" y2="250.498">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<rect x="56.383" y="175.495" fill="url(#SVGID_7_)" width="35.871" height="29.135"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="325.2891" y1="164.2451" x2="325.2891" y2="250.498">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<rect x="307.354" y="175.495" fill="url(#SVGID_8_)" width="35.87" height="29.135"/>
</svg>

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="400px" height="400px" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="235.0928" y1="-79.4072" x2="368.0312" y2="-79.4072" gradientTransform="matrix(1 0 0 -1 -96 195)">
<stop offset="0" style="stop-color:#F3D99F"/>
<stop offset="0.459" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</linearGradient>
<path fill="url(#SVGID_1_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M272.025,221.045c-0.176-0.008-0.4-0.021-0.596-0.029c-0.037,0.732-0.174,1.461-0.386,2.166c-0.063,0.215-0.14,0.424-0.216,0.633
c-0.064,0.183-0.139,0.36-0.217,0.537c0.022,0.047,0.002,0.002-0.096,0.209c-0.098,0.211-0.203,0.42-0.312,0.625
c-0.251,0.463-0.529,0.914-0.832,1.342c-0.505,0.719-1.075,1.392-1.684,2.021c-0.772,0.805-1.608,1.553-2.494,2.233
c-0.473,0.362-0.949,0.72-1.439,1.06c-0.352,0.244-0.709,0.482-1.068,0.715c-0.324,0.207-0.395,0.248-0.645,0.401
c-0.387,0.235-0.777,0.464-1.172,0.688c-0.572,0.326-1.151,0.643-1.735,0.943c-1.3,0.674-2.634,1.286-3.981,1.857
c-2.719,1.148-5.508,2.109-8.334,2.957c-4.573,1.371-9.242,2.381-13.946,3.193c-12.861,2.219-26.09,2.678-39.099,1.809
c-12.298-0.819-24.897-2.781-36.396-7.383c-4.018-1.607-7.937-3.551-11.379-6.191c-1.338-1.027-2.588-2.188-3.646-3.503
c-0.539-0.673-1.026-1.386-1.434-2.144c-0.216-0.402-0.41-0.816-0.578-1.242c-0.108-0.275-0.135-0.933-0.532-0.678
c0.058-0.049,0.137-0.104,0.204-0.148c0.079-0.055-0.098-0.534-0.122-0.645c-0.106-0.479-0.177-0.97-0.203-1.459
c-0.699,0.036-0.603-0.021-0.571,0.576c0.036,0.648,0.07,1.299,0.105,1.949c0.13,2.438,0.262,4.876,0.393,7.312
c0.398,7.426,2.526,65.11,2.629,67.02c0.153,2.859,0.823,5.536,2.286,8.04c1.826,3.124,4.449,5.607,7.279,7.815
c1.487,1.16,3.101,2.175,4.73,3.116c0.844,0.49,1.707,0.941,2.568,1.398c0.368,0.196,0.75,0.371,1.125,0.555
c0.288,0.144,0.295,0.146,0.602,0.29c0.434,0.205,0.869,0.41,1.31,0.599c0.556,0.241,1.109,0.487,1.672,0.718
c1.211,0.495,2.433,0.959,3.662,1.406c2.479,0.897,5.013,1.624,7.557,2.308c0.097,0.025,0.097,0.025,0.46,0.119
c0.388,0.098,0.775,0.193,1.163,0.289c0.495,0.118,0.991,0.231,1.488,0.346c0.902,0.208,1.809,0.394,2.717,0.579
c2.568,0.522,5.161,0.938,7.761,1.276c4.517,0.587,9.062,0.928,13.615,1.035c9.443,0.228,18.91-0.501,28.181-2.343
c9.291-1.849,18.74-4.878,26.695-10.129c5.561-3.671,11.321-9.269,11.704-16.369c0.22-4.076,2.596-66.386,2.953-73.011
c0.086-1.608,0.082-3.254,0.26-4.856c-0.1-0.006-0.197-0.012-0.297-0.017C271.826,221.041,271.953,221.044,272.025,221.045
L272.025,221.045z"/>
<g>
<radialGradient id="SVGID_2_" cx="227.0781" cy="-1.4951" r="113.4384" gradientTransform="matrix(1 0 0 -1 -96 195)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</radialGradient>
<path fill="url(#SVGID_2_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M205.559,195.945c8.189,0,16.043,0.558,23.282,1.571c7.312,1.024,14.066,2.525,19.938,4.407
c5.982,1.918,11.097,4.245,14.967,6.892c3.967,2.709,6.65,5.767,7.611,9.064c0.99,3.4,0.062,6.738-2.534,9.861
c-2.667,3.207-7.079,6.172-12.935,8.723c-5.98,2.602-13.418,4.751-21.931,6.262c-8.615,1.522-18.237,2.375-28.399,2.375
c-10.165,0-19.786-0.853-28.4-2.375c-8.511-1.511-15.948-3.66-21.928-6.262c-5.855-2.551-10.27-5.516-12.937-8.723
c-2.595-3.123-3.522-6.461-2.533-9.861c0.96-3.299,3.645-6.355,7.611-9.064c3.869-2.646,8.984-4.974,14.966-6.892
c5.874-1.882,12.627-3.382,19.939-4.407C189.517,196.503,197.369,195.945,205.559,195.945z"/>
</g>
</g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="205.5615" y1="134.5928" x2="205.5615" y2="253.6306">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon fill="url(#SVGID_3_)" points="223.498,169.696 223.498,113.482 187.625,113.482 187.625,169.696 159.627,169.696
205.562,215.631 251.496,169.696 "/>
<polygon fill="#94AEBD" points="243.365,87.928 168.416,87.928 139.927,139.646 271.197,139.646 "/>
<rect x="187.626" y="35.08" fill="#86BF40" width="35.872" height="78.404"/>
<path fill="#424242" d="M281.246,48.863c0,1.99-1.615,3.604-3.604,3.604H133.482c-1.991,0-3.604-1.614-3.604-3.604V9.22
c0-1.991,1.613-3.604,3.604-3.604h144.161c1.987,0,3.604,1.614,3.604,3.604V48.863z"/>
<text transform="matrix(1 0 0 1 164.5 259)" font-family="'Frutiger-BoldCn'" font-size="11">CUSTOMER (</text>
<text transform="matrix(1 0 0 1 164.5 270)" font-family="'Frutiger-BoldCn'" font-size="11">ID BIGINT,</text>
<text transform="matrix(1 0 0 1 164.5 281)" font-family="'Frutiger-BoldCn'" font-size="11">NAME VARCHAR,</text>
<text transform="matrix(1 0 0 1 164.5 292)" font-family="'Frutiger-BoldCn'" font-size="11">...</text>
<text transform="matrix(1 0 0 1 164.5 303)" font-family="'Frutiger-BoldCn'" font-size="11">TENANT_ID VARCHAR</text>
<text transform="matrix(1 0 0 1 164.5 314)" font-family="'Frutiger-BoldCn'" font-size="11">)</text>
<text transform="matrix(1 0 0 1 147.9751 38.0801)" fill="#FFFFFF" font-family="'Frutiger-BoldCn'" font-size="24">Application</text>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="205.5605" y1="99.2612" x2="205.5605" y2="185.5127">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<rect x="187.625" y="110.511" fill="url(#SVGID_4_)" width="35.871" height="29.135"/>
</svg>

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,126 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="400px" height="400px" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="326.6055" y1="-142.313" x2="459.5439" y2="-142.313" gradientTransform="matrix(1 0 0 -1 -96 195)">
<stop offset="0" style="stop-color:#F3D99F"/>
<stop offset="0.459" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</linearGradient>
<path fill="url(#SVGID_1_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M363.54,283.952c-0.175-0.011-0.401-0.021-0.595-0.032c-0.039,0.734-0.176,1.463-0.389,2.166c-0.063,0.216-0.14,0.426-0.216,0.637
c-0.063,0.18-0.14,0.357-0.216,0.534c0.021,0.048,0.002,0-0.096,0.21s-0.204,0.42-0.312,0.624
c-0.251,0.463-0.529,0.913-0.832,1.345c-0.506,0.717-1.074,1.391-1.683,2.021c-0.772,0.804-1.611,1.552-2.494,2.231
c-0.474,0.363-0.952,0.719-1.442,1.061c-0.351,0.245-0.709,0.482-1.068,0.713c-0.324,0.209-0.395,0.25-0.643,0.4
c-0.387,0.238-0.777,0.468-1.172,0.69c-0.574,0.327-1.152,0.644-1.736,0.944c-1.299,0.673-2.633,1.285-3.979,1.857
c-2.722,1.148-5.508,2.107-8.334,2.957c-4.576,1.369-9.243,2.381-13.949,3.192c-12.858,2.218-26.088,2.678-39.098,1.81
c-12.298-0.82-24.896-2.781-36.397-7.385c-4.017-1.605-7.935-3.549-11.379-6.191c-1.337-1.025-2.586-2.188-3.645-3.502
c-0.54-0.672-1.026-1.385-1.436-2.142c-0.217-0.403-0.41-0.817-0.578-1.243c-0.108-0.274-0.135-0.934-0.531-0.679
c0.059-0.049,0.136-0.103,0.203-0.147c0.08-0.057-0.098-0.535-0.121-0.644c-0.107-0.481-0.176-0.972-0.203-1.462
c-0.698,0.038-0.602-0.021-0.571,0.578c0.035,0.648,0.07,1.299,0.104,1.949c0.133,2.438,0.264,4.875,0.394,7.312
c0.397,7.426,2.524,65.108,2.629,67.018c0.155,2.861,0.823,5.538,2.287,8.043c1.826,3.122,4.448,5.607,7.28,7.814
c1.484,1.16,3.099,2.174,4.729,3.117c0.844,0.488,1.708,0.938,2.568,1.396c0.369,0.197,0.75,0.372,1.126,0.557
c0.287,0.143,0.295,0.146,0.601,0.291c0.434,0.205,0.87,0.407,1.309,0.599c0.558,0.24,1.111,0.486,1.672,0.717
c1.214,0.495,2.436,0.958,3.665,1.405c2.477,0.897,5.012,1.623,7.556,2.308c0.098,0.025,0.098,0.025,0.46,0.119
c0.388,0.098,0.775,0.195,1.162,0.288c0.497,0.12,0.992,0.234,1.488,0.347c0.903,0.206,1.811,0.395,2.717,0.579
c2.567,0.524,5.163,0.938,7.761,1.275c4.52,0.589,9.062,0.93,13.616,1.038c9.442,0.227,18.911-0.501,28.181-2.345
c9.293-1.848,18.741-4.876,26.694-10.128c5.562-3.671,11.323-9.27,11.705-16.369c0.219-4.079,2.597-66.387,2.952-73.012
c0.086-1.61,0.084-3.254,0.261-4.856c-0.101-0.006-0.196-0.011-0.297-0.017C363.338,283.948,363.466,283.95,363.54,283.952
L363.54,283.952z"/>
<g>
<radialGradient id="SVGID_2_" cx="318.5908" cy="-64.4004" r="113.4382" gradientTransform="matrix(1 0 0 -1 -96 195)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</radialGradient>
<path fill="url(#SVGID_2_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M297.07,258.852c8.191,0,16.044,0.559,23.283,1.57c7.312,1.023,14.064,2.525,19.939,4.407c5.979,1.918,11.096,4.245,14.964,6.89
c3.968,2.709,6.65,5.768,7.612,9.067c0.99,3.399,0.061,6.737-2.535,9.858c-2.666,3.207-7.078,6.174-12.934,8.725
c-5.98,2.604-13.418,4.751-21.93,6.26c-8.615,1.523-18.236,2.377-28.4,2.377c-10.162,0-19.783-0.854-28.399-2.377
c-8.513-1.509-15.95-3.656-21.93-6.26c-5.854-2.551-10.269-5.518-12.935-8.725c-2.597-3.121-3.523-6.459-2.535-9.858
c0.961-3.302,3.646-6.358,7.611-9.067c3.87-2.645,8.984-4.972,14.965-6.89c5.875-1.882,12.629-3.384,19.94-4.407
C281.027,259.409,288.882,258.852,297.07,258.852z"/>
</g>
</g>
<rect x="180.977" y="94.169" fill="#86BF40" width="35.871" height="70.285"/>
<g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="130.9292" y1="-142.313" x2="263.8682" y2="-142.313" gradientTransform="matrix(1 0 0 -1 -96 195)">
<stop offset="0" style="stop-color:#F3D99F"/>
<stop offset="0.459" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</linearGradient>
<path fill="url(#SVGID_3_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M167.86,283.952c-0.174-0.011-0.401-0.021-0.594-0.032c-0.037,0.734-0.174,1.463-0.386,2.166c-0.063,0.216-0.138,0.426-0.216,0.637
c-0.065,0.18-0.139,0.357-0.216,0.534c0.022,0.048,0,0-0.096,0.21c-0.099,0.21-0.204,0.42-0.314,0.624
c-0.249,0.463-0.527,0.913-0.831,1.345c-0.503,0.717-1.075,1.391-1.682,2.021c-0.773,0.804-1.611,1.552-2.494,2.231
c-0.474,0.363-0.95,0.719-1.44,1.061c-0.352,0.245-0.709,0.482-1.07,0.713c-0.324,0.209-0.394,0.25-0.643,0.4
c-0.386,0.238-0.778,0.468-1.173,0.69c-0.571,0.327-1.149,0.644-1.734,0.944c-1.3,0.673-2.634,1.285-3.98,1.857
c-2.72,1.148-5.509,2.107-8.336,2.957c-4.574,1.369-9.244,2.381-13.947,3.192c-12.862,2.218-26.089,2.678-39.097,1.81
c-12.3-0.82-24.897-2.781-36.397-7.385c-4.019-1.605-7.936-3.549-11.38-6.191c-1.336-1.025-2.585-2.188-3.645-3.502
c-0.539-0.672-1.026-1.385-1.433-2.142c-0.218-0.403-0.41-0.817-0.579-1.243c-0.108-0.274-0.136-0.934-0.532-0.679
c0.059-0.049,0.136-0.103,0.203-0.147c0.08-0.057-0.097-0.535-0.121-0.644c-0.107-0.481-0.178-0.972-0.203-1.462
c-0.7,0.038-0.604-0.021-0.571,0.578c0.035,0.648,0.07,1.299,0.105,1.949c0.13,2.438,0.261,4.875,0.392,7.312
c0.399,7.426,2.527,65.108,2.63,67.018c0.153,2.861,0.822,5.538,2.285,8.043c1.828,3.122,4.45,5.607,7.281,7.814
c1.486,1.16,3.101,2.174,4.729,3.117c0.845,0.488,1.707,0.938,2.569,1.396c0.37,0.197,0.749,0.372,1.126,0.557
c0.286,0.143,0.293,0.146,0.601,0.291c0.434,0.205,0.869,0.407,1.307,0.599c0.557,0.24,1.113,0.486,1.673,0.717
c1.21,0.495,2.432,0.958,3.663,1.405c2.478,0.897,5.012,1.623,7.556,2.308c0.098,0.025,0.098,0.025,0.46,0.119
c0.387,0.098,0.774,0.195,1.164,0.288c0.495,0.12,0.99,0.234,1.487,0.347c0.903,0.206,1.809,0.395,2.717,0.579
c2.568,0.524,5.162,0.938,7.761,1.275c4.515,0.589,9.063,0.93,13.615,1.038c9.444,0.227,18.911-0.501,28.18-2.345
c9.292-1.848,18.741-4.876,26.696-10.128c5.559-3.671,11.323-9.27,11.705-16.369c0.219-4.079,2.595-66.387,2.953-73.012
c0.086-1.61,0.083-3.254,0.26-4.856c-0.1-0.006-0.198-0.011-0.296-0.017C167.661,283.948,167.788,283.95,167.86,283.952
L167.86,283.952z"/>
<g>
<radialGradient id="SVGID_4_" cx="122.9121" cy="-64.4004" r="113.4382" gradientTransform="matrix(1 0 0 -1 -96 195)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#FAF8ED"/>
<stop offset="0.9836" style="stop-color:#E3A835"/>
</radialGradient>
<path fill="url(#SVGID_4_)" stroke="#AB710A" stroke-width="1.2013" stroke-linejoin="round" stroke-miterlimit="10" d="
M101.394,258.852c8.19,0,16.042,0.559,23.281,1.57c7.312,1.023,14.065,2.525,19.938,4.407c5.983,1.918,11.097,4.245,14.968,6.89
c3.966,2.709,6.65,5.768,7.611,9.067c0.989,3.399,0.062,6.737-2.534,9.858c-2.667,3.207-7.08,6.174-12.937,8.725
c-5.98,2.604-13.417,4.751-21.928,6.26c-8.616,1.523-18.238,2.377-28.4,2.377c-10.164,0-19.787-0.854-28.401-2.377
c-8.511-1.509-15.948-3.656-21.928-6.26c-5.855-2.551-10.269-5.518-12.935-8.725c-2.597-3.121-3.523-6.459-2.535-9.858
c0.961-3.302,3.644-6.358,7.611-9.067c3.87-2.645,8.984-4.972,14.965-6.89c5.875-1.882,12.628-3.384,19.939-4.407
C85.352,259.409,93.204,258.852,101.394,258.852z"/>
</g>
</g>
<polygon fill="#94AEBD" points="236.716,71.166 161.766,71.166 133.278,122.885 264.547,122.885 "/>
<polygon fill="#86BF40" points="315.436,232.604 315.436,176.39 315.436,137.82 82.388,137.82 82.388,176.39 82.388,232.604
54.391,232.605 100.325,278.538 146.258,232.604 118.259,232.604 118.259,176.39 118.259,173.692 279.562,173.692 279.562,176.39
279.562,232.604 251.566,232.605 297.501,278.538 343.436,232.604 "/>
<rect x="180.977" y="38.9" fill="#86BF40" width="35.871" height="54.85"/>
<path fill="#424242" d="M274.598,49.364c0,1.989-1.615,3.603-3.604,3.603h-144.16c-1.99,0-3.605-1.614-3.605-3.603V9.72
c0-1.991,1.615-3.604,3.605-3.604h144.16c1.989,0,3.604,1.614,3.604,3.604V49.364z"/>
<text transform="matrix(1 0 0 1 62.5 325.5)" font-family="'Frutiger-BoldCn'" font-size="12">CUSTOMER (</text>
<text transform="matrix(1 0 0 1 62.5 337.9004)" font-family="'Frutiger-BoldCn'" font-size="12">ID BIGINT,</text>
<text transform="matrix(1 0 0 1 62.5 350.2998)" font-family="'Frutiger-BoldCn'" font-size="12">NAME VARCHAR,</text>
<text transform="matrix(1 0 0 1 62.5 362.7002)" font-family="'Frutiger-BoldCn'" font-size="12">...</text>
<text transform="matrix(1 0 0 1 62.5 375.0996)" font-family="'Frutiger-BoldCn'" font-size="12">)</text>
<text transform="matrix(1 0 0 1 264.5 325.5)" font-family="'Frutiger-BoldCn'" font-size="12">CUSTOMER (</text>
<text transform="matrix(1 0 0 1 264.5 337.9004)" font-family="'Frutiger-BoldCn'" font-size="12">ID BIGINT,</text>
<text transform="matrix(1 0 0 1 264.5 350.2998)" font-family="'Frutiger-BoldCn'" font-size="12">NAME VARCHAR,</text>
<text transform="matrix(1 0 0 1 264.5 362.7002)" font-family="'Frutiger-BoldCn'" font-size="12">...</text>
<text transform="matrix(1 0 0 1 264.5 375.0996)" font-family="'Frutiger-BoldCn'" font-size="12">)</text>
<text transform="matrix(1 0 0 1 141.6475 38.5801)" fill="#FFFFFF" font-family="'Frutiger-BoldCn'" font-size="24">Application</text>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="297.501" y1="197.5" x2="297.501" y2="316.5378">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon fill="url(#SVGID_5_)" points="315.438,232.604 315.438,176.389 279.564,176.389 279.564,232.604 251.566,232.604
297.502,278.538 343.436,232.604 "/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="100.3247" y1="197.5" x2="100.3247" y2="316.5378">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<polygon fill="url(#SVGID_6_)" points="118.259,232.604 118.259,176.389 82.387,176.389 82.387,232.604 54.391,232.604
100.325,278.538 146.258,232.604 "/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="198.9121" y1="82.5" x2="198.9121" y2="168.7514">
<stop offset="0" style="stop-color:#86BF40"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<rect x="180.977" y="93.75" fill="url(#SVGID_7_)" width="35.871" height="29.135"/>
</svg>

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,420 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>OSGi</title>
<abstract>
<para>
The Open Services Gateway initiative (OSGi) specification describes a dynamic, modularized system. "Bundles"
(components) can be installed, activated, deactivated, and uninstalled during runtime, without requiring
a system restart. OSGi frameworks manage bundles' dependencies, packages, and classes. The framework
is also in charge of ClassLoading, managing visibility of packages between bundles. Further, service
registry and discovery is provided through a "whiteboard" pattern.
</para>
<para>
OSGi environments present numerous, unique challenges. Most notably, the dynamic nature of available
bundles during runtime can require significant architectural considerations. Also,
architectures must allow the OSGi-specific ClassLoading and service registration/discovery.
</para>
</abstract>
</info>
<section>
<title>OSGi Specification and Environment</title>
<para>
Hibernate targets the OSGi 4.3 spec or later. It was necessary to start with 4.3, over 4.2, due to our
dependency on OSGi's <literal>BundleWiring</literal> for entity/mapping scanning.
</para>
<para>
Hibernate supports three types of configurations within OSGi.
<orderedlist>
<listitem>
<firstterm>Container-Managed JPA</firstterm>: <xref linkend="osgi-managed-jpa"/>
</listitem>
<listitem>
<firstterm>Unmanaged JPA</firstterm>: <xref linkend="osgi-unmanaged-jpa"/>
</listitem>
<listitem>
<firstterm>Unmanaged Native</firstterm>: <xref linkend="osgi-unmanaged-native"/>
</listitem>
</orderedlist>
</para>
</section>
<section>
<title>hibernate-osgi</title>
<para>
Rather than embed OSGi capabilities into hibernate-core, hibernate-entitymanager, and sub-modules,
hibernate-osgi was created. It's purposefully separated, isolating all OSGi dependencies. It provides an
OSGi-specific ClassLoader (aggregates the container's CL with core and entitymanager CLs), JPA persistence
provider, SF/EMF bootstrapping, entities/mappings scanner, and service management.
</para>
</section>
<section xml:id="osgi-managed-jpa">
<title>Container-Managed JPA</title>
<para>
The Enterprise OSGi specification includes container-managed JPA. The container is responsible for
discovering persistence units and creating the <literal>EntityManagerFactory</literal> (one EMF per PU).
It uses the JPA provider (hibernate-osgi) that has registered itself with the OSGi
<literal>PersistenceProvider</literal> service.
</para>
<para>
Quickstart tutorial project, demonstrating a container-managed JPA client bundle:
<link xl:href="https://github.com/hibernate/hibernate-orm/tree/master/documentation/src/main/docbook/quickstart/tutorials/osgi/managed-jpa">managed-jpa</link>
</para>
<section>
<title>Client bundle imports</title>
<para>
Your client bundle's manifest will need to import, at a minimum,
<itemizedlist>
<listitem>
<literal>javax.persistence</literal>
</listitem>
<listitem>
<para>
<literal>org.hibernate.proxy</literal> and <literal>javassist.util.proxy</literal>, due to
Hibernate's ability to return proxies for lazy initialization (Javassist enhancement
occurs on the entity's ClassLoader during runtime).
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>JPA 2.1</title>
<para>
No Enterprise OSGi JPA container currently supports JPA 2.1 (the spec is not yet released). For
testing, the managed-jpa example makes use of
<link xl:href="https://github.com/brmeyer/aries/tree/jpa21">Brett's fork of Aries</link>. To work
with Hibernate 4.3, clone the fork and build Aries JPA.
</para>
</section>
<section>
<title>DataSource</title>
<para>
Typical Enterprise OSGi JPA usage includes a DataSource installed in the container. The client
bundle's <literal>persistence.xml</literal> uses the DataSource through JNDI. For an example,
see the QuickStart's DataSource:
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/datasource-h2.xml">datasource-h2.xml</link>
The DataSource is then called out in
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/managed-jpa/src/main/resources/META-INF/persistence.xml">
persistence.xml's</link> <literal>jta-data-source</literal>.
</para>
</section>
<section>
<title>Bundle Ordering</title>
<para>
Hibernate currently requires fairly specific bundle activation ordering. See the managed-jpa
QuickStart's
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/managed-jpa/features.xml">features.xml</link>
for the best supported sequence.
</para>
</section>
<section>
<title>Obtaining an EntityManger</title>
<para>
The easiest, and most supported, method of obtaining an <literal>EntityManager</literal> utilizes OSGi's
<literal>blueprint.xml</literal>. The container takes the name of your persistence unit, then injects
an <literal>EntityManager</literal> instance into your given bean attribute. See the
<literal>dpService</literal> bean in the managed-jpa QuickStart's
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/managed-jpa/src/main/resources/OSGI-INF/blueprint/blueprint.xml">blueprint.xml</link>
for an example.
</para>
</section>
</section>
<section xml:id="osgi-unmanaged-jpa">
<title>Unmanaged JPA</title>
<para>
Hibernate also supports the use of JPA through hibernate-entitymanager, unmanaged by the OSGi
container. The client bundle is responsible for managing the EntityManagerFactory and EntityManagers.
</para>
<para>
Quickstart tutorial project, demonstrating an unmanaged JPA client bundle:
<link xl:href="https://github.com/hibernate/hibernate-orm/tree/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-jpa">unmanaged-jpa</link>
</para>
<section>
<title>Client bundle imports</title>
<para>
Your client bundle's manifest will need to import, at a minimum,
<itemizedlist>
<listitem>
<literal>javax.persistence</literal>
</listitem>
<listitem>
<para>
<literal>org.hibernate.proxy</literal> and <literal>javassist.util.proxy</literal>, due to
Hibernate's ability to return proxies for lazy initialization (Javassist enhancement
occurs on the entity's ClassLoader during runtime)
</para>
</listitem>
<listitem>
<para>
JDBC driver package (example: <literal>org.h2</literal>)
</para>
</listitem>
<listitem>
<para>
<literal>org.osgi.framework</literal>, necessary to discover the EMF (described below)
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Bundle Ordering</title>
<para>
Hibernate currently requires fairly specific bundle activation ordering. See the unmanaged-jpa
QuickStart's
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-jpa/features.xml">features.xml</link>
for the best supported sequence.
</para>
</section>
<section>
<title>Obtaining an EntityMangerFactory</title>
<para>
hibernate-osgi registers an OSGi service, using the JPA <literal>PersistenceProvider</literal> interface
name, that bootstraps and creates an <literal>EntityManagerFactory</literal> specific for OSGi
environments. It is VITAL that your EMF be obtained through the service, rather than creating it
manually. The service handles the OSGi ClassLoader, discovered extension points, scanning, etc. Manually
creating an <literal>EntityManagerFactory</literal> is guaranteed to NOT work during runtime!
</para>
<para>
For an example on how to discover and use the service, see the unmanaged-jpa
QuickStart's
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-jpa/src/main/java/org/hibernate/osgitest/HibernateUtil.java">HibernateUtil.java</link>.
</para>
</section>
</section>
<section xml:id="osgi-unmanaged-native">
<title>Unmanaged Native</title>
<para>
Native Hibernate use is also supported. The client bundle is responsible for managing the
SessionFactory and Sessions.
</para>
<para>
Quickstart tutorial project, demonstrating an unmanaged native client bundle:
<link xl:href="https://github.com/hibernate/hibernate-orm/tree/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-native">unmanaged-native</link>
</para>
<section>
<title>Client bundle imports</title>
<para>
Your client bundle's manifest will need to import, at a minimum,
<itemizedlist>
<listitem>
<literal>javax.persistence</literal>
</listitem>
<listitem>
<para>
<literal>org.hibernate.proxy</literal> and <literal>javassist.util.proxy</literal>, due to
Hibernate's ability to return proxies for lazy initialization (Javassist enhancement
occurs on the entity's ClassLoader during runtime)
</para>
</listitem>
<listitem>
<para>
JDBC driver package (example: <literal>org.h2</literal>)
</para>
</listitem>
<listitem>
<para>
<literal>org.osgi.framework</literal>, necessary to discover the SF (described below)
</para>
</listitem>
<listitem>
<para>
<literal>org.hibernate.*</literal> packages, as necessary (ex: cfg, criterion, service, etc.)
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Bundle Ordering</title>
<para>
Hibernate currently requires fairly specific bundle activation ordering. See the unmanaged-native
QuickStart's
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-native/features.xml">features.xml</link>
for the best supported sequence.
</para>
</section>
<section>
<title>Obtaining an SessionFactory</title>
<para>
hibernate-osgi registers an OSGi service, using the <literal>SessionFactory</literal> interface
name, that bootstraps and creates an <literal>SessionFactory</literal> specific for OSGi
environments. It is VITAL that your SF be obtained through the service, rather than creating it
manually. The service handles the OSGi ClassLoader, discovered extension points, scanning, etc. Manually
creating an <literal>SessionFactory</literal> is guaranteed to NOT work during runtime!
</para>
<para>
For an example on how to discover and use the service, see the unmanaged-native
QuickStart's
<link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-native/src/main/java/org/hibernate/osgitest/HibernateUtil.java">HibernateUtil.java</link>.
</para>
</section>
</section>
<section>
<title>Optional Modules</title>
<para>
The <link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-native">unmanaged-native</link>
QuickStart project demonstrates the use of optional Hibernate modules. Each module adds additional
dependency bundles that must first be activated
(see <link xl:href="https://github.com/hibernate/hibernate-orm/blob/master/documentation/src/main/docbook/quickstart/tutorials/osgi/unmanaged-native/features.xml">features.xml</link>).
As of ORM 4.2, Envers is fully supported. Support for C3P0, Proxool, EhCache, and Infinispan were added in
4.3, however none of their 3rd party libraries currently work in OSGi (lots of ClassLoader problems, etc.).
We're tracking the issues in JIRA.
</para>
</section>
<section>
<title>Extension Points</title>
<para>
Multiple contracts exist to allow applications to integrate with and extend Hibernate capabilities. Most
apps utilize JDK services to provide their implementations. hibernate-osgi supports the same
extensions through OSGi services. Implement and register them in any of the three configurations.
hibernate-osgi will discover and integrate them during EMF/SF bootstrapping. Supported extension points
are as follows. The specified interface should be used during service registration.
<itemizedlist>
<listitem>
<literal>org.hibernate.integrator.spi.Integrator</literal> (as of 4.2)
</listitem>
<listitem>
<literal>org.hibernate.boot.registry.selector.StrategyRegistrationProvider</literal> (as of 4.3)
</listitem>
<listitem>
<literal>org.hibernate.boot.model.TypeContributor</literal> (as of 4.3)
</listitem>
<listitem>
JTA's <literal>javax.transaction.TransactionManager</literal> and
<literal>javax.transaction.UserTransaction</literal> (as of 4.2), however these are typically
provided by the OSGi container.
</listitem>
</itemizedlist>
</para>
<para>
The easiest way to register extension point implementations is through a <literal>blueprint.xml</literal>
file. Add <literal>OSGI-INF/blueprint/blueprint.xml</literal> to your classpath. Envers' blueprint
is a great example:
</para>
<example>
<title>Example extension point registrations in blueprint.xml</title>
<programlisting role="XML"><xi:include href="extras/extension_point_blueprint.xml" parse="text"/></programlisting>
</example>
<para>
Extension points can also be registered programmatically with
<literal>BundleContext#registerService</literal>, typically within your
<literal>BundleActivator#start</literal>.
</para>
</section>
<section>
<title>Caveats</title>
<itemizedlist>
<listitem>
<para>
Technically, multiple persistence units are supported by Enterprise OSGi JPA and unmanaged
Hibernate JPA use. However, we cannot currently support this in OSGi. In Hibernate 4, only one
instance of the OSGi-specific ClassLoader is used per Hibernate bundle, mainly due to heavy use of
static TCCL utilities. We hope to support one OSGi ClassLoader per persistence unit in
Hibernate 5.
</para>
</listitem>
<listitem>
<para>
Scanning is supported to find non-explicitly listed entities and mappings. However, they MUST be
in the same bundle as your persistence unit (fairly typical anyway). Our OSGi ClassLoader only
considers the "requesting bundle" (hence the requirement on using services to create EMF/SF),
rather than attempting to scan all available bundles. This is primarily for versioning
considerations, collision protections, etc.
</para>
</listitem>
<listitem>
<para>
Some containers (ex: Aries) always return true for
<literal>PersistenceUnitInfo#excludeUnlistedClasses</literal>,
even if your persistence.xml explicitly has <literal>exclude-unlisted-classes</literal> set
to <literal>false</literal>. They claim it's to protect JPA providers from having to implement
scanning ("we handle it for you"), even though we still want to support it in many cases. The work
around is to set <literal>hibernate.archive.autodetection</literal> to, for example,
<literal>hbm,class</literal>. This tells hibernate to ignore the excludeUnlistedClasses value and
scan for <literal>*.hbm.xml</literal> and entities regardless.
</para>
</listitem>
<listitem>
<para>
Scanning does not currently support annotated packages on <literal>package-info.java</literal>.
</para>
</listitem>
<listitem>
<para>
Currently, Hibernate OSGi is primarily tested using Apache Karaf and Apache Aries JPA. Additional
testing is needed with Equinox, Gemini, and other container providers.
</para>
</listitem>
<listitem>
<para>
Hibernate ORM has many dependencies that do not currently provide OSGi manifests.
The QuickStart tutorials make heavy use of 3rd party bundles (SpringSource, ServiceMix) or the
<literal>wrap:...</literal> operator.
</para>
</listitem>
<listitem>
<para>
As previously mentioned, bundle activation is currently order specific. See the QuickStart
tutorials' <literal>features.xml</literal> for example sequences.
</para>
</listitem>
<listitem>
<para>
No Enterprise OSGi JPA container currently supports JPA 2.1 (the spec is not yet released). For
testing, the managed-jpa example makes use of
<link xl:href="https://github.com/brmeyer/aries/tree/jpa21">Brett's fork of Aries</link>. To work
with Hibernate 4.3, clone the fork and build Aries JPA.
</para>
</listitem>
</itemizedlist>
</section>
</chapter>

View File

@ -1,17 +0,0 @@
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<blueprint default-activation="eager"
xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<bean id="integrator" class="org.hibernate.envers.boot.internal.EnversIntegrator" />
<service ref="integrator" interface="org.hibernate.integrator.spi.Integrator" />
<bean id="typeContributor"
class="org.hibernate.envers.boot.internal.TypeContributorImpl" />
<service ref="typeContributor" interface="org.hibernate.boot.model.TypeContributor" />
</blueprint>

View File

@ -1,356 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude">
<info>
<title>Persistence Contexts</title>
</info>
<para>
Both the <interfacename>org.hibernate.Session</interfacename> API and
<interfacename>javax.persistence.EntityManager</interfacename> API represent a context for dealing with
persistent data. This concept is called a <literal>persistence context</literal>. Persistent data has a
state in relation to both a persistence context and the underlying database.
</para>
<itemizedlist>
<title>Entity states</title>
<listitem>
<para>
<literal>new</literal>, or <literal>transient</literal> - the entity has just been instantiated and is
not associated with a persistence context. It has no persistent representation in the database and no
identifier value has been assigned.
</para>
</listitem>
<listitem>
<para>
<literal>managed</literal>, or <literal>persistent</literal> - the entity has an associated identifier
and is associated with a persistence context.
</para>
</listitem>
<listitem>
<para>
<literal>detached</literal> - the entity has an associated identifier, but is no longer associated with
a persistence context (usually because the persistence context was closed or the instance was evicted
from the context)
</para>
</listitem>
<listitem>
<para>
<literal>removed</literal> - the entity has an associated identifier and is associated with a persistence
context, however it is scheduled for removal from the database.
</para>
</listitem>
</itemizedlist>
<!-- todo : need a "see also" link to cascading chapter -->
<para>
In Hibernate native APIs, the persistence context is defined as the
<interfacename>org.hibernate.Session</interfacename>. In JPA, the persistence context is defined by
<interfacename>javax.persistence.EntityManager</interfacename>. Much of the
<interfacename>org.hibernate.Session</interfacename> and
<interfacename>javax.persistence.EntityManager</interfacename> methods deal with moving entities between these
states.
</para>
<section>
<title>Making entities persistent</title>
<para>
Once you've created a new entity instance (using the standard <literal>new</literal> operator) it is in
<literal>new</literal> state. You can make it persistent by associating it to either a
<interfacename>org.hibernate.Session</interfacename> or
<interfacename>javax.persistence.EntityManager</interfacename>
</para>
<example>
<title>Example of making an entity persistent</title>
<programlisting role="JAVA"><xi:include href="extras/MakingPersistentWithSession.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/MakingPersistentWithEM.java" parse="text"/></programlisting>
</example>
<para>
<interfacename>org.hibernate.Session</interfacename> also has a method named <methodname>persist</methodname>
which follows the exact semantic defined in the JPA specification for the <methodname>persist</methodname>
method. It is this method on <interfacename>org.hibernate.Session</interfacename> to which the
Hibernate <interfacename>javax.persistence.EntityManager</interfacename> implementation delegates.
</para>
<para>
If the <classname>DomesticCat</classname> entity type has a generated identifier, the value is associated
to the instance when the <methodname>save</methodname> or <methodname>persist</methodname> is called. If the
identifier is not automatically generated, the application-assigned (usually natural) key value has to be
set on the instance before <methodname>save</methodname> or <methodname>persist</methodname> is called.
</para>
</section>
<section>
<title>Deleting entities</title>
<para>
Entities can also be deleted.
</para>
<example>
<title>Example of deleting an entity</title>
<programlisting role="JAVA"><xi:include href="extras/DeletingWithSession.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/DeletingWithEM.java" parse="text"/></programlisting>
</example>
<para>
It is important to note that Hibernate itself can handle deleting detached state. JPA, however, disallows
it. The implication here is that the entity instance passed to the
<interfacename>org.hibernate.Session</interfacename> <methodname>delete</methodname> method can be either
in managed or detached state, while the entity instance passed to <methodname>remove</methodname> on
<interfacename>javax.persistence.EntityManager</interfacename> must be in managed state.
</para>
</section>
<section>
<title>Obtain an entity reference without initializing its data</title>
<para>
Sometimes referred to as lazy loading, the ability to obtain a reference to an entity without having to
load its data is hugely important. The most common case being the need to create an association between
an entity and another, existing entity.
</para>
<example>
<title>Example of obtaining an entity reference without initializing its data</title>
<programlisting role="JAVA"><xi:include href="extras/GetReferenceWithSession.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/GetReferenceWithEM.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
</example>
<para>
The above works on the assumption that the entity is defined to allow lazy loading, generally through
use of runtime proxies. For more information see <xref linkend="devguide-mappingEntities"/>. In both
cases an exception will be thrown later if the given entity does not refer to actual database state if and
when the application attempts to use the returned proxy in any way that requires access to its data.
</para>
</section>
<section>
<title>Obtain an entity with its data initialized</title>
<para>
It is also quite common to want to obtain an entity along with with its data, for display for example.
</para>
<example>
<title>Example of obtaining an entity reference with its data initialized</title>
<programlisting role="JAVA"><xi:include href="extras/LoadWithSession.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/LoadWithEM.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
</example>
<para>
In both cases null is returned if no matching database row was found.
</para>
</section>
<section>
<title>Obtain an entity by natural-id</title>
<para>
In addition to allowing to load by identifier, Hibernate allows applications to load by declared
natural identifier.
</para>
<example>
<title>Example of simple natural-id access</title>
<programlisting role="JAVA"><xi:include href="extras/SimpleNaturalIdLoading.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
</example>
<example>
<title>Example of natural-id access</title>
<programlisting role="JAVA"><xi:include href="extras/NaturalIdLoading.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
</example>
<para>
Just like we saw above, access entity data by natural id allows both the <methodname>load</methodname>
and <methodname>getReference</methodname> forms, with the same semantics.
</para>
<para>
Accessing persistent data by identifier and by natural-id is consistent in the Hibernate API. Each defines
the same 2 data access methods:
</para>
<variablelist>
<varlistentry>
<term><methodname>getReference</methodname></term>
<listitem>
<para>
Should be used in cases where the identifier is assumed to exist, where non-existence would be
an actual error. Should never be used to test existence. That is because this method will
prefer to create and return a proxy if the data is not already associated with the Session
rather than hit the database. The quintessential use-case for using this method is to create
foreign-key based associations.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><methodname>load</methodname></term>
<listitem>
<para>
Will return the persistent data associated with the given identifier value or null if that
identifier does not exist.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
In addition to those 2 methods, each also defines the method <methodname>with</methodname> accepting
a <interfacename>org.hibernate.LockOptions</interfacename> argument. Locking is discussed in a separate
chapter.
</para>
</section>
<section>
<title>Refresh entity state</title>
<para>
You can reload an entity instance and it's collections at any time.
</para>
<example>
<title>Example of refreshing entity state</title>
<programlisting role="JAVA"><xi:include href="extras/RefreshWithSession.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/RefreshWithEM.java" xmlns:xi="http://www.w3.org/2001/XInclude" parse="text"/></programlisting>
</example>
<para>
One case where this is useful is when it is known that the database state has changed since the data was
read. Refreshing allows the current database state to be pulled into the entity instance and the
persistence context.
</para>
<para>
Another case where this might be useful is when database triggers are used to initialize some of the
properties of the entity. Note that only the entity instance and its collections are refreshed unless you
specify <literal>REFRESH</literal> as a cascade style of any associations. However, please note that
Hibernate has the capability to handle this automatically through its notion of generated properties.
See <xref linkend="devguide-mappingEntities"/> for information.
</para>
</section>
<section>
<title>Modifying managed/persistent state</title>
<para>
Entities in managed/persistent state may be manipulated by the application and any changes will be
automatically detected and persisted when the persistence context is flushed. There is no need to call a
particular method to make your modifications persistent.
</para>
<example>
<title>Example of modifying managed state</title>
<programlisting role="JAVA"><xi:include href="extras/ManagedUpdateWithSession.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/ManagedUpdateWithEM.java" parse="text"/></programlisting>
</example>
</section>
<section>
<title>Working with detached data</title>
<para>
Detachment is the process of working with data outside the scope of any persistence context. Data becomes
detached in a number of ways. Once the persistence context is closed, all data that was associated with it
becomes detached. Clearing the persistence context has the same effect. Evicting a particular entity
from the persistence context makes it detached. And finally, serialization will make the deserialized form
be detached (the original instance is still managed).
</para>
<para>
Detached data can still be manipulated, however the persistence context will no longer automatically know
about these modification and the application will need to intervene to make the changes persistent.
</para>
<section>
<title>Reattaching detached data</title>
<para>
Reattachment is the process of taking an incoming entity instance that is in detached state
and re-associating it with the current persistence context.
</para>
<important>
<para>
JPA does not provide for this model. This is only available through Hibernate
<interfacename>org.hibernate.Session</interfacename>.
</para>
</important>
<example>
<title>Example of reattaching a detached entity</title>
<programlisting role="JAVA"><xi:include href="extras/ReattachingWithSession1.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/ReattachingWithSession2.java" parse="text"/></programlisting>
</example>
<para>
The method name <methodname>update</methodname> is a bit misleading here. It does not mean that an
<literal>SQL</literal> <literal>UPDATE</literal> is immediately performed. It does, however, mean that
an <literal>SQL</literal> <literal>UPDATE</literal> will be performed when the persistence context is
flushed since Hibernate does not know its previous state against which to compare for changes. Unless
the entity is mapped with <literal>select-before-update</literal>, in which case Hibernate will
pull the current state from the database and see if an update is needed.
</para>
<para>
Provided the entity is detached, <methodname>update</methodname> and <methodname>saveOrUpdate</methodname>
operate exactly the same.
</para>
</section>
<section>
<title>Merging detached data</title>
<para>
Merging is the process of taking an incoming entity instance that is in detached state and copying its
data over onto a new instance that is in managed state.
</para>
<example>
<title>Visualizing merge</title>
<programlisting role="JAVA"><xi:include href="extras/VisualizingMerge.java" parse="text"/></programlisting>
</example>
<para>
That is not exactly what happens, but its a good visualization.
</para>
<example>
<title>Example of merging a detached entity</title>
<programlisting role="JAVA"><xi:include href="extras/MergeWithSession.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/MergeWithEM.java" parse="text"/></programlisting>
</example>
</section>
</section>
<section>
<title>Checking persistent state</title>
<para>
An application can verify the state of entities and collections in relation to the persistence context.
</para>
<example>
<title>Examples of verifying managed state</title>
<programlisting role="JAVA"><xi:include href="extras/ContainsWithSession.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/ContainsWithEM.java" parse="text"/></programlisting>
</example>
<example>
<title>Examples of verifying laziness</title>
<programlisting role="JAVA"><xi:include href="extras/CheckingLazinessWithHibernate.java" parse="text"/></programlisting>
<programlisting role="JAVA"><xi:include href="extras/CheckingLazinessWithJPA.java" parse="text"/></programlisting>
</example>
<para>
In JPA there is an alternative means to check laziness using the following
<interfacename>javax.persistence.PersistenceUtil</interfacename> pattern. However, the
<interfacename>javax.persistence.PersistenceUnitUtil</interfacename> is recommended where ever possible
</para>
<example>
<title>Alternative JPA means to verify laziness</title>
<programlisting role="JAVA"><xi:include href="extras/CheckingLazinessWithJPA2.java" parse="text"/></programlisting>
</example>
</section>
<section>
<title>Accessing Hibernate APIs from JPA</title>
<para>
JPA defines an incredibly useful method to allow applications access to the APIs of the underlying provider.
</para>
<example>
<title>Usage of EntityManager.unwrap</title>
<programlisting role="JAVA"><xi:include href="extras/UnwrapWithEM.java" parse="text"/></programlisting>
</example>
</section>
</chapter>

View File

@ -1,9 +0,0 @@
if ( Hibernate.isInitialized( customer.getAddress() ) {
//display address if loaded
}
if ( Hibernate.isInitialized( customer.getOrders()) ) ) {
//display orders if loaded
}
if (Hibernate.isPropertyInitialized( customer, "detailedBio" ) ) {
//display property detailedBio if loaded
}

View File

@ -1,10 +0,0 @@
javax.persistence.PersistenceUnitUtil jpaUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
if ( jpaUtil.isLoaded( customer.getAddress() ) {
//display address if loaded
}
if ( jpaUtil.isLoaded( customer.getOrders()) ) ) {
//display orders if loaded
}
if (jpaUtil.isLoaded( customer, "detailedBio" ) ) {
//display property detailedBio if loaded
}

View File

@ -1,10 +0,0 @@
javax.persistence.PersistenceUtil jpaUtil = javax.persistence.Persistence.getPersistenceUtil();
if ( jpaUtil.isLoaded( customer.getAddress() ) {
//display address if loaded
}
if ( jpaUtil.isLoaded( customer.getOrders()) ) ) {
//display orders if loaded
}
if (jpaUtil.isLoaded(customer, "detailedBio") ) {
//display property detailedBio if loaded
}

View File

@ -1 +0,0 @@
assert entityManager.contains( cat );

View File

@ -1 +0,0 @@
entityManager.remove( fritz );

View File

@ -1,2 +0,0 @@
Book book = new Book();
book.setAuthor( entityManager.getReference( Author.class, authorId ) );

View File

@ -1,2 +0,0 @@
Book book = new Book();
book.setAuthor( session.byId( Author.class ).getReference( authorId ) );

View File

@ -1 +0,0 @@
entityManager.find( Author.class, authorId );

View File

@ -1 +0,0 @@
session.byId( Author.class ).load( authorId );

View File

@ -1,5 +0,0 @@
DomesticCat fritz = new DomesticCat();
fritz.setColor( Color.GINGER );
fritz.setSex( 'M' );
fritz.setName( "Fritz" );
entityManager.persist( fritz );

View File

@ -1,5 +0,0 @@
DomesticCat fritz = new DomesticCat();
fritz.setColor( Color.GINGER );
fritz.setSex( 'M' );
fritz.setName( "Fritz" );
session.save( fritz );

View File

@ -1,3 +0,0 @@
Cat cat = entityManager.find( Cat.class, catId );
cat.setName( "Garfield" );
entityManager.flush(); // generally this is not explicitly needed

View File

@ -1,3 +0,0 @@
Cat cat = session.get( Cat.class, catId );
cat.setName( "Garfield" );
session.flush(); // generally this is not explicitly needed

View File

@ -1 +0,0 @@
Cat theManagedInstance = entityManager.merge( someDetachedCat );

View File

@ -1 +0,0 @@
Cat theManagedInstance = session.merge( someDetachedCat );

View File

@ -1,31 +0,0 @@
import java.lang.String;
@Entity
public class User {
@Id
@GeneratedValue
Long id;
@NaturalId
String system;
@NaturalId
String userName;
...
}
// use getReference() to create associations...
Resource aResource = (Resource) session.byId( Resource.class ).getReference( 123 );
User aUser = (User) session.byNaturalId( User.class )
.using( "system", "prod" )
.using( "userName", "steve" )
.getReference();
aResource.assignTo( user );
// use load() to pull initialzed data
return session.byNaturalId( User.class )
.using( "system", "prod" )
.using( "userName", "steve" )
.load();

View File

@ -1 +0,0 @@
session.saveOrUpdate( someDetachedCat );

View File

@ -1,3 +0,0 @@
Cat cat = entityManager.find( Cat.class, catId );
...
entityManager.refresh( cat );

View File

@ -1,3 +0,0 @@
Cat cat = session.get( Cat.class, catId );
...
session.refresh( cat );

View File

@ -1,20 +0,0 @@
@Entity
public class User {
@Id
@GeneratedValue
Long id;
@NaturalId
String userName;
...
}
// use getReference() to create associations...
Resource aResource = (Resource) session.byId( Resource.class ).getReference( 123 );
User aUser = (User) session.bySimpleNaturalId( User.class ).getReference( "steve" );
aResource.assignTo( user );
// use load() to pull initialzed data
return session.bySimpleNaturalId( User.class ).load( "steve" );

View File

@ -1,2 +0,0 @@
Session session = entityManager.unwrap( Session.class );
SessionImplementor sessionImplementor = entityManager.unwrap( SessionImplementor.class );

View File

@ -1,5 +0,0 @@
Object detached = ...;
Object managed = entityManager.find( detached.getClass(), detached.getId() );
managed.setXyz( detached.getXyz() );
...
return managed;

View File

@ -1,413 +0,0 @@
<?xml version='1.0' encoding='utf-8' ?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
-->
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Criteria</title>
<para>
Criteria queries offer a type-safe alternative to HQL, JPQL and native-sql queries.
</para>
<important>
<para>
Hibernate offers an older, legacy <interfacename>org.hibernate.Criteria</interfacename> API which should be
considered deprecated. No feature development will target those APIs. Eventually, Hibernate-specific
criteria features will be ported as extensions to the JPA
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. For details on the
<interfacename>org.hibernate.Criteria</interfacename> API, see <xref linkend="query-criteria-legacy"/>.
</para>
<para>
This chapter will focus on the JPA APIs for declaring type-safe criteria queries.
</para>
</important>
<para>
Criteria queries are a programmatic, type-safe way to express a query. They are type-safe in terms of
using interfaces and classes to represent various structural parts of a query such as the query itself,
or the select clause, or an order-by, etc. They can also be type-safe in terms of referencing attributes
as we will see in a bit. Users of the older Hibernate <interfacename>org.hibernate.Criteria</interfacename>
query API will recognize the general approach, though we believe the JPA API to be superior
as it represents a clean look at the lessons learned from that API.
</para>
<para>
Criteria queries are essentially an object graph, where each part of the graph represents an increasing
(as we navigate down this graph) more atomic part of query. The first step in performing a criteria query
is building this graph. The <interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>
interface is the first thing with which you need to become acquainted to begin using criteria queries. Its
role is that of a factory for all the individual pieces of the criteria. You obtain a
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> instance by calling the
<methodname>getCriteriaBuilder</methodname> method of either
<interfacename>javax.persistence.EntityManagerFactory</interfacename> or
<interfacename>javax.persistence.EntityManager</interfacename>.
</para>
<para>
The next step is to obtain a <interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>. This
is accomplished using one of the 3 methods on
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> for this purpose:
</para>
<programlisting role="JAVA"><xi:include href="extras/CriteriaBuilder_query_creation_snippet.java" parse="text"/></programlisting>
<para>
Each serves a different purpose depending on the expected type of the query results.
</para>
<note>
<para>
<citetitle pubwork="chapter">Chapter 6 Criteria API</citetitle> of the JPA Specification
already contains a decent amount of reference material pertaining to the various parts of a
criteria query. So rather than duplicate all that content here, lets instead look at some of
the more widely anticipated usages of the API.
</para>
</note>
<section id="querycriteria-typedquery">
<title>Typed criteria queries</title>
<para>
The type of the criteria query (aka the <![CDATA[<T>]]>) indicates the expected types in the query
result. This might be an entity, an Integer, or any other object.
</para>
<section id="querycriteria-typedquery-entity">
<title>Selecting an entity</title>
<para>
This is probably the most common form of query. The application wants to select entity instances.
</para>
<example id="ex-criteria-typedquery-entity">
<title>Selecting the root entity</title>
<programlisting role="JAVA"><xi:include href="extras/select_root_entity_example.java" parse="text"/></programlisting>
</example>
<para>
The example uses <methodname>createQuery</methodname> passing in the <classname>Person</classname>
class reference as the results of the query will be Person objects.
</para>
<note>
<para>
The call to the <methodname>CriteriaQuery.select</methodname> method in this example is
unnecessary because <emphasis>personRoot</emphasis> will be the implied selection since we
have only a single query root. It was done here only for completeness of an example.
</para>
<para>
The <emphasis>Person_.eyeColor</emphasis> reference is an example of the static form of JPA
metamodel reference. We will use that form exclusively in this chapter. See
the documentation for the Hibernate JPA Metamodel Generator for additional details on
the JPA static metamodel.
</para>
</note>
</section>
<section id="querycriteria-typedquery-expression">
<title>Selecting an expression</title>
<para>
The simplest form of selecting an expression is selecting a particular attribute from an entity.
But this expression might also represent an aggregation, a mathematical operation, etc.
</para>
<example id="ex-criteria-typedquery-attribute">
<title>Selecting an attribute</title>
<programlisting role="JAVA"><xi:include href="extras/select_attribute_example.java" parse="text"/></programlisting>
</example>
<para>
In this example, the query is typed as <classname>java.lang.Integer</classname> because that
is the anticipated type of the results (the type of the <methodname>Person#age</methodname> attribute
is <classname>java.lang.Integer</classname>). Because a query might contain multiple references to
the Person entity, attribute references always need to be qualified. This is accomplished by the
<methodname>Root#get</methodname> method call.
</para>
</section>
<section id="querycriteria-typedquery-multiselect">
<title>Selecting multiple values</title>
<para>
There are actually a few different ways to select multiple values using criteria queries. We
will explore 2 options here, but an alternative recommended approach is to use tuples as described in
<xref linkend="querycriteria-tuple" />. Or consider a wrapper query; see
<xref linkend="querycriteria-typedquery-construct"/> for details.
</para>
<example id="ex-criteria-typedquery-array">
<title>Selecting an array</title>
<programlisting role="JAVA"><xi:include href="extras/select_multiple_values_array.java" parse="text"/></programlisting>
</example>
<para>
Technically this is classified as a typed query, but you can see from handling the results that
this is sort of misleading. Anyway, the expected result type here is an array.
</para>
<para>
The example then uses the <methodname>array</methodname> method of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> which explicitly
combines individual selections into a
<interfacename>javax.persistence.criteria.CompoundSelection</interfacename>.
</para>
<example id="ex-criteria-typedquery-array2">
<title>Selecting an array (2)</title>
<programlisting role="JAVA"><xi:include href="extras/select_multiple_values_array2.java" parse="text"/></programlisting>
</example>
<para>
Just as we saw in <xref linkend="ex-criteria-typedquery-array" /> we have a typed criteria
query returning an Object array. Both queries are functionally equivalent. This second example
uses the <methodname>multiselect</methodname> method which behaves slightly differently based on
the type given when the criteria query was first built, but in this case it says to select and
return an <emphasis>Object[]</emphasis>.
</para>
</section>
<section id="querycriteria-typedquery-construct">
<title>Selecting a wrapper</title>
<para>Another alternative to <xref linkend="querycriteria-typedquery-multiselect" /> is to instead
select an object that will <quote>wrap</quote> the multiple values. Going back to the example
query there, rather than returning an array of <emphasis>[Person#id, Person#age]</emphasis>
instead declare a class that holds these values and instead return that.
</para>
<example id="ex-criteria-typedquery-construct">
<title>Selecting an wrapper</title>
<programlisting role="JAVA"><xi:include href="extras/select_wrapper.java" parse="text"/></programlisting>
</example>
<para>
First we see the simple definition of the wrapper object we will be using to wrap our result
values. Specifically notice the constructor and its argument types. Since we will be returning
<classname>PersonWrapper</classname> objects, we use <classname>PersonWrapper</classname> as the
type of our criteria query.
</para>
<para>
This example illustrates the use of the
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> method
<methodname>construct</methodname> which is used to build a wrapper expression. For every row in the
result we are saying we would like a <emphasis>PersonWrapper</emphasis> instantiated with
the remaining arguments by the matching constructor. This wrapper expression is then passed as
the select.
</para>
</section>
</section>
<section id="querycriteria-tuple">
<title>Tuple criteria queries</title>
<para>
A better approach to <xref linkend="querycriteria-typedquery-multiselect" /> is to use either a
wrapper (which we just saw in <xref linkend="querycriteria-typedquery-construct" />) or using the
<interfacename>javax.persistence.Tuple</interfacename> contract.
</para>
<example id="ex-criteria-typedquery-tuple">
<title>Selecting a tuple</title>
<programlisting role="JAVA"><xi:include href="extras/select_tuple.java" parse="text"/></programlisting>
</example>
<para>
This example illustrates accessing the query results through the
<interfacename>javax.persistence.Tuple</interfacename> interface. The example uses the explicit
<methodname>createTupleQuery</methodname> of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename>. An alternate approach
is to use <methodname>createQuery</methodname> passing <literal>Tuple.class</literal>.
</para>
<para>
Again we see the use of the <methodname>multiselect</methodname> method, just like in
<xref linkend="ex-criteria-typedquery-array2" />. The difference here is that the type of the
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename> was defined as
<interfacename>javax.persistence.Tuple</interfacename> so the compound selections in this case are
interpreted to be the tuple elements.
</para>
<para>
The <interfacename>javax.persistence.Tuple</interfacename> contract provides 3 forms of access to
the underlying elements:
</para>
<variablelist>
<varlistentry>
<term>typed</term>
<listitem>
<para>
The <xref linkend="ex-criteria-typedquery-tuple"/> example illustrates this form of access
in the <literal>tuple.get( idPath )</literal> and <literal>tuple.get( agePath )</literal> calls.
This allows typed access to the underlying tuple values based on the
<interfacename>javax.persistence.TupleElement</interfacename> expressions used to build
the criteria.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>positional</term>
<listitem>
<para>
Allows access to the underlying tuple values based on the position. The simple
<emphasis>Object get(int position)</emphasis> form is very similar to the access
illustrated in <xref linkend="ex-criteria-typedquery-array" /> and
<xref linkend="ex-criteria-typedquery-array2" />. The
<emphasis><![CDATA[<X> X get(int position, Class<X> type]]></emphasis> form
allows typed positional access, but based on the explicitly supplied type which the tuple
value must be type-assignable to.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>aliased</term>
<listitem>
<para>
Allows access to the underlying tuple values based an (optionally) assigned alias. The
example query did not apply an alias. An alias would be applied via the
<methodname>alias</methodname> method on
<interfacename>javax.persistence.criteria.Selection</interfacename>. Just like
<literal>positional</literal> access, there is both a typed
(<emphasis>Object get(String alias)</emphasis>) and an untyped
(<emphasis><![CDATA[<X> X get(String alias, Class<X> type]]></emphasis> form.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section id="querycriteria-from">
<title>FROM clause</title>
<blockquote>
<attribution><citetitle>JPA Specification</citetitle>, section 6.5.2 Query Roots, pg 262</attribution>
<para>
A CriteriaQuery object defines a query over one or more entity, embeddable, or basic abstract
schema types. The root objects of the query are entities, from which the other types are reached
by navigation.
</para>
</blockquote>
<note>
<para>
All the individual parts of the FROM clause (roots, joins, paths) implement the
<interfacename>javax.persistence.criteria.From</interfacename> interface.
</para>
</note>
<section id="querycriteria-from-root">
<title>Roots</title>
<para>
Roots define the basis from which all joins, paths and attributes are available in the query.
A root is always an entity type. Roots are defined and added to the criteria by the overloaded
<methodname>from</methodname> methods on
<interfacename>javax.persistence.criteria.CriteriaQuery</interfacename>:
</para>
<programlisting role="JAVA"><xi:include href="extras/from_root_methods.java" parse="text"/></programlisting>
<example>
<title>Adding a root</title>
<programlisting role="JAVA"><xi:include href="extras/from_root_example.java" parse="text"/></programlisting>
</example>
<para>
Criteria queries may define multiple roots, the effect of which is to create a cartesian
product between the newly added root and the others. Here is an example matching all single
men and all single women:
</para>
<example>
<title>Adding multiple roots</title>
<programlisting role="JAVA"><xi:include href="extras/from_root_example_multiple.java" parse="text"/></programlisting>
</example>
</section>
<section id="querycriteria-from-join">
<title>Joins</title>
<para>
Joins allow navigation from other <interfacename>javax.persistence.criteria.From</interfacename>
to either association or embedded attributes. Joins are created by the numerous overloaded
<methodname>join</methodname> methods of the
<interfacename>javax.persistence.criteria.From</interfacename> interface
</para>
<example id="criteria-join-singular">
<title>Example with Embedded and ManyToOne</title>
<programlisting role="JAVA"><xi:include href="extras/from_join_example_embedded_and_many2one.java" parse="text"/></programlisting>
</example>
<example id="criteria-join-plural">
<title>Example with Collections</title>
<programlisting role="JAVA"><xi:include href="extras/from_join_example_plural.java" parse="text"/></programlisting>
</example>
</section>
<section id="querycriteria-from-fetch">
<title>Fetches</title>
<para>
Just like in HQL and JPQL, criteria queries can specify that associated data be fetched along
with the owner. Fetches are created by the numerous overloaded <methodname>fetch</methodname>
methods of the <interfacename>javax.persistence.criteria.From</interfacename> interface.
</para>
<example id="criteria-fetch-singular">
<title>Example with Embedded and ManyToOne</title>
<programlisting role="JAVA"><xi:include href="extras/from_fetch_example_embedded_and_many2one.java" parse="text"/></programlisting>
</example>
<note>
<para>
Technically speaking, embedded attributes are always fetched with their owner. However in
order to define the fetching of <emphasis>Address#country</emphasis> we needed a
<interfacename>javax.persistence.criteria.Fetch</interfacename> for its parent path.
</para>
</note>
<example id="criteria-fetch-plural">
<title>Example with Collections</title>
<programlisting role="JAVA"><xi:include href="extras/from_fetch_example_plural.java" parse="text"/></programlisting>
</example>
</section>
</section>
<section id="querycriteria-path">
<title>Path expressions</title>
<note>
<para>
Roots, joins and fetches are themselves paths as well.
</para>
</note>
</section>
<section id="querycriteria-param">
<title>Using parameters</title>
<example id="ex-querycriteria-param">
<title>Using parameters</title>
<programlisting role="JAVA"><xi:include href="extras/parameter_example.java" parse="text"/></programlisting>
</example>
<para>
Use the <methodname>parameter</methodname> method of
<interfacename>javax.persistence.criteria.CriteriaBuilder</interfacename> to obtain a parameter
reference. Then use the parameter reference to bind the parameter value to the
<interfacename>javax.persistence.Query</interfacename>
</para>
</section>
</chapter>

View File

@ -1,3 +0,0 @@
<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
CriteriaQuery<Tuple> createTupleQuery();
CriteriaQuery<Object> createQuery();

View File

@ -1,6 +0,0 @@
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Fetch<Person,Address> personAddress = personRoot.fetch( Person_.address );
// Address.country is a ManyToOne
Fetch<Address,Country> addressCountry = personAddress.fetch( Address_.country );

View File

@ -1,4 +0,0 @@
CriteriaQuery&lt;Person&gt; personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
Fetch<Person,Order> orders = personRoot.fetch( Person_.orders );
Fetch<Order,LineItem> orderLines = orders.fetch( Order_.lineItems );

View File

@ -1,6 +0,0 @@
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Join<Person,Address> personAddress = personRoot.join( Person_.address );
// Address.country is a ManyToOne
Join<Address,Country> addressCountry = personAddress.join( Address_.country );

View File

@ -1,4 +0,0 @@
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
Join<Person,Order> orders = personRoot.join( Person_.orders );
Join<Order,LineItem> orderLines = orders.join( Order_.lineItems );

View File

@ -1,3 +0,0 @@
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
// create and add the root
person.from( Person.class );

View File

@ -1,12 +0,0 @@
CriteriaQuery query = builder.createQuery();
Root<Person> men = query.from( Person.class );
Root<Person> women = query.from( Person.class );
Predicate menRestriction = builder.and(
builder.equal( men.get( Person_.gender ), Gender.MALE ),
builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
);
Predicate womenRestriction = builder.and(
builder.equal( women.get( Person_.gender ), Gender.FEMALE ),
builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
);
query.where( builder.and( menRestriction, womenRestriction ) );

View File

@ -1,3 +0,0 @@
<X> Root<X> from(Class<X>);
<X> Root<X> from(EntityType<X>)

View File

@ -1,9 +0,0 @@
CriteriaQuery<Person> criteria = build.createQuery( Person.class );
Root<Person> personRoot = criteria.from( Person.class );
criteria.select( personRoot );
ParameterExpression<String> eyeColorParam = builder.parameter( String.class );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), eyeColorParam ) );
TypedQuery<Person> query = em.createQuery( criteria );
query.setParameter( eyeColorParam, "brown" );
List<Person> people = query.getResultList();

View File

@ -1,9 +0,0 @@
CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class );
Root<Person> personRoot = criteria.from( Person.class );
criteria.select( personRoot.get( Person_.age ) );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List<Integer> ages = em.createQuery( criteria ).getResultList();
for ( Integer age : ages ) {
...
}

View File

@ -1,13 +0,0 @@
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
Root<Person> personRoot = criteria.from( Person.class );
Path<Long> idPath = personRoot.get( Person_.id );
Path<Integer> agePath = personRoot.get( Person_.age );
criteria.select( builder.array( idPath, agePath ) );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List<Object[]> valueArray = em.createQuery( criteria ).getResultList();
for ( Object[] values : valueArray ) {
final Long id = (Long) values[0];
final Integer age = (Integer) values[1];
...
}

View File

@ -1,13 +0,0 @@
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class );
Root<Person> personRoot = criteria.from( Person.class );
Path<Long> idPath = personRoot.get( Person_.id );
Path<Integer> agePath = personRoot.get( Person_.age );
criteria.multiselect( idPath, agePath );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List<Object[]> valueArray = em.createQuery( criteria ).getResultList();
for ( Object[] values : valueArray ) {
final Long id = (Long) values[0];
final Integer age = (Integer) values[1];
...
}

View File

@ -1,9 +0,0 @@
CriteriaQuery<Person> criteria = builder.createQuery( Person.class );
Root<Person> personRoot = criteria.from( Person.class );
criteria.select( personRoot );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List<Person> people = em.createQuery( criteria ).getResultList();
for ( Person person : people ) {
...
}

View File

@ -1,13 +0,0 @@
CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
Root<Person> personRoot = criteria.from( Person.class );
Path<Long> idPath = personRoot.get( Person_.id );
Path<Integer> agePath = personRoot.get( Person_.age );
criteria.multiselect( idPath, agePath );
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List<Tuple> tuples = em.createQuery( criteria ).getResultList();
for ( Tuple tuple : valueArray ) {
assert tuple.get( 0 ) == tuple.get( idPath );
assert tuple.get( 1 ) == tuple.get( agePath );
...
}

View File

@ -1,27 +0,0 @@
public class PersonWrapper {
private final Long id;
private final Integer age;
public PersonWrapper(Long id, Integer age) {
this.id = id;
this.age = age;
}
...
}
...
CriteriaQuery<PersonWrapper> criteria = builder.createQuery( PersonWrapper.class );
Root<Person> personRoot = criteria.from( Person.class );
criteria.select(
builder.construct(
PersonWrapper.class,
personRoot.get( Person_.id ),
personRoot.get( Person_.age )
)
);
criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) );
List<PersonWrapper> people = em.createQuery( criteria ).getResultList();
for ( PersonWrapper person : people ) {
...
}

View File

@ -1,10 +0,0 @@
select count(*), sum( o.total ), avg( o.total ), min( o.total ), max( o.total )
from Order o
select count( distinct c.name )
from Customer c
select c.id, c.name, sum( o.total )
from Customer c
left join c.orders o
group by c.id, c.name

View File

@ -1,9 +0,0 @@
select year( current_date() ) - year( c.dateOfBirth )
from Customer c
select c
from Customer c
where year( current_date() ) - year( c.dateOfBirth ) < 30
select o.customer, o.total + ( o.total * :salesTax )
from Order o

View File

@ -1,36 +0,0 @@
select cal
from Calendar cal
where maxelement(cal.holidays) > current_date()
select o
from Order o
where maxindex(o.items) > 100
select o
from Order o
where minelement(o.items) > 10000
select m
from Cat as m, Cat as kit
where kit in elements(m.kittens)
// the above query can be re-written in jpql standard way:
select m
from Cat as m, Cat as kit
where kit member of m.kittens
select p
from NameList l, Person p
where p.name = some elements(l.names)
select cat
from Cat cat
where exists elements(cat.kittens)
select p
from Player p
where 3 > all elements(p.scores)
select show
from Show show
where 'fizard' in indices(show.acts)

View File

@ -1,16 +0,0 @@
select c
from Customer c
join c.orders o
join o.lineItems l
join l.product p
where o.status = 'pending'
and p.status = 'backorder'
// alternate syntax
select c
from Customer c,
in(c.orders) o,
in(o.lineItems) l
join l.product p
where o.status = 'pending'
and p.status = 'backorder'

View File

@ -1,3 +0,0 @@
select 'Mr. ' || c.name.first || ' ' || c.name.last
from Customer c
where c.gender = Gender.MALE

View File

@ -1,4 +0,0 @@
select new Family( mother, mate, offspr )
from DomesticCat as mother
join mother.mate as mate
left join mother.kittens as offspr

View File

@ -1,7 +0,0 @@
select o
from Order o
where o.lineItems is empty
select c
from Customer c
where c.pastDueBills is not empty

View File

@ -1,8 +0,0 @@
select p
from Payment p
where type(p) = CreditCardPayment
select p
from Payment p
where type(p) = :aType

View File

@ -1,10 +0,0 @@
// retrieve the total for all orders
select sum( o.total )
from Order o
// retrieve the total of all orders
// *grouped by* customer
select c.id, sum( o.total )
from Order o
inner join o.customer c
group by c.id

View File

@ -1,5 +0,0 @@
select c.id, sum( o.total )
from Order o
inner join o.customer c
group by c.id
having sum( o.total ) > 10000.00

View File

@ -1,22 +0,0 @@
select o
from Order o
where o.items[0].id = 1234
select p
from Person p, Calendar c
where c.holidays['national day'] = p.birthDay
and p.nationality.calendar = c
select i
from Item i, Order o
where o.items[ o.deliveredItemIndices[0] ] = i
and o.id = 11
select i
from Item i, Order o
where o.items[ maxindex(o.items) ] = i
and o.id = 11
select i
from Item i, Order o
where o.items[ size(o.items) - 1 ] = i

View File

@ -1,10 +0,0 @@
select c
from Customer c
join c.chiefExecutive ceo
where ceo.age < 25
// same query but specifying join type as 'inner' explicitly
select c
from Customer c
inner join c.chiefExecutive ceo
where ceo.age < 25

View File

@ -1,15 +0,0 @@
// get customers who have orders worth more than $5000
// or who are in "preferred" status
select distinct c
from Customer c
left join c.orders o
where o.value > 5000.00
or c.status = 'preferred'
// functionally the same query but using the
// 'left outer' phrase
select distinct c
from Customer c
left outer join c.orders o
where o.value > 5000.00
or c.status = 'preferred'

View File

@ -1,3 +0,0 @@
select c
from Customer c
left join fetch c.orders o

Some files were not shown because too many files have changed in this diff Show More