HHH-11890 - Remove old docbook folder from the documentation module
This commit is contained in:
parent
ba2e273e9e
commit
d671fe1391
|
@ -1,2 +0,0 @@
|
|||
# Ignore publican output
|
||||
*/tmp
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
@ -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><cache></code>, you can use <code><class-cache></code> and
|
||||
<code><collection-cache></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>
|
|
@ -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>
|
|
@ -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
|
||||
<one-to-one>, <many-to-one>, <key>, and <many-to-many> 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 <column> 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><column></option> elements.</title>
|
||||
<para>
|
||||
Many mapping elements accept one or more child <column> 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 <comment> elements to your schema.</title>
|
||||
<para>
|
||||
Use the <comment> 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
|
@ -1,10 +0,0 @@
|
|||
<!ENTITY version "WORKING">
|
||||
<!ENTITY today "NOW">
|
||||
<!ENTITY copyrightYear "2011">
|
||||
<!--
|
||||
~ 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>.
|
||||
-->
|
||||
<!ENTITY copyrightHolder "Red Hat, Inc.">
|
|
@ -1,65 +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>.
|
||||
-->
|
||||
<!DOCTYPE book SYSTEM "http://docbook.org/xml/5.0/dtd/docbook.dtd" [
|
||||
<!ENTITY % BOOK_ENTITIES SYSTEM "Hibernate_Development_Guide.ent">
|
||||
%BOOK_ENTITIES;
|
||||
]>
|
||||
|
||||
<book>
|
||||
<info>
|
||||
<title>Hibernate Developer Guide</title>
|
||||
<releaseinfo>&version;</releaseinfo>
|
||||
<productname>Hibernate O/RM</productname>
|
||||
<productnumber>&version;</productnumber>
|
||||
<pubdate>&today;</pubdate>
|
||||
<mediaobject>
|
||||
<imageobject role="fo">
|
||||
<imagedata fileref="images/hibernate_logo_a.png" align="center" />
|
||||
</imageobject>
|
||||
<imageobject role="html">
|
||||
<imagedata fileref="images/hibernate_logo_a.png" depth="3cm" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
<copyright>
|
||||
<year>©rightYear;</year>
|
||||
<holder>©rightHolder;</holder>
|
||||
</copyright>
|
||||
|
||||
<authorgroup xmlns:xl="http://www.w3.org/1999/xlink">
|
||||
<author>
|
||||
<orgname><link xl:href="http://hibernate.org">The Hibernate Team</link></orgname>
|
||||
</author>
|
||||
<othercredit>
|
||||
<orgname><link xl:href="http://design.jboss.org/">The JBoss Visual Design Team</link></orgname>
|
||||
</othercredit>
|
||||
</authorgroup>
|
||||
</info>
|
||||
|
||||
|
||||
<xi:include href="Preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Database_Access.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/transactions/Transactions.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/pc/Persistence_Context.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Batch_Processing.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Locking.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Caching.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/services/Services.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Data_Categorizations.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Mapping_Entities.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Mapping_Association.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/query_ql/HQL_JPQL.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/query_criteria/Criteria.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/query_native/Native_SQL.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="JMX.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="Envers.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/multitenancy/Multi_Tenancy.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="chapters/osgi/OSGi.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="appendix-Configuration_Properties.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<xi:include href="appendices/legacy_criteria/Legacy_Criteria.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
</book>
|
||||
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
@ -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>
|
|
@ -1,107 +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>.
|
||||
-->
|
||||
<preface xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" >
|
||||
|
||||
<title>Preface</title>
|
||||
<para>
|
||||
Working with both Object-Oriented software and Relational Databases can be cumbersome and time consuming.
|
||||
Development costs are significantly higher due to a paradigm mismatch between how data is represented in
|
||||
objects versus relational databases. Hibernate is an Object/Relational Mapping solution for Java environments.
|
||||
The term Object/Relational Mapping refers to the technique of mapping data from an object model representation
|
||||
to a relational data model representation (and visa versa). See
|
||||
<link xl:href="http://en.wikipedia.org/wiki/Object-relational_mapping"/> for a good high-level discussion.
|
||||
</para>
|
||||
|
||||
<note>
|
||||
<para>
|
||||
While having a strong background in SQL is not required to use Hibernate, having a basic understanding of
|
||||
the concepts can greatly help you understand Hibernate more fully and quickly. Probably the single
|
||||
best background is an understanding of data modeling principles. You might want to consider these resources
|
||||
as a good starting point:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://www.agiledata.org/essays/dataModeling101.html"/>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<link xl:href="http://en.wikipedia.org/wiki/Data_modeling"/>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to
|
||||
SQL data types), but also provides data query and retrieval facilities. It can significantly reduce
|
||||
development time otherwise spent with manual data handling in SQL and JDBC. Hibernate’s design goal is to
|
||||
relieve the developer from 95% of common data persistence-related programming tasks by eliminating the need for
|
||||
manual, hand-crafted data processing using SQL and JDBC. However, unlike many other persistence solutions,
|
||||
Hibernate does not hide the power of SQL from you and guarantees that your investment in relational technology
|
||||
and knowledge is as valid as always.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Hibernate may not be the best solution for data-centric applications that only use stored-procedures to
|
||||
implement the business logic in the database, it is most useful with object-oriented domain models and business
|
||||
logic in the Java-based middle-tier. However, Hibernate can certainly help you to remove or encapsulate
|
||||
vendor-specific SQL code and will help with the common task of result set translation from a tabular
|
||||
representation to a graph of objects.
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Get Involved</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Use Hibernate and report any bugs or issues you find. See
|
||||
<link xl:href="http://hibernate.org/issuetracker.html"/> for details.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Try your hand at fixing some bugs or implementing enhancements. Again, see
|
||||
<link xl:href="http://hibernate.org/issuetracker.html"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Engage with the community using mailing lists, forums, IRC, or other ways listed at
|
||||
<link xl:href="http://hibernate.org/community.html"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Help improve or translate this documentation. Contact us on
|
||||
the developer mailing list if you have interest.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Spread the word. Let the rest of your organization know about the benefits of
|
||||
Hibernate.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Getting Started Guide</title>
|
||||
<para>
|
||||
New users may want to first look through the
|
||||
<citetitle pubwork="book">Hibernate Getting Started Guide</citetitle> for basic information as well as
|
||||
tutorials. Even seasoned veterans may want to considering perusing the sections pertaining to
|
||||
build artifacts for any changes.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
</preface>
|
||||
|
|
@ -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><one-to-many/></literal>
|
||||
or <literal><many-to-many/></literal>) or components
|
||||
(<literal><composite-element/></literal> ),
|
||||
and the second is if the collection contains scalar values
|
||||
(<literal><element/></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
|
||||
"elements". For an indexed collection, we can also reference the index property using
|
||||
the special property "indices".
|
||||
</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><natural-id></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>
|
|
@ -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 <cache> 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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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) < 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() );
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
SessionFactory sessionFactory = new Configuration()
|
||||
.setInterceptor( new AuditInterceptor() )
|
||||
...
|
||||
.buildSessionFactory();
|
|
@ -1 +0,0 @@
|
|||
Session session = sf.withOptions().interceptor( new AuditInterceptor() ).openSession();
|
|
@ -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) );
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -1,10 +0,0 @@
|
|||
@Entity
|
||||
public class Department {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@OneToMany(mappedBy="department")
|
||||
private List<Employees> employees;
|
||||
|
||||
...
|
||||
}
|
|
@ -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;
|
||||
|
||||
...
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
@FetchProfile(
|
||||
name="employee.projects",
|
||||
fetchOverrides={
|
||||
@FetchOverride(
|
||||
entity=Employee.class,
|
||||
association="projects",
|
||||
mode=JOIN
|
||||
)
|
||||
}
|
||||
)
|
|
@ -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();
|
|
@ -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();
|
|
@ -1,10 +0,0 @@
|
|||
@Entity
|
||||
public class Project {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@ManyToMany
|
||||
private Set<Employee> employees;
|
||||
|
||||
...
|
||||
}
|
|
@ -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();
|
|
@ -1,4 +0,0 @@
|
|||
String userid = ...;
|
||||
session.enableFetchProfile( "employee.projects" );
|
||||
Employee e = (Employee) session.bySimpleNaturalId( Employee.class )
|
||||
.load( userid );
|
|
@ -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();
|
|
@ -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>
|
|
@ -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" );
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
...
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
Session session = sessionFactory.withOptions()
|
||||
.tenantIdentifier( yourTenantIdentifier )
|
||||
...
|
||||
.openSession();
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
|
@ -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 |
Binary file not shown.
Before Width: | Height: | Size: 17 KiB |
|
@ -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 |
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
|
@ -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 |
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
assert entityManager.contains( cat );
|
|
@ -1 +0,0 @@
|
|||
assert session.contains( cat );
|
|
@ -1 +0,0 @@
|
|||
entityManager.remove( fritz );
|
|
@ -1 +0,0 @@
|
|||
session.delete( fritz );
|
|
@ -1,2 +0,0 @@
|
|||
Book book = new Book();
|
||||
book.setAuthor( entityManager.getReference( Author.class, authorId ) );
|
|
@ -1,2 +0,0 @@
|
|||
Book book = new Book();
|
||||
book.setAuthor( session.byId( Author.class ).getReference( authorId ) );
|
|
@ -1 +0,0 @@
|
|||
entityManager.find( Author.class, authorId );
|
|
@ -1 +0,0 @@
|
|||
session.byId( Author.class ).load( authorId );
|
|
@ -1,5 +0,0 @@
|
|||
DomesticCat fritz = new DomesticCat();
|
||||
fritz.setColor( Color.GINGER );
|
||||
fritz.setSex( 'M' );
|
||||
fritz.setName( "Fritz" );
|
||||
entityManager.persist( fritz );
|
|
@ -1,5 +0,0 @@
|
|||
DomesticCat fritz = new DomesticCat();
|
||||
fritz.setColor( Color.GINGER );
|
||||
fritz.setSex( 'M' );
|
||||
fritz.setName( "Fritz" );
|
||||
session.save( fritz );
|
|
@ -1,3 +0,0 @@
|
|||
Cat cat = entityManager.find( Cat.class, catId );
|
||||
cat.setName( "Garfield" );
|
||||
entityManager.flush(); // generally this is not explicitly needed
|
|
@ -1,3 +0,0 @@
|
|||
Cat cat = session.get( Cat.class, catId );
|
||||
cat.setName( "Garfield" );
|
||||
session.flush(); // generally this is not explicitly needed
|
|
@ -1 +0,0 @@
|
|||
Cat theManagedInstance = entityManager.merge( someDetachedCat );
|
|
@ -1 +0,0 @@
|
|||
Cat theManagedInstance = session.merge( someDetachedCat );
|
|
@ -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();
|
|
@ -1 +0,0 @@
|
|||
session.saveOrUpdate( someDetachedCat );
|
|
@ -1,3 +0,0 @@
|
|||
Cat cat = entityManager.find( Cat.class, catId );
|
||||
...
|
||||
entityManager.refresh( cat );
|
|
@ -1,3 +0,0 @@
|
|||
Cat cat = session.get( Cat.class, catId );
|
||||
...
|
||||
session.refresh( cat );
|
|
@ -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" );
|
|
@ -1,2 +0,0 @@
|
|||
Session session = entityManager.unwrap( Session.class );
|
||||
SessionImplementor sessionImplementor = entityManager.unwrap( SessionImplementor.class );
|
|
@ -1,5 +0,0 @@
|
|||
Object detached = ...;
|
||||
Object managed = entityManager.find( detached.getClass(), detached.getId() );
|
||||
managed.setXyz( detached.getXyz() );
|
||||
...
|
||||
return managed;
|
|
@ -1,414 +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="criteria"
|
||||
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>
|
|
@ -1,3 +0,0 @@
|
|||
<T> CriteriaQuery<T> createQuery(Class<T> resultClass);
|
||||
CriteriaQuery<Tuple> createTupleQuery();
|
||||
CriteriaQuery<Object> createQuery();
|
|
@ -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 );
|
|
@ -1,4 +0,0 @@
|
|||
CriteriaQuery<Person> 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 );
|
|
@ -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 );
|
|
@ -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 );
|
|
@ -1,3 +0,0 @@
|
|||
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
|
||||
// create and add the root
|
||||
person.from( Person.class );
|
|
@ -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 ) );
|
|
@ -1,3 +0,0 @@
|
|||
<X> Root<X> from(Class<X>);
|
||||
|
||||
<X> Root<X> from(EntityType<X>)
|
|
@ -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();
|
|
@ -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 ) {
|
||||
...
|
||||
}
|
|
@ -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];
|
||||
...
|
||||
}
|
|
@ -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];
|
||||
...
|
||||
}
|
|
@ -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 ) {
|
||||
...
|
||||
}
|
|
@ -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 );
|
||||
...
|
||||
}
|
|
@ -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 ) {
|
||||
...
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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'
|
|
@ -1,3 +0,0 @@
|
|||
select 'Mr. ' || c.name.first || ' ' || c.name.last
|
||||
from Customer c
|
||||
where c.gender = Gender.MALE
|
|
@ -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
|
|
@ -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
|
|
@ -1,8 +0,0 @@
|
|||
select p
|
||||
from Payment p
|
||||
where type(p) = CreditCardPayment
|
||||
|
||||
select p
|
||||
from Payment p
|
||||
where type(p) = :aType
|
||||
|
|
@ -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
|
|
@ -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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue