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:
parent
fe92abb60e
commit
892a818878
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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—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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
Loading…
Reference in New Issue