Updated docs for getCurrentSession()

git-svn-id: https://svn.jboss.org/repos/hibernate/trunk/Hibernate3/doc@8370 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Christian Bauer 2005-10-07 13:29:07 +00:00
parent fe92abb60e
commit 892a818878
5 changed files with 390 additions and 364 deletions

View File

@ -2,7 +2,6 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
"../support/docbook-dtd/docbookx.dtd"
[
<!ENTITY quickstart SYSTEM "modules/quickstart.xml">
<!ENTITY tutorial SYSTEM "modules/tutorial.xml">
<!ENTITY architecture SYSTEM "modules/architecture.xml">
<!ENTITY configuration SYSTEM "modules/configuration.xml">
@ -75,12 +74,7 @@
<orderedlist>
<listitem>
<para>
Read <xref linkend="quickstart"/> for a 30 minute quickstart, using Tomcat.
</para>
</listitem>
<listitem>
<para>
Read <xref linkend="tutorial"/> for a longer tutorial with more step-by-step
Read <xref linkend="tutorial"/> for a tutorial with step-by-step
instructions.
</para>
</listitem>
@ -148,8 +142,6 @@
</preface>
&quickstart;
&tutorial;
&architecture;

View File

@ -265,76 +265,82 @@
</para>
</sect1>
<sect1 id="architecture-current-session">
<sect1 id="architecture-current-session" revision="1">
<title>Contextual Sessions</title>
<para>
Most applications using Hibernate need some form of "contextual" sessions, where a given
session is in effect throughout the scope of a given context. However, across applications
the definition of what constitutes a context is typically different; and different contexts
define different scopes to the notion of current. Applications using Hibernate prior
to version 3.0 tended to utilize either home-grown <literal>ThreadLocal</literal>-based
contextual sessions, or utilized third-party frameworks (such as Spring or Pico) which
provided proxy/interception-based contextual sessions.
Most applications using Hibernate need some form of "contextual" sessions, where a given
session is in effect throughout the scope of a given context. However, across applications
the definition of what constitutes a context is typically different; and different contexts
define different scopes to the notion of current. Applications using Hibernate prior
to version 3.0 tended to utilize either home-grown <literal>ThreadLocal</literal>-based
contextual sessions, helper classes such as <literal>HibernateUtil</literal>, or utilized
third-party frameworks (such as Spring or Pico) which provided proxy/interception-based contextual sessions.
</para>
<para>
Starting with version 3.0.1, Hibernate added the <literal>SessionFactory.getCurrentSession()</literal>
method. Initially, this assumed usage of <literal>JTA</literal> transactions, where the
<literal>JTA</literal> transaction defined both the scope and context of a current session.
The Hibernate team maintains that, given the maturity of the numerous stand-alone
<literal>JTA TransactionManager</literal> implementations out there, most (if not all)
applications should be using <literal>JTA</literal> transaction management whether or not
they are deployed into a <literal>J2EE</literal> container. Based on that, the
<literal>JTA</literal>-based contextual sessions is all you should ever need to use.
</para>
<para>
However, we recognize that with the large amounts of FUD out there regarding
<literal>JTA</literal>, such a shift in thinking may be a long time coming to
fruition. Thus, as of version 3.1, the processing behind
<literal>SessionFactory.getCurrentSession()</literal> is now pluggable. To that
end, a new extension interface (<literal>org.hibernate.context.CurrentSessionContext</literal>)
and a new configuration parameter (<literal>hibernate.current_session_context_class</literal>)
have been added to allow pluggability of the scope and context of defining current sessions.
</para>
<para>
See the javadocs for the <literal>org.hibernate.context.CurrentSessionContext</literal>
interface for a detailed discussion of its contract. It defines a single method,
<literal>currentSession()</literal>, by which the implementation is responsible for
tracking the current contextual session. Out-of-the-box, Hibernate comes with two
implementations of this interface.
</para>
<itemizedlist>
<listitem>
<para>
<literal>org.hibernate.context.JTASessionContext</literal> - current sessions
are tracked and scoped by a <literal>JTA</literal> transaction. The processing
here is exactly the same as in the older JTA-only approach. See the javadocs
for details.
</para>
</listitem>
<listitem>
<para>
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> - current
sessions are tracked by thread of execution. Again, see the javadocs for details.
However, it is important to point out that when using threads as the context
mechanism, there is no clearly defined notion of scoping. Threads, unlike
<literal>JTA</literal> transactions, do not emit completion notifications; and
even worse is the fact that many, many environments actually pool and re-use
threads. Thus user of the <literal>ThreadLocalSessionContext</literal> are
expected to manually call the static bind and unbind methods to manually
demarcate context boundaries.
</para>
</listitem>
</itemizedlist>
<para>
The <literal>hibernate.current_session_context_class</literal> configuration parameter
defines which <literal>org.hibernate.context.CurrentSessionContext</literal> implementation
should be used. Note that for backwards compatibility, if this config param is not set
but a <literal>org.hibernate.transaction.TransactionManagerLookup</literal> is configured,
Hibernate will use the <literal>org.hibernate.context.JTASessionContext</literal>.
Typically, the value of this parameter would just name the implementation class to
use; for the two out-of-the-box implementations, however, there are two corresponding
short names, "jta" and "thread".
</para>
<para>
Starting with version 3.0.1, Hibernate added the <literal>SessionFactory.getCurrentSession()</literal>
method. Initially, this assumed usage of <literal>JTA</literal> transactions, where the
<literal>JTA</literal> transaction defined both the scope and context of a current session.
The Hibernate team maintains that, given the maturity of the numerous stand-alone
<literal>JTA TransactionManager</literal> implementations out there, most (if not all)
applications should be using <literal>JTA</literal> transaction management whether or not
they are deployed into a <literal>J2EE</literal> container. Based on that, the
<literal>JTA</literal>-based contextual sessions is all you should ever need to use.
</para>
<para>
However, as of version 3.1, the processing behind
<literal>SessionFactory.getCurrentSession()</literal> is now pluggable. To that
end, a new extension interface (<literal>org.hibernate.context.CurrentSessionContext</literal>)
and a new configuration parameter (<literal>hibernate.current_session_context_class</literal>)
have been added to allow pluggability of the scope and context of defining current sessions.
</para>
<para>
See the Javadocs for the <literal>org.hibernate.context.CurrentSessionContext</literal>
interface for a detailed discussion of its contract. It defines a single method,
<literal>currentSession()</literal>, by which the implementation is responsible for
tracking the current contextual session. Out-of-the-box, Hibernate comes with two
implementations of this interface.
</para>
<itemizedlist>
<listitem>
<para>
<literal>org.hibernate.context.JTASessionContext</literal> - current sessions
are tracked and scoped by a <literal>JTA</literal> transaction. The processing
here is exactly the same as in the older JTA-only approach. See the Javadocs
for details.
</para>
</listitem>
<listitem>
<para>
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> - current
sessions are tracked by thread of execution. Again, see the Javadocs for details.
</para>
</listitem>
</itemizedlist>
<para>
Both implementations provide a "one session - one database transaction" programming
model, also known and used as <emphasis>session-per-request</emphasis>. The beginning
and end of a Hibernate session is defined by the duration of a database transaction.
If you use programatic transaction demarcation (e.g. in pure J2SE or with
JTA/UserTransaction/BMT), you are adviced to use the Hibernate <literal>Transaction</literal>
API to hide the underlying transaction system from your code. If you execute in
an EJB container that supports CMT, transaction boundaries are defined declaratively
and you don't need any transaction or session demarcation operations in your code.
Refer to <xref linkend="transactions"/> for more information and code examples.
</para>
<para>
The <literal>hibernate.current_session_context_class</literal> configuration parameter
defines which <literal>org.hibernate.context.CurrentSessionContext</literal> implementation
should be used. Note that for backwards compatibility, if this config param is not set
but a <literal>org.hibernate.transaction.TransactionManagerLookup</literal> is configured,
Hibernate will use the <literal>org.hibernate.context.JTASessionContext</literal>.
Typically, the value of this parameter would just name the implementation class to
use; for the two out-of-the-box implementations, however, there are two corresponding
short names, "jta" and "thread".
</para>
</sect1>
</chapter>

View File

@ -832,7 +832,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</tgroup>
</table>
<table frame="topbot" id="configuration-transaction-properties" revision="8">
<table frame="topbot" id="configuration-transaction-properties" revision="9">
<title>Hibernate Transaction Properties</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*"/>
@ -892,8 +892,9 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</entry>
<entry>
If enabled, the session will be automatically flushed during the
before completion phase of the transaction. (Very useful when
using Hibernate with CMT.)
before completion phase of the transaction. Built-in and
automatic session context management is preferred, see
<xref linkend="architecture-current-session"/>.
<para>
<emphasis role="strong">eg.</emphasis>
<literal>true</literal> | <literal>false</literal>
@ -906,8 +907,9 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</entry>
<entry>
If enabled, the session will be automatically closed during the
after completion phase of the transaction. (Very useful when
using Hibernate with CMT.)
after completion phase of the transaction. Built-in and
utomatic session context management is preferred, see
<xref linkend="architecture-current-session"/>.
<para>
<emphasis role="strong">eg.</emphasis>
<literal>true</literal> | <literal>false</literal>
@ -918,7 +920,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</tgroup>
</table>
<table frame="topbot" id="configuration-misc-properties" revision="8">
<table frame="topbot" id="configuration-misc-properties" revision="9">
<title>Miscellaneous Properties</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*"/>
@ -930,6 +932,22 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</row>
</thead>
<tbody>
<row>
<entry>
<literal>hibernate.current_session_context_class</literal>
</entry>
<entry>
Supply a (custom) strategy for the scoping of the "current"
<literal>Session</literal>. See
<xref linkend="architecture-current-session"/> for more
information about the built-in strategies.
<para>
<emphasis role="strong">eg.</emphasis>
<literal>jta</literal> | <literal>thread</literal> |
<literal>custom.Class</literal>
</para>
</entry>
</row>
<row>
<entry>
<literal>hibernate.query.factory_class</literal>
@ -1415,11 +1433,11 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<listitem>
<para>
<emphasis>JTA Session binding:</emphasis> The Hibernate <literal>Session</literal>
may be automatically bound to the scope of JTA transactions if you use EJBs. Simply
may be automatically bound to the scope of JTA transactions. Simply
lookup the <literal>SessionFactory</literal> from JNDI and get the current
<literal>Session</literal>. Let Hibernate take care of flushing and closing the
<literal>Session</literal> when your JTA transaction completes. Transaction
demarcation is declarative, in EJB deployment descriptors.
demarcation is either declarative (CMT) or programmatic (BMT/UserTransaction).
</para>
</listitem>
</itemizedlist>
@ -1496,7 +1514,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</para>
<para>
Some features in Hibernate (i.e. the second level cache, automatic JTA and Session binding, etc.)
Some features in Hibernate (i.e. the second level cache, Contextual Sessions with JTA, etc.)
require access to the JTA <literal>TransactionManager</literal> in a managed environment.
In an application server you have to specify how Hibernate should obtain a reference to the
<literal>TransactionManager</literal>, since J2EE does not standardize a single mechanism:
@ -1560,7 +1578,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</sect2>
<sect2 id="configuration-optional-jndi" revision="2">
<sect2 id="configuration-optional-jndi" revision="3">
<title>JNDI-bound <literal>SessionFactory</literal></title>
<para>
@ -1594,46 +1612,41 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<para>
If you use a JNDI <literal>SessionFactory</literal>, an EJB or any other class may
obtain the <literal>SessionFactory</literal> using a JNDI lookup. Note that this
setup is not neccessary if you use the <literal>HibernateUtil</literal> helper class
introduced in chapter one, which acts as a Singleton registry. However,
<literal>HibernateUtil</literal> is more common in a non-managed environment.
obtain the <literal>SessionFactory</literal> using a JNDI lookup.
</para>
<para>
We recommend that you bind the <literal>SessionFactory</literal> to JNDI in
a managend environment and use a <literal>static</literal> singleton otherwise.
To shield your application code from these details, we also recommend to hide the
actual lookup code for a <literal>SessionFactory</literal> in a helper class,
such as <literal>HibernateUtil.getSessionFactory()</literal>. Note that such a
class is also a convenient way to startup Hibernate&mdash;see chapter 1.
</para>
</sect2>
<sect2 id="configuration-j2ee-currentsession" revision="3">
<title>Automatic JTA and Session binding</title>
<sect2 id="configuration-j2ee-currentsession" revision="4">
<title>Current Session context management with JTA</title>
<para>
We recommend that you bind the <literal>SessionFactory</literal> to JNDI in
a managend environment. For transaction and <literal>Session</literal> handling,
you could use the already introduced <literal>HibernateUtil</literal> helper class.
However, EJBs might not execute in the same thread, which makes <literal>ThreadLocal</literal>
handling not always appropriate (e.g. when two session beans call each other).
</para>
<para>
Instead of rolling your own <literal>ThreadLocal</literal> utility, we also recommend
use of the <literal>getCurrentSession()</literal> method on <literal>SessionFactory</literal>
to obtain a Hibernate <literal>Session</literal>. See the discussion of
<xref linkend="architecture-current-session">current sessions</xref>. Using the
<literal>"jta"</literal> session context, if there is no Hibernate
The easiest way to handle <literal>Session</literal>s and transactions is
Hibernates automatic "current" <literal>Session</literal> management.
See the discussion of <xref linkend="architecture-current-session">current sessions</xref>.
Using the <literal>"jta"</literal> session context, if there is no Hibernate
<literal>Session</literal> associated with the current JTA transaction, one will
be started and associated with that JTA transaction. The <literal>Session</literal>s
be started and associated with that JTA transaction the first time you call
<literal>sessionFactory.getCurrentSession()</literal>. The <literal>Session</literal>s
retrieved via <literal>getCurrentSession()</literal> in <literal>"jta"</literal> context
will be set to automatically flush before the transaction completes, close
after the transaction completes, and aggressively release JDBC connections
after each statement. This allows the <literal>Session</literal>s to
be managed by the lifecycle of the JTA transaction to which it is associated,
keeping user code clean of such management concerns.
</para>
<para>
If you, for example, use the DAO design pattern to write your persistence layer,
all DAO's lookup the <literal>SessionFactory</literal> when needed and retrieve the
"current" Session. There is no need to pass instances of <literal>SessionFactory</literal>
or <literal>Session</literal> around between controlling code and DAO code.
keeping user code clean of such management concerns. Your code can either use
JTA programmatically through <literal>UserTransaction</literal>, or (recommended
for portable code) use the Hibernate <literal>Transaction</literal> API to set
transaction boundaries. If you run in an EJB container, declarative transaction
demarcation with CMT is preferred.
</para>
</sect2>

View File

@ -1,4 +1,4 @@
<chapter id="transactions" revision="1">
<chapter id="transactions" revision="2">
<title>Transactions And Concurrency</title>
<para>
@ -6,24 +6,30 @@
easy to understand. Hibernate directly uses JDBC connections and JTA resources without
adding any additional locking behavior. We highly recommend you spend some time with the
JDBC, ANSI, and transaction isolation specification of your database management system.
Hibernate only adds automatic versioning but does not lock objects in memory or change the
isolation level of your database transactions. Basically, use Hibernate like you would
use direct JDBC (or JTA/CMT) with your database resources.
</para>
<para>
However, in addition to automatic versioning, Hibernate also offers a (minor) API for
pessimistic locking of rows, using the <literal>SELECT FOR UPDATE</literal> syntax. This API
is discussed later in this chapter.
Hibernate does not lock objects in memory. Your application can expect the behavior as
defined by the isolation level of your database transactions. Note that thanks to the
<literal>Session</literal>, which is also a transaction-scoped cache, Hibernate
provides repeatable reads for lookup by identifier and entity queries (not
reporting queries that return scalar values).
</para>
<para>
In addition to versioning for automatic optimistic concurrency control, Hibernate also
offers a (minor) API for pessimistic locking of rows, using the
<literal>SELECT FOR UPDATE</literal> syntax. Optimistic concurrency control and
this API are discussed later in this chapter.
</para>
<para>
We start the discussion of concurrency control in Hibernate with the granularity of
<literal>Configuration</literal>, <literal>SessionFactory</literal>, and
<literal>Session</literal>, as well as database and long application transactions.
<literal>Session</literal>, as well as database transactions and long conversations.
</para>
<sect1 id="transactions-basics">
<sect1 id="transactions-basics" revision="1">
<title>Session and transaction scopes</title>
<para>
@ -34,19 +40,19 @@
<para>
A <literal>Session</literal> is an inexpensive, non-threadsafe object that should be
used once, for a single business process, a single unit of work, and then discarded.
used once, for a single request, a conversation, single unit of work, and then discarded.
A <literal>Session</literal> will not obtain a JDBC <literal>Connection</literal>
(or a <literal>Datasource</literal>) unless it is needed, so you may safely open
and close a <literal>Session</literal> even if you are not sure that data access will
be needed to serve a particular request. (This becomes important as soon as you are
implementing some of the following patterns using request interception.)
(or a <literal>Datasource</literal>) unless it is needed, hence consume no
resources until used.
</para>
<para>
To complete this picture you also have to think about database transactions. A
database transaction has to be as short as possible, to reduce lock contention in
the database. Long database transactions will prevent your application from scaling
to highly concurrent load.
to highly concurrent load. Hence, it is almost never good design to hold a
database transaction open during user think time, until the unit of work is
complete.
</para>
<para>
@ -67,7 +73,12 @@
units of work. (Note that this also means that auto-commit after every single
SQL statement is useless in an application, this mode is intended for ad-hoc SQL
console work. Hibernate disables, or expects the application server to do so,
auto-commit mode immediately.)
auto-commit mode immediately.) Database transactions are never optional, all
communication with a database has to occur inside a transaction, no matter if
you read or write data. As explained, auto-commit behavior for reading data
should be avoided, as many small transactions are unlikely to perform better than
one clearly defined unit of work. The latter is also much more maintainable
and extensible.
</para>
<para>
@ -83,24 +94,42 @@
</para>
<para>
The challenge lies in the implementation: not only has the <literal>Session</literal>
and transaction to be started and ended correctly, but they also have to be accessible for
data access operations. The demarcation of a unit of work is ideally implemented using an
interceptor that runs when a request hits the server and before the response will be send (i.e.
a <literal>ServletFilter</literal>). We recommend to bind the <literal>Session</literal> to
the thread that serves the request, using a <literal>ThreadLocal</literal> variable. This allows
easy access (like accessing a static variable) in all code that runs in this thread. Depending
on the database transaction demarcation mechanism you chose, you might also keep the transaction
context in a <literal>ThreadLocal</literal> variable. The implementation patterns for this
are known as <emphasis>ThreadLocal Session</emphasis> and <emphasis>Open Session in View</emphasis>
and can be found on the Hibernate Wiki. Of course, you'd have to find a way to implement an
interceptor and set it up in your environment. See the Hibernate website for tips and examples.
The challenge lies in the implementation. Hibernate provides built-in management of
the "current session" to simplify this pattern. All you have to do is start a
transaction when a server request has to be processed, and end the transaction
before the response is send to the client. You can do this in any way you
like, common solutions are <literal>ServletFilter</literal>, AOP interceptor with a
pointcut on the service methods, or a proxy/interception container. An EJB container
is a standardized way to implement cross-cutting aspects such as transaction
demarcation on EJB session beans, declaratively with CMT. If you decide to
use programmatic transaction demarcation, prefer the Hibernate <literal>Transaction</literal>
API shown later in this chapter, for ease of use and code portability.
</para>
<para>
Your application code can access a "current session" to process the request
by simply calling <literal>sessionFactory.getCurrentSession()</literal> anywhere
and as often as needed. You will always get a <literal>Session</literal> scoped
to the current database transaction. This has to be configured for either
resource-local or JTA environments, see <xref linkend="architecture-current-session"/>.
</para>
<para>
Sometimes it is convenient to extend the scope of a <literal>Session</literal> and
database transaction until the "view has been rendered". This is especially useful
in servlet applications that utilize a separate rendering phase after the request
has been processed. Extending the database transaction until view rendering is
complete is easy to do if you implement your own interceptor. However, it is not
easily doable if you rely on EJBs with container-managed transactions, as a
transaction will be completed when an EJB method returns, before rendering of any
view can start. See the Hibernate website and forum for tips and examples around
this <emphasis>Open Session in View</emphasis> pattern.
</para>
</sect2>
<sect2 id="transactions-basics-apptx">
<title>Application transactions</title>
<sect2 id="transactions-basics-apptx" revision="1">
<title>Long conversations</title>
<para>
The session-per-request pattern is not the only useful concept you can use to design
@ -129,8 +158,8 @@
<para>
We call this unit of work, from the point of view of the user, a long running
<emphasis>application transaction</emphasis>. There are many ways how you can implement
this in your application.
<emphasis>conversation</emphasis> (or <emphasis>application transaction</emphasis>).
There are many ways how you can implement this in your application.
</para>
<para>
@ -142,9 +171,9 @@
</para>
<para>
Clearly, we have to use several database transactions to implement the application
transaction. In this case, maintaining isolation of business processes becomes the
partial responsibility of the application tier. A single application transaction
Clearly, we have to use several database transactions to implement the converastion.
In this case, maintaining isolation of business processes becomes the
partial responsibility of the application tier. A single conversation
usually spans several database transactions. It will be atomic if only one of
these database transactions (the last one) stores the updated data, all others
simply read data (e.g. in a wizard-style dialog spanning several request/response
@ -157,7 +186,8 @@
<para>
<emphasis>Automatic Versioning</emphasis> - Hibernate can do automatic
optimistic concurrency control for you, it can automatically detect
if a concurrent modification occured during user think time.
if a concurrent modification occured during user think time. Usually
we only check at the end of the conversation.
</para>
</listitem>
<listitem>
@ -172,19 +202,21 @@
</listitem>
<listitem>
<para>
<emphasis>Long Session</emphasis> - The Hibernate <literal>Session</literal> may
be disconnected from the underlying JDBC connection after the database transaction
has been committed, and reconnected when a new client request occurs. This pattern
is known as <emphasis>session-per-application-transaction</emphasis> and makes
<emphasis>Extended (or Long) Session</emphasis> - The Hibernate
<literal>Session</literal> may be disconnected from the underlying JDBC
connection after the database transaction has been committed, and reconnected
when a new client request occurs. This pattern is known as
<emphasis>session-per-conversation</emphasis> and makes
even reattachment unnecessary. Automatic versioning is used to isolate
concurrent modifications.
concurrent modifications and the <literal>Session</literal> is usually
not allowed to be flushed automatically, but explicitely.
</para>
</listitem>
</itemizedlist>
<para>
Both <emphasis>session-per-request-with-detached-objects</emphasis> and
<emphasis>session-per-application-transaction</emphasis> have advantages and disadvantages,
<emphasis>session-per-conversation</emphasis> have advantages and disadvantages,
we discuss them later in this chapter in the context of optimistic concurrency control.
</para>
@ -317,7 +349,9 @@
the database can occur outside of a database transaction (this seems to confuse many developers
who are used to the auto-commit mode). Always use clear transaction boundaries, even for
read-only operations. Depending on your isolation level and database capabilities this might not
be required but there is no downside if you always demarcate transactions explicitly.
be required but there is no downside if you always demarcate transactions explicitly. Certainly,
a single database transaction is going to perform better than many small transactions, even
for reading data.
</para>
<para>
@ -325,13 +359,15 @@
and managed J2EE environments. In a non-managed environment, Hibernate is usually responsible for
its own database connection pool. The application developer has to manually set transaction
boundaries, in other words, begin, commit, or rollback database transactions himself. A managed environment
usually provides container-managed transactions, with the transaction assembly defined declaratively
usually provides container-managed transactions (CMT), with the transaction assembly defined declaratively
in deployment descriptors of EJB session beans, for example. Programmatic transaction demarcation is
then no longer necessary, even flushing the <literal>Session</literal> is done automatically.
then no longer necessary.
</para>
<para>
However, it is often desirable to keep your persistence layer portable. Hibernate offers a wrapper
However, it is often desirable to keep your persistence layer portable between non-managed
resource-local environments, and systems that can rely on JTA but use BMT instead of CMT.
In both cases you'd use programmatic transaction demaracation. Hibernate offers a wrapper
API called <literal>Transaction</literal> that translates into the native transaction system of
your deployment environment. This API is actually optional, but we strongly encourage its use
unless you are in a CMT session bean.
@ -370,7 +406,7 @@
</para>
<sect2 id="transactions-demarcation-nonmanaged">
<sect2 id="transactions-demarcation-nonmanaged" revision="1">
<title>Non-managed environment</title>
<para>
@ -398,63 +434,52 @@ finally {
sess.close();
}]]></programlisting>
<para>
Or even like this:
<para>
You don't have to <literal>flush()</literal> the <literal>Session</literal> explicitly -
the call to <literal>commit()</literal> automatically triggers the synchronization.
A call to <literal>close()</literal> marks the end of a session. The main implication
of <literal>close()</literal> is that the JDBC connection will be relinquished by the
session. This Java code is portable and runs in both non-managed and JTA environments.
</para>
<programlisting><![CDATA[// Non-managed environment idiom
Session sess = factory.openSession();
<para>
A much more flexible solution is Hibernate's built-in "current session" context
management, as described earlier:
</para>
<programlisting><![CDATA[// Non-managed environment idiom with getCurrentSession()
try {
sess.getTransaction().begin();
factory.getCurrentSession().beginTransaction();
// do some work
...
sess.getTransaction().commit()
factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
if ( sess.getTransaction().isActive() ) {
sess.getTransaction().rollback();
}
factory.getCurrentSession().getTransaction().rollback();
throw e; // or display error message
}
finally {
sess.close();
}]]></programlisting>
<para>
You don't have to <literal>flush()</literal> the <literal>Session</literal> explicitly -
the call to <literal>commit()</literal> automatically triggers the synchronization.
</para>
<para>
A call to <literal>close()</literal> marks the end of a session. The main implication
of <literal>close()</literal> is that the JDBC connection will be relinquished by the
session.
</para>
<para>
This Java code is portable and runs in both non-managed and JTA environments.
</para>
<para>
You will very likely never see this idiom in business code in a normal application;
You will very likely never see these code snippets in a regular application;
fatal (system) exceptions should always be caught at the "top". In other words, the
code that executes Hibernate calls (in the persistence layer) and the code that handles
<literal>RuntimeException</literal> (and usually can only clean up and exit) are in
different layers. This can be a challenge to design yourself and you should use J2EE/EJB
container services whenever they are available. Exception handling is discussed later in
this chapter.
different layers. The current context management by Hibernate can significantly
simplify this design, as all you need is access to a <literal>SessionFactory</literal>.
Exception handling is discussed later in this chapter.
</para>
<para>
Note that you should select <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
(which is the default).
(which is the default), and for the second example <literal>"thread"</literal> as your
<literal>hibernate.current_session_context_class</literal>.
</para>
</sect2>
<sect2 id="transactions-demarcation-jta" revision="1">
<sect2 id="transactions-demarcation-jta" revision="2">
<title>Using JTA</title>
<para>
@ -489,83 +514,56 @@ finally {
}]]></programlisting>
<para>
Or:
Or with automatic session context management:
</para>
<programlisting><![CDATA[// BMT idiom
Session sess = factory.openSession();
<programlisting><![CDATA[// BMT idiom with getCurrentSession()
try {
sess.getTransaction().begin();
factory.getCurrentSession().beginTransaction();
// do some work
...
sess.getTransaction().commit()
factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
if ( sess.getTransaction().isActive() ) {
sess.getTransaction().rollback();
}
factory.getCurrentSession().getTransaction().rollback();
throw e; // or display error message
}
finally {
sess.close();
}]]></programlisting>
<para>
With CMT, transaction demarcation is done in session bean deployment descriptors, not programatically.
If you don't want to manually flush and close the <literal>Session</literal> yourself, just set
<literal>hibernate.transaction.flush_before_completion</literal> to <literal>true</literal>,
<literal>hibernate.connection.release_mode</literal> to <literal>after_statement</literal> or
<literal>auto</literal> and <literal>hibernate.transaction.auto_close_session</literal> to
<literal>true</literal>. Hibernate will then automatically flush and close the <literal>Session</literal>
for you. The only thing left is to rollback the transaction when an exception occurs. Fortunately, in a
CMT bean, even this happens automatically, since an unhandled <literal>RuntimeException</literal> thrown
by a session bean method tells the container to set the global transaction to rollback. <emphasis>This
means you do not need to use the Hibernate <literal>Transaction</literal> API at all in CMT.</emphasis>
With CMT, transaction demarcation is done in session bean deployment descriptors, not programatically,
hence, the code is reduced to:
</para>
<programlisting><![CDATA[// CMT idiom
Session sess = factory.getCurrentSession();
// do some work
...
]]></programlisting>
<para>
In a CMT?EJB even rollback happens automatically, since an unhandled <literal>RuntimeException</literal>
thrown by a session bean method tells the container to set the global transaction to rollback.
<emphasis>This means you do not need to use the Hibernate <literal>Transaction</literal> API at
all in CMT.</emphasis>
</para>
<para>
Note that you should choose <literal>org.hibernate.transaction.JTATransactionFactory</literal>
in a BMT session bean, and <literal>org.hibernate.transaction.CMTTransactionFactory</literal>
in a CMT session bean, when you configure Hibernate's transaction factory. Remember to also set
<literal>org.hibernate.transaction.manager_lookup_class</literal>.
<literal>hibernate.transaction.manager_lookup_class</literal>. Furthermore, make sure
that your <literal>hibernate.current_session_context_class</literal> is either unset (backwards
compatiblity), or set to <literal>"jta"</literal>.
</para>
<para>
If you work in a JTA environment, and use automatic flushing and closing of the session, you
might also want to use the same session in different parts of your code. Typically, in a non-managed
environment you would use a <literal>ThreadLocal</literal> variable to hold the session, but a
single EJB request might execute in different threads (e.g. session bean calling another session bean).
If you don't want to bother passing your <literal>Session</literal> instance around, the
<literal>SessionFactory</literal> provides the <literal>getCurrentSession()</literal>
method, which returns a session that is bound to the JTA transaction context (see discussion of
<xref linkend="architecture-current-session">current sessions</xref>). This is the
easiest way to integrate Hibernate into an application! The "current" session always has
auto-flush, auto-close and auto-connection-release enabled (regardless of the above property
settings). Our session/transaction management idiom is reduced to this:
</para>
<programlisting><![CDATA[// CMT idiom
Session sess = factory.getCurrentSession();
// do some work
...
]]></programlisting>
<para>
In other words, all you have to do in a managed environment is call
<literal>SessionFactory.getCurrentSession()</literal>, do your data access work, and leave
the rest to the container. Transaction boundaries are set declaratively in the deployment
descriptors of your session bean. The lifecycle of the session is completely managed by
Hibernate.
</para>
<para>
The <literal>getCurrentSession()</literal> operation has one downside in a JTA environment.
There is one caveat to the use of <literal>after_statement</literal> connection release
mode. Due to a silly limitation of the JTA spec, it is not possible for Hibernate to
automatically clean up any unclosed <literal>ScrollableResults</literal> or
mode, which is then used by default. Due to a silly limitation of the JTA spec, it is not
possible for Hibernate to automatically clean up any unclosed <literal>ScrollableResults</literal> or
<literal>Iterator</literal> instances returned by <literal>scroll()</literal> or
<literal>iterate()</literal>. You <emphasis>must</emphasis> release the underlying database
cursor by calling <literal>ScrollableResults.close()</literal> or
@ -680,9 +678,7 @@ try {
sess.getTransaction().commit()
}
catch (RuntimeException e) {
if ( sess.getTransaction().isActive() ) {
sess.getTransaction().rollback();
}
sess.getTransaction().rollback();
throw e; // or display error message
}
finally {
@ -707,7 +703,7 @@ finally {
checking uses version numbers, or timestamps, to detect conflicting updates
(and to prevent lost updates). Hibernate provides for three possible approaches
to writing application code that uses optimistic concurrency. The use cases
we show are in the context of long application transactions but version checking
we show are in the context of long conversations, but version checking
also has the benefit of preventing lost updates in single database transactions.
</para>
@ -719,17 +715,19 @@ finally {
database occurs in a new <literal>Session</literal> and the developer is responsible
for reloading all persistent instances from the database before manipulating them.
This approach forces the application to carry out its own version checking to ensure
application transaction isolation. This approach is the least efficient in terms of
conversation transaction isolation. This approach is the least efficient in terms of
database access. It is the approach most similar to entity EJBs.
</para>
<programlisting><![CDATA[// foo is an instance loaded by a previous Session
session = factory.openSession();
Transaction t = session.beginTransaction();
int oldVersion = foo.getVersion();
session.load( foo, foo.getKey() ); // load the current state
if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
foo.setProperty("bar");
t.commit();
session.close();]]></programlisting>
@ -743,7 +741,7 @@ session.close();]]></programlisting>
Of course, if you are operating in a low-data-concurrency environment and don't
require version checking, you may use this approach and just skip the version
check. In that case, <emphasis>last commit wins</emphasis> will be the default
strategy for your long application transactions. Keep in mind that this might
strategy for your long conversations. Keep in mind that this might
confuse the users of the application, as they might experience lost updates without
error messages or a chance to merge conflicting changes.
</para>
@ -752,22 +750,22 @@ session.close();]]></programlisting>
Clearly, manual version checking is only feasible in very trivial circumstances
and not practical for most applications. Often not only single instances, but
complete graphs of modified ojects have to be checked. Hibernate offers automatic
version checking with either long <literal>Session</literal> or detached instances
version checking with either an extended <literal>Session</literal> or detached instances
as the design paradigm.
</para>
</sect2>
<sect2 id="transactions-optimistic-longsession">
<title>Long session and automatic versioning</title>
<title>Extended session and automatic versioning</title>
<para>
A single <literal>Session</literal> instance and its persistent instances are
used for the whole application transaction. Hibernate checks instance versions
at flush time, throwing an exception if concurrent modification is detected.
It's up to the developer to catch and handle this exception (common options
are the opportunity for the user to merge changes or to restart the business
process with non-stale data).
used for the whole conversation, known as <emphasis>session-per-conversation</emphasis>.
Hibernate checks instance versions at flush time, throwing an exception if concurrent
modification is detected. It's up to the developer to catch and handle this exception
(common options are the opportunity for the user to merge changes or to restart the
business conversation with non-stale data).
</para>
<para>
@ -778,43 +776,58 @@ session.close();]]></programlisting>
database transaction.
</para>
<programlisting><![CDATA[// foo is an instance loaded earlier by the Session
session.reconnect(); // Obtain a new JDBC connection
Transaction t = session.beginTransaction();
foo.setProperty("bar");
t.commit(); // End database transaction, flushing the change and checking the version
session.disconnect(); // Return JDBC connection ]]></programlisting>
<programlisting><![CDATA[// foo is an instance loaded earlier by the old session
Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
foo.setProperty("bar");
session.flush(); // Only for last transaction in conversation
t.commit(); // Also return JDBC connection
session.close(); // Only for last transaction in conversation]]></programlisting>
<para>
The <literal>foo</literal> object still knows which <literal>Session</literal> it was
loaded in. <literal>Session.reconnect()</literal> obtains a new connection (or you
may supply one) and resumes the session. The method <literal>Session.disconnect()</literal>
will disconnect the session from the JDBC connection and return the connection to the pool
(unless you provided the connection). After reconnection, to force a version check on data
you aren't updating, you may call <literal>Session.lock()</literal> with
<literal>LockMode.READ</literal> on any objects that might have been updated by another
loaded in. Beginning a new database transaction on an old session obtains a new connection
and resumes the session. Committing a database transaction disconnects a session
from the JDBC connection and returns the connection to the pool. After reconnection, to
force a version check on data you aren't updating, you may call <literal>Session.lock()</literal>
with <literal>LockMode.READ</literal> on any objects that might have been updated by another
transaction. You don't need to lock any data that you <emphasis>are</emphasis> updating.
Usually you would set <literal>FlushMode.NEVER</literal> on an extended <literal>Session</literal>,
so that only the last database transaction cycle is allowed to actually persist all
modifications made in this conversation. Hence, only this last database transaction
would include the <literal>flush()</literal> operation, and then also
<literal>close()</literal> the session to end the conversation.
</para>
<para>
If the explicit calls to <literal>disconnect()</literal> and <literal>reconnect()</literal>
are too onerous, you may instead use <literal>hibernate.connection.release_mode</literal>.
</para>
<para>
This pattern is problematic if the <literal>Session</literal> is too big to
be stored during user think time, e.g. an <literal>HttpSession</literal> should
be kept as small as possible. As the <literal>Session</literal> is also the
(mandatory) first-level cache and contains all loaded objects, we can probably
use this strategy only for a few request/response cycles. This is indeed
recommended, as the <literal>Session</literal> will soon also have stale data.
use this strategy only for a few request/response cycles. You should use a
<literal>Session</literal> only for a single conversation, as it will soon also
have stale data.
</para>
<para>
(Note that earlier Hibernate versions required explicit disconnection and reconnection
of a <literal>Session</literal>. These methods are deprecated, as beginning and
ending a transaction has the same effect.)
</para>
<para>
Also note that you should keep the disconnected <literal>Session</literal> close
to the persistence layer. In other words, use an EJB stateful session bean to
hold the <literal>Session</literal> and don't transfer it to the web layer (or
even serialize it to a separate tier) to store it in the <literal>HttpSession</literal>.
hold the <literal>Session</literal> in a three-tier environment, and don't transfer
it to the web layer (or even serialize it to a separate tier) to store it in the
<literal>HttpSession</literal>.
</para>
<para>
The extended session pattern, or <emphasis>session-per-conversation</emphasis>, is
more difficult to implement with automatic current session context management.
You need to supply your own implementation of the <literal>CurrentSessionContext</literal>
for this, see the Hibernate Wiki for examples.
</para>
</sect2>

View File

@ -305,7 +305,7 @@ public class Event {
</sect2>
<sect2 id="tutorial-firstapp-configuration">
<sect2 id="tutorial-firstapp-configuration" revision="1">
<title>Hibernate configuration</title>
<para>
@ -355,8 +355,8 @@ public class Event {
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- For a HSQL 1.8 in-memory database, this is required -->
<property name="connection.shutdown">true</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
@ -385,6 +385,8 @@ public class Event {
The first four <literal>property</literal> elements contain the necessary
configuration for the JDBC connection. The dialect <literal>property</literal>
element specifies the particular SQL variant Hibernate generates.
Hibernate's automatic session management for persistence contexts will
come in handy as you will soon see.
The <literal>hbm2ddl.auto</literal> option turns on automatic generation of
database schemas - directly into the database. This can of course also be turned
off (by removing the config option) or redirected to a file with the help of
@ -481,7 +483,7 @@ Total time: 1 second ]]></programlisting>
</sect2>
<sect2 id="tutorial-firstapp-helpers" revision="1">
<sect2 id="tutorial-firstapp-helpers" revision="2">
<title>Startup and helpers</title>
<para>
@ -496,9 +498,8 @@ Total time: 1 second ]]></programlisting>
<para>
We'll create a <literal>HibernateUtil</literal> helper class which takes care
of startup and makes <literal>Session</literal> handling convenient. The so called
<emphasis>ThreadLocal Session</emphasis> pattern is useful here, we keep the current
unit of work associated with the current thread. Let's have a look at the implementation:
of startup and makes accessing a <literal>SessionFactory</literal> convenient.
Let's have a look at the implementation:
</para>
<programlisting><![CDATA[import org.hibernate.*;
@ -506,7 +507,7 @@ import org.hibernate.cfg.*;
public class HibernateUtil {
public static final SessionFactory sessionFactory;
private static final SessionFactory sessionFactory;
static {
try {
@ -519,47 +520,26 @@ public class HibernateUtil {
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session getCurrentSession() throws HibernateException {
Session s = (Session) session.get();
// Open a new Session, if this thread has none yet
if (s == null) {
s = sessionFactory.openSession();
// Store it in the ThreadLocal variable
session.set(s);
}
return s;
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
if (s != null)
s.close();
session.set(null);
}
}]]></programlisting>
<para>
This class does not only produce the global <literal>SessionFactory</literal> in
its static initializer (called once by the JVM when the class is loaded), but also
has a <literal>ThreadLocal</literal> variable to hold the
<literal>Session</literal> for the current thread. No matter when you call
<literal>HibernateUtil.getCurrentSession()</literal>, it will always return the same
Hibernate unit of work in the same thread. A call to <literal>HibernateUtil.closeSession()</literal>
ends the unit of work currently associated with the thread.
hides the fact that it uses a static singleton. It might as well lookup the
<literal>SessionFactory</literal> from JNDI in an application server.
</para>
<para>
Make sure you understand the Java concept of a thread-local variables before you
use this helper. A more powerful <literal>HibernateUtil</literal> helper can be found
in <literal>CaveatEmptor</literal> on http://caveatemptor.hibernate.org/ - as well as
in the book "Hibernate in Action". Note that this class is not necessary if you deploy
Hibernate in a J2EE application server: a <literal>Session</literal> will be
automatically bound to the current JTA transaction and you can look up the
<literal>SessionFactory</literal> through JNDI. If you use JBoss AS, Hibernate can
be deployed as a managed system service and will automatically bind the
<literal>SessionFactory</literal> to a JNDI name.
If you give the <literal>SessionFactory</literal> a name in your configuration
file, Hibernate will in fact try to bind it to JNDI after it has been built.
To avoid this code completely you could also use JMX deployment and let the
JMX-capable container instantiate and bind a <literal>HibernateService</literal>
to JNDI. These advanced options are discussed in the Hibernate reference
documentation.
</para>
<para>
@ -595,7 +575,7 @@ build.xml]]></programlisting>
</sect2>
<sect2 id="tutorial-firstapp-workingpersistence" revision="2">
<sect2 id="tutorial-firstapp-workingpersistence" revision="3">
<title>Loading and storing objects</title>
<para>
@ -617,7 +597,7 @@ public class EventManager {
mgr.createAndStoreEvent("My Event", new Date());
}
HibernateUtil.sessionFactory.close();
HibernateUtil.getSessionFactory().close();
}
}]]></programlisting>
@ -628,17 +608,19 @@ public class EventManager {
</para>
<programlisting><![CDATA[private void createAndStoreEvent(String title, Date theDate) {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
HibernateUtil.getSessionFactory().getCurrentSession()
.beginTransaction();
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
session.save(theEvent);
HibernateUtil.getSessionFactory().getCurrentSession()
.save(theEvent);
tx.commit();
HibernateUtil.closeSession();
HibernateUtil.getSessionFactory().getCurrentSession()
.getTransaction.commit();
}]]></programlisting>
<para>
@ -649,28 +631,40 @@ public class EventManager {
</para>
<para>
A <literal>Session</literal> is a single unit of work. You might be surprised that we
have an additional API, <literal>Transaction</literal>. This implies that a unit of work
can be "longer" than a single database transaction - imagine a unit of work that spans
several Http request/response cycles (e.g. a wizard dialog) in a web application.
Separating database transactions from "unit of work from the application
user's point of view" is one of Hibernates basic design concepts. We call a long
unit of work <emphasis>Application Transaction</emphasis>, usually encapsulating
several short database transactions. For now we'll keep things simple and assume a
one-to-one granularity between a <literal>Session</literal> and <literal>Transaction</literal>.
A <literal>Session</literal> is a single unit of work. For now we'll keep things
simple and assume a one-to-one granularity between a Hibernate <literal>Session</literal>
and a database transaction. To shield our code from the actual underlying transaction
system (in this case plain JDBC, but it could also run with JTA) we use the
<literal>Transaction</literal> API that is available on the Hibernate <literal>Session</literal>.
</para>
<para>
What does <literal>Transaction.begin()</literal> and <literal>commit()</literal> do? Where
is the <literal>rollback()</literal> in case something goes wrong? The Hibernate
<literal>Transaction</literal> API is actually optional, but we use it for convenience
and portability. If you'd handle the database transaction yourself (e.g. by calling
<literal>session.connection.commit()</literal>), you'd bind the code to a particular
deployment environment, in this direct unmanaged JDBC. By setting the factory for
<literal>Transaction</literal> in your Hibernate configuration you can deploy your
persistence layer anywhere. Have a look at <xref linkend="transactions"/> for more information
What does <literal>getCurrentSession()</literal> do and why is it repeated so
often? First, it is repeated in the code example to explain its usage in a real
application: you can call it as many times and anywhere you like, once you get
hold of your <literal>SessionFactory</literal> (easy thanks to <literal>HibernateUtil</literal>).
The <literal>getCurrentSession()</literal> method always returns the "current"
unit of work. Remember that we switched the configuration option for this mechanism
to "thread"? Hence, the scope of the current unit of work is the current Java
thread that executes our application. A <literal>Session</literal> begins when it is
first needed, when the first call to <literal>getCurrentSession()</literal> is made.
It is then bound by Hibernate to the current thread. When the transaction ends,
either committed or rolled back, Hibernate also unbinds the <literal>Session</literal>
from the thread and closes it for you.
</para>
<para>
You could implement your own <literal>Session</literal> management, and open and
close it yourself. Or you could even extend the "current session" mechanism with
your own implementation. However, most Hibernate applications should use the
built-in context handlers, either for thread-bound <literal>Session</literal>s
or, in a managend environment (application server), bound to the JTA transaction.
</para>
<para>
Have a look at <xref linkend="transactions"/> for more information
about transaction handling and demarcation. We also skipped any error handling and
rollback in this example.
rollback in the previous example.
</para>
<para>
@ -725,13 +719,14 @@ else if (args[0].equals("list")) {
</para>
<programlisting><![CDATA[private List listEvents() {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
HibernateUtil.getSessionFactory().getCurrentSession()
.beginTransaction();
List result = session.createQuery("from Event").list();
List result = HibernateUtil.getSessionFactory().getCurrentSession()
.createQuery("from Event").list();
tx.commit();
session.close();
HibernateUtil.getSessionFactory().getCurrentSession()
.getTransaction().commit();
return result;
}]]></programlisting>
@ -845,7 +840,7 @@ else if (args[0].equals("list")) {
</sect2>
<sect2 id="tutorial-associations-unidirset">
<sect2 id="tutorial-associations-unidirset" revision="1">
<title>A unidirectional Set-based association</title>
<para>
@ -937,16 +932,17 @@ else if (args[0].equals("list")) {
</para>
<programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
HibernateUtil.getSessionFactory().getCurrentSession()
.beginTransaction();
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId);
aPerson.getEvents().add(anEvent);
tx.commit();
HibernateUtil.closeSession();
HibernateUtil.getSessionFactory().getCurrentSession()
.getTransaction().commit();
}]]></programlisting>
<para>
@ -971,24 +967,30 @@ else if (args[0].equals("list")) {
<programlisting><![CDATA[ private void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getCurrentSession();
Transaction tx = session.beginTransaction();
HibernateUtil.getSessionFactory().getCurrentSession()
.beginTransaction();
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Person aPerson = (Person) session.load(Person.class, personId);
Event anEvent = (Event) session.load(Event.class, eventId);
tx.commit();
HibernateUtil.closeSession();
HibernateUtil.getSessionFactory().getCurrentSession()
.getTransaction().commit();
// End of first unit of work
aPerson.getEvents().add(anEvent); // aPerson is detached
Session session2 = HibernateUtil.getCurrentSession();
Transaction tx2 = session.beginTransaction();
// Begin second unit of work
HibernateUtil.getSessionFactory().getCurrentSession()
.beginTransaction();
Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.update(aPerson); // Reattachment of aPerson
tx2.commit();
HibernateUtil.closeSession();
HibernateUtil.getSessionFactory().getCurrentSession()
.getTransaction().commit();
}
]]></programlisting>