doc'd new lazy stuff

added node examples


git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@6648 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Gavin King 2005-05-03 03:22:42 +00:00
parent 92359983cc
commit 617a17a15b
3 changed files with 240 additions and 117 deletions

View File

@ -237,6 +237,8 @@
<area id="class19" coords="20 55"/>
<area id="class20" coords="21 55"/>
<area id="class21" coords="22 55"/>
<area id="class22" coords="23 55"/>
<area id="class23" coords="24 55"/>
</areaspec>
<programlisting><![CDATA[<class
name="ClassName"
@ -261,6 +263,7 @@
subselect="SQL expression"
abstract="true|false"
entity-name="EntityName"
node="element-name"
/>]]></programlisting>
<calloutlist>
<callout arearefs="class1">
@ -403,6 +406,12 @@
<literal>&lt;union-subclass&gt;</literal> hierarchies.
</para>
</callout>
<callout arearefs="class22">
<para>
<literal>entity-name</literal> (optional, defaults to the class name): Explicitly
specify an entity name.
</para>
</callout>
</calloutlist>
</programlistingco>
@ -537,11 +546,11 @@
<programlistingco>
<areaspec>
<area id="id1" coords="2 65"/>
<area id="id2" coords="3 65" />
<area id="id3" coords="4 65"/>
<area id="id4" coords="5 65" />
<area id="id5" coords="6 65" />
<area id="id1" coords="2 70"/>
<area id="id2" coords="3 70" />
<area id="id3" coords="4 70"/>
<area id="id4" coords="5 70" />
<area id="id5" coords="6 70" />
</areaspec>
<programlisting><![CDATA[<id
name="propertyName"
@ -549,6 +558,7 @@
column="column_name"
unsaved-value="null|any|none|undefined|id_value"
access="field|property|ClassName">
node="element-name|@attribute-name|element/@attribute|."
<generator class="generatorClass"/>
</id>]]></programlisting>
@ -861,6 +871,7 @@
class="ClassName"
unsaved-value="undefined|any|none"
access="field|property|ClassName">
node="element-name|."
<key-property name="propertyName" type="typename" column="column_name"/>
<key-many-to-one name="propertyName class="ClassName" column="column_name"/>
@ -1020,11 +1031,11 @@
<programlistingco>
<areaspec>
<area id="version1" coords="2 60"/>
<area id="version2" coords="3 60"/>
<area id="version3" coords="4 60"/>
<area id="version4" coords="5 60"/>
<area id="version5" coords="6 60"/>
<area id="version1" coords="2 70"/>
<area id="version2" coords="3 70"/>
<area id="version3" coords="4 70"/>
<area id="version4" coords="5 70"/>
<area id="version5" coords="6 70"/>
</areaspec>
<programlisting><![CDATA[<version
column="version_column"
@ -1032,6 +1043,7 @@
type="typename"
access="field|property|ClassName"
unsaved-value="null|negative|undefined"
node="element-name|@attribute-name|element/@attribute|."
/>]]></programlisting>
<calloutlist>
<callout arearefs="version1">
@ -1096,16 +1108,17 @@
<programlistingco>
<areaspec>
<area id="timestamp1" coords="2 45"/>
<area id="timestamp2" coords="3 45" />
<area id="timestamp3" coords="4 45" />
<area id="timestamp4" coords="5 45" />
<area id="timestamp1" coords="2 70"/>
<area id="timestamp2" coords="3 70" />
<area id="timestamp3" coords="4 70" />
<area id="timestamp4" coords="5 70" />
</areaspec>
<programlisting><![CDATA[<timestamp
column="timestamp_column"
name="propertyName"
access="field|property|ClassName"
unsaved-value="null|undefined"
node="element-name|@attribute-name|element/@attribute|."
/>]]></programlisting>
<calloutlist>
<callout arearefs="timestamp1">
@ -1156,19 +1169,19 @@
<programlistingco>
<areaspec>
<area id="property1" coords="2 45"/>
<area id="property2" coords="3 45"/>
<area id="property3" coords="4 45"/>
<area id="property1" coords="2 70"/>
<area id="property2" coords="3 70"/>
<area id="property3" coords="4 70"/>
<areaset id="property4-5" coords="">
<area id="property4" coords='5 45'/>
<area id="property5" coords='6 45'/>
<area id="property4" coords='5 70'/>
<area id="property5" coords='6 70'/>
</areaset>
<area id="property6" coords="7 45"/>
<area id="property7" coords="8 45"/>
<area id="property8" coords="9 45"/>
<area id="property9" coords="10 45"/>
<area id="property10" coords="11 45"/>
<area id="property11" coords="12 45"/>
<area id="property6" coords="7 70"/>
<area id="property7" coords="8 70"/>
<area id="property8" coords="9 70"/>
<area id="property9" coords="10 70"/>
<area id="property10" coords="11 70"/>
<area id="property11" coords="12 70"/>
</areaspec>
<programlisting><![CDATA[<property
name="propertyName"
@ -1182,6 +1195,7 @@
unique="true|false"
not-null="true|false"
optimistic-lock="true|false"
node="element-name|@attribute-name|element/@attribute|."
/>]]></programlisting>
<calloutlist>
<callout arearefs="property1">
@ -1338,22 +1352,23 @@
<programlistingco>
<areaspec>
<area id="manytoone1" coords="2 60"/>
<area id="manytoone2" coords="3 60"/>
<area id="manytoone3" coords="4 60"/>
<area id="manytoone4" coords="5 60"/>
<area id="manytoone5" coords="6 60"/>
<area id="manytoone1" coords="2 70"/>
<area id="manytoone2" coords="3 70"/>
<area id="manytoone3" coords="4 70"/>
<area id="manytoone4" coords="5 70"/>
<area id="manytoone5" coords="6 70"/>
<areaset id="manytoone6-7" coords="">
<area id="manytoone6" coords='7 60'/>
<area id="manytoone7" coords='8 60'/>
<area id="manytoone6" coords='7 70'/>
<area id="manytoone7" coords='8 70'/>
</areaset>
<area id="manytoone8" coords="9 60"/>
<area id="manytoone9" coords="10 60"/>
<area id="manytoone10" coords="11 60"/>
<area id="manytoone11" coords="12 60"/>
<area id="manytoone12" coords="13 60"/>
<area id="manytoone13" coords="14 60"/>
<area id="manytoone14" coords="15 60"/>
<area id="manytoone8" coords="9 70"/>
<area id="manytoone9" coords="10 70"/>
<area id="manytoone10" coords="11 70"/>
<area id="manytoone11" coords="12 70"/>
<area id="manytoone12" coords="13 70"/>
<area id="manytoone13" coords="14 70"/>
<area id="manytoone14" coords="15 70"/>
<area id="manytoone15" coords="16 70"/>
</areaspec>
<programlisting><![CDATA[<many-to-one
name="propertyName"
@ -1368,9 +1383,11 @@
unique="true|false"
not-null="true|false"
optimistic-lock="true|false"
lazy="true|false"
lazy="true|proxy|false"
not-found="ignore|exception"
entity-name="EntityName"
node="element-name|@attribute-name|element/@attribute|."
embed-xml="true|false"
/>]]></programlisting>
<calloutlist>
<callout arearefs="manytoone1">
@ -1449,11 +1466,12 @@
</callout>
<callout arearefs="manytoone13">
<para>
<literal>lazy</literal> (optional - defaults to <literal>false</literal>): Specifies
that this property should be fetched lazily when the instance variable is first
accessed (requires build-time bytecode instrumentation). Note that this does not
influence Hibernate's proxy behavior - like the <literal>lazy</literal> attribute
on class or collection mappings, but uses interception for deferred loading.
<literal>lazy</literal> (optional - defaults to <literal>proxy</literal>):
By default, single point associations are proxied. <literal>lazy="true"</literal>
specifies that the property should be fetched lazily when the instance variable
is first accessed (requires build-time bytecode instrumentation).
<literal>lazy="false"</literal> specifies that the association will always
be eagerly fetched.
</para>
</callout>
<callout arearefs="manytoone14">
@ -1463,6 +1481,11 @@
<literal>ignore</literal> will treat a missing row as a null association.
</para>
</callout>
<callout arearefs="manytoone15">
<para>
<literal>entity-name</literal> (optional): The entity name of the associated class.
</para>
</callout>
</calloutlist>
</programlistingco>
@ -1522,14 +1545,16 @@
<programlistingco>
<areaspec>
<area id="onetoone1" coords="2 60"/>
<area id="onetoone2" coords="3 60"/>
<area id="onetoone3" coords="4 60"/>
<area id="onetoone4" coords="5 60"/>
<area id="onetoone5" coords="6 60"/>
<area id="onetoone6" coords="7 60"/>
<area id="onetoone7" coords="8 60"/>
<area id="onetoone8" coords="9 60"/>
<area id="onetoone1" coords="2 70"/>
<area id="onetoone2" coords="3 70"/>
<area id="onetoone3" coords="4 70"/>
<area id="onetoone4" coords="5 70"/>
<area id="onetoone5" coords="6 70"/>
<area id="onetoone6" coords="7 70"/>
<area id="onetoone7" coords="8 70"/>
<area id="onetoone8" coords="9 70"/>
<area id="onetoone9" coords="10 70"/>
<area id="onetoone10" coords="11 70"/>
</areaspec>
<programlisting><![CDATA[<one-to-one
name="propertyName"
@ -1540,7 +1565,10 @@
property-ref="propertyNameFromAssociatedClass"
access="field|property|ClassName"
formula="any SQL expression"
lazy="true|proxy|false"
entity-name="EntityName"
node="element-name|@attribute-name|element/@attribute|."
embed-xml="true|false"
/>]]></programlisting>
<calloutlist>
<callout arearefs="onetoone1">
@ -1596,6 +1624,22 @@
<literal>org.hibernate.test.onetooneformula</literal> for an example.)
</para>
</callout>
<callout arearefs="onetoone9">
<para>
<literal>lazy</literal> (optional - defaults to <literal>proxy</literal>):
By default, single point associations are proxied. <literal>lazy="true"</literal>
specifies that the property should be fetched lazily when the instance variable
is first accessed (requires build-time bytecode instrumentation).
<literal>lazy="false"</literal> specifies that the association will always
be eagerly fetched. <emphasis>Note that if <literal>constrained="false"</literal>,
proxying is impossible and Hibernate will eager fetch the association!</emphasis>
</para>
</callout>
<callout arearefs="onetoone10">
<para>
<literal>entity-name</literal> (optional): The entity name of the associated class.
</para>
</callout>
</calloutlist>
</programlistingco>
@ -1696,6 +1740,7 @@
lazy="true|false"
optimistic-lock="true|false"
unique="true|false"
node="element-name|."
>
<property ...../>
@ -1901,7 +1946,8 @@
lazy="true|false"
dynamic-update="true|false"
dynamic-insert="true|false"
entity-name="EntityName">
entity-name="EntityName"
node="element-name">
<property .... />
.....
@ -1993,7 +2039,8 @@
extends="SuperclassName"
persister="ClassName"
subselect="SQL expression"
entity-name="EntityName">
entity-name="EntityName"
node="element-name">
<key .... >
@ -2105,7 +2152,8 @@
abstract="true|false"
persister="ClassName"
subselect="SQL expression"
entity-name="EntityName">
entity-name="EntityName"
node="element-name">
<property .... />
.....

View File

@ -129,6 +129,8 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
batch-size="N"
access="field|property|ClassName"
optimistic-lock="true|false"
node="element-name|."
embed-xml="true|false"
>
<key .... />
@ -156,7 +158,8 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
<callout arearefs="mappingcollection4">
<para>
<literal>lazy</literal> (optional - defaults to <literal>true</literal>)
enable lazy initialization (not available for arrays)
may be used to disable lazy fetching and specify that the association is
always eagerly fetched (not available for arrays)
</para>
</callout>
<callout arearefs="mappingcollection5">
@ -328,6 +331,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
column="column_name"
formula="any SQL expression"
type="type_name"
node="@attribute-name"
length="N"/>]]></programlisting>
<calloutlist>
<callout arearefs="mapkey1">
@ -464,6 +468,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
<area id="manytomany4" coords="5 60"/>
<area id="manytomany5" coords="6 60"/>
<area id="manytomany6" coords="7 60"/>
<area id="manytomany7" coords="8 60"/>
</areaspec>
<programlisting><![CDATA[<many-to-many
column="column_name"
@ -473,6 +478,8 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
unique="true|false"
not-found="ignore|exception"
entity-name="EntityName"
node="element-name|element/@attribute"
embed-xml="true|false"
/>]]></programlisting>
<calloutlist>
<callout arearefs="manytomany1">
@ -516,6 +523,12 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
<literal>ignore</literal> will treat a missing row as a null association.
</para>
</callout>
<callout arearefs="manytomany7">
<para>
<literal>entity-name</literal> (optional): The entity name of the associated class,
as an alternative to <literal>class</literal>.
</para>
</callout>
</calloutlist>
</programlistingco>
@ -617,11 +630,15 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
<areaspec>
<area id="onetomany1" coords="2 60"/>
<area id="onetomany2" coords="3 60"/>
<area id="onetomany3" coords="4 60"/>
</areaspec>
<programlisting><![CDATA[<one-to-many
class="ClassName"
not-found="ignore|exception"
entity-name="EntityName"/>]]></programlisting>
entity-name="EntityName"
node="element-name|element/@attribute"
embed-xml="true|false"
/>]]></programlisting>
<calloutlist>
<callout arearefs="onetomany1">
<para>
@ -635,6 +652,12 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
<literal>ignore</literal> will treat a missing row as a null association.
</para>
</callout>
<callout arearefs="onetomany3">
<para>
<literal>entity-name</literal> (optional): The entity name of the associated class,
as an alternative to <literal>class</literal>.
</para>
</callout>
</calloutlist>
</programlistingco>

View File

@ -5,11 +5,10 @@
<title>Fetching strategies</title>
<para>
A <emphasis>fetching strategy</emphasis> is the strategy Hibernate will
use for retrieving associated objects if the application needs to
navigate the association. Fetch strategies may be declared in the O/R
mapping metadata, or over-ridden by a particular HQL or
<literal>Criteria</literal> query.
A <emphasis>fetching strategy</emphasis> is the strategy Hibernate will use for
retrieving associated objects if the application needs to navigate the association.
Fetch strategies may be declared in the O/R mapping metadata, or over-ridden by a
particular HQL or <literal>Criteria</literal> query.
</para>
<para>
@ -51,25 +50,77 @@
</para>
</listitem>
</itemizedlist>
<para>
By default, Hibernate3 uses lazy select fetching, which is the best choice for most entities
and collections in most applications. If you set
<literal>hibernate.default_batch_fetch_size</literal>, Hibernate will use the batch fetch
optimization to lazy fetching (this optimization may also be enabled at a more granular level).
</para>
<para>
However, there is one problem to be aware of. Access to a lazy association
outside of the context of an open Hibernate session will result in an exception.
For example:
Hibernate also distinguishes between:
</para>
<itemizedlist>
<listitem>
<para>
<emphasis>Immediate fetching</emphasis> - an association, collection or
attribute is fetched immediately, when the owner is loaded.
</para>
</listitem>
<listitem>
<para>
<emphasis>Lazy collection fetching</emphasis> - a collection is fetched
when the application invokes an operation upon that collection. (This
is the default for collections.)
</para>
</listitem>
<listitem>
<para>
<emphasis>Proxy fetching</emphasis> - a single-valued association is
fetched when a method other than the identifier getter is invoked
upon the associated object.
</para>
</listitem>
<listitem>
<para>
<emphasis>Lazy attribute fetching</emphasis> - an attribute or single
valued association is fetched when the instance variable is accessed
(required buildtime bytecode instrumentation). This approach is
rarely necessary.
</para>
</listitem>
</itemizedlist>
<para>
We have two orthogonal notions here: <emphasis>when</emphasis> is the association
fetched, and <emphasis>how</emphasis> is it fetched (what SQL is used). Don't
confuse them! We use <literal>fetch</literal> to tune performance. We may use
<literal>lazy</literal> to define a contract for what data is always available
in any detached instance of a particular class.
</para>
<sect2 id="performance-fetching-lazy">
<title>Working with lazy associations</title>
<para>
By default, Hibernate3 uses lazy select fetching for collections and lazy proxy
fetching for single-valued associations. These defaults make sense for almost
all associations in almost all applications.
</para>
<para>
<emphasis>Note:</emphasis> if you set
<literal>hibernate.default_batch_fetch_size</literal>, Hibernate will use the
batch fetch optimization for lazy fetching (this optimization may also be enabled
at a more granular level).
</para>
<para>
However, lazy fetching poses one problem that you must be aware of. Access to a
lazy association outside of the context of an open Hibernate session will result
in an exception. For example:
</para>
<programlisting><![CDATA[s = sessions.openSession();
Transaction tx = s.beginTransaction();
User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();
tx.commit();
@ -77,40 +128,41 @@ s.close();
Integer accessLevel = (Integer) permissions.get("accounts"); // Error!]]></programlisting>
<para>
Since the permissions collection was not
initialized when the <literal>Session</literal> was closed, the collection
will not be able to load its state. <emphasis>Hibernate does not support lazy
initialization for detached objects</emphasis>. The fix is to move the
code that reads from the collection to just before the commit. (There are
other more advanced ways to solve this problem, some are discussed later.)
</para>
<para>
It is also possible to use a non-lazy collection or join fetching, which is
non-lazy by nature. However, it is intended that lazy initialization be used
for almost all collections, especially for collections of entity references.
If you define too many non-lazy associations in your object model, Hibernate
will end up needing to fetch the entire database into memory in every
transaction!
</para>
<para>
On the other hand, we often want to choose join fetching (which is non-lazy by
nature) instead of select fetching in a particular transaction. We'll now see
how to customize the fetching strategy. In Hibernate3, the mechanisms for
choosing a fetch strategy are identical for single-valued associations and
collections.
</para>
<para>
Since the permissions collection was not initialized when the
<literal>Session</literal> was closed, the collection will not be able to
load its state. <emphasis>Hibernate does not support lazy initialization
for detached objects</emphasis>. The fix is to move the code that reads
from the collection to just before the transaction is committed.
</para>
<para>
Alternatively, we could use a non-lazy collection or association,
by specifying <literal>lazy="false"</literal> for the association mapping.
However, it is intended that lazy initialization be used for almost all
collections and associations. If you define too many non-lazy associations
in your object model, Hibernate will end up needing to fetch the entire
database into memory in every transaction!
</para>
<para>
On the other hand, we often want to choose join fetching (which is non-lazy by
nature) instead of select fetching in a particular transaction. We'll now see
how to customize the fetching strategy. In Hibernate3, the mechanisms for
choosing a fetch strategy are identical for single-valued associations and
collections.
</para>
</sect2>
<sect2 id="performance-fetching-custom" revision="3">
<title>Tuning fetch strategies</title>
<para>
Select fetching (the default) is extremely vulnerable to N+1 selects problems,
so we might want to enable join fetching in the mapping document:
</para>
<para>
Select fetching (the default) is extremely vulnerable to N+1 selects problems,
so we might want to enable join fetching in the mapping document:
</para>
<programlisting><![CDATA[<set name="permissions"
fetch="join">
<key column="userId"/>
@ -142,10 +194,10 @@ Integer accessLevel = (Integer) permissions.get("accounts"); // Error!]]></prog
</listitem>
</itemizedlist>
<para>
<emphasis>Specifying <literal>join</literal> as the fetch strategy in the mapping
document does not affect HQL queries.</emphasis>
</para>
<para>
<emphasis>Specifying <literal>join</literal> as the fetch strategy in the mapping
document does not affect HQL queries.</emphasis>
</para>
<para>
Usually, we don't use the mapping document to customize fetching. Instead, we
@ -157,16 +209,16 @@ Integer accessLevel = (Integer) permissions.get("accounts"); // Error!]]></prog
</para>
<para>
If you ever feel like you wish you could change the fetching strategy used by
<literal>get()</literal> or <literal>load()</literal>, simply use a
<literal>Criteria</literal> query, for example:
If you ever feel like you wish you could change the fetching strategy used by
<literal>get()</literal> or <literal>load()</literal>, simply use a
<literal>Criteria</literal> query, for example:
</para>
<programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
.setFetchMode("permissions", FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
.uniqueResult();]]></programlisting>
.setFetchMode("permissions", FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
.uniqueResult();]]></programlisting>
<para>
(This is Hibernate's equivalent of what some ORM solutions call a "fetch plan".)
</para>