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

View File

@ -265,7 +265,7 @@
</para> </para>
</sect1> </sect1>
<sect1 id="architecture-current-session"> <sect1 id="architecture-current-session" revision="1">
<title>Contextual Sessions</title> <title>Contextual Sessions</title>
<para> <para>
Most applications using Hibernate need some form of "contextual" sessions, where a given Most applications using Hibernate need some form of "contextual" sessions, where a given
@ -273,8 +273,8 @@
the definition of what constitutes a context is typically different; and different contexts 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 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 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 contextual sessions, helper classes such as <literal>HibernateUtil</literal>, or utilized
provided proxy/interception-based contextual sessions. third-party frameworks (such as Spring or Pico) which provided proxy/interception-based contextual sessions.
</para> </para>
<para> <para>
Starting with version 3.0.1, Hibernate added the <literal>SessionFactory.getCurrentSession()</literal> Starting with version 3.0.1, Hibernate added the <literal>SessionFactory.getCurrentSession()</literal>
@ -287,44 +287,49 @@
<literal>JTA</literal>-based contextual sessions is all you should ever need to use. <literal>JTA</literal>-based contextual sessions is all you should ever need to use.
</para> </para>
<para> <para>
However, we recognize that with the large amounts of FUD out there regarding However, as of version 3.1, the processing behind
<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 <literal>SessionFactory.getCurrentSession()</literal> is now pluggable. To that
end, a new extension interface (<literal>org.hibernate.context.CurrentSessionContext</literal>) end, a new extension interface (<literal>org.hibernate.context.CurrentSessionContext</literal>)
and a new configuration parameter (<literal>hibernate.current_session_context_class</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. have been added to allow pluggability of the scope and context of defining current sessions.
</para> </para>
<para> <para>
See the javadocs for the <literal>org.hibernate.context.CurrentSessionContext</literal> See the Javadocs for the <literal>org.hibernate.context.CurrentSessionContext</literal>
interface for a detailed discussion of its contract. It defines a single method, interface for a detailed discussion of its contract. It defines a single method,
<literal>currentSession()</literal>, by which the implementation is responsible for <literal>currentSession()</literal>, by which the implementation is responsible for
tracking the current contextual session. Out-of-the-box, Hibernate comes with two tracking the current contextual session. Out-of-the-box, Hibernate comes with two
implementations of this interface. implementations of this interface.
</para> </para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
<literal>org.hibernate.context.JTASessionContext</literal> - current sessions <literal>org.hibernate.context.JTASessionContext</literal> - current sessions
are tracked and scoped by a <literal>JTA</literal> transaction. The processing 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 here is exactly the same as in the older JTA-only approach. See the Javadocs
for details. for details.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<literal>org.hibernate.context.ThreadLocalSessionContext</literal> - current <literal>org.hibernate.context.ThreadLocalSessionContext</literal> - current
sessions are tracked by thread of execution. Again, see the javadocs for details. 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> </para>
</listitem> </listitem>
</itemizedlist> </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> <para>
The <literal>hibernate.current_session_context_class</literal> configuration parameter The <literal>hibernate.current_session_context_class</literal> configuration parameter
defines which <literal>org.hibernate.context.CurrentSessionContext</literal> implementation defines which <literal>org.hibernate.context.CurrentSessionContext</literal> implementation
@ -335,6 +340,7 @@
use; for the two out-of-the-box implementations, however, there are two corresponding use; for the two out-of-the-box implementations, however, there are two corresponding
short names, "jta" and "thread". short names, "jta" and "thread".
</para> </para>
</sect1> </sect1>
</chapter> </chapter>

View File

@ -832,7 +832,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</tgroup> </tgroup>
</table> </table>
<table frame="topbot" id="configuration-transaction-properties" revision="8"> <table frame="topbot" id="configuration-transaction-properties" revision="9">
<title>Hibernate Transaction Properties</title> <title>Hibernate Transaction Properties</title>
<tgroup cols="2"> <tgroup cols="2">
<colspec colname="c1" colwidth="1*"/> <colspec colname="c1" colwidth="1*"/>
@ -892,8 +892,9 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</entry> </entry>
<entry> <entry>
If enabled, the session will be automatically flushed during the If enabled, the session will be automatically flushed during the
before completion phase of the transaction. (Very useful when before completion phase of the transaction. Built-in and
using Hibernate with CMT.) automatic session context management is preferred, see
<xref linkend="architecture-current-session"/>.
<para> <para>
<emphasis role="strong">eg.</emphasis> <emphasis role="strong">eg.</emphasis>
<literal>true</literal> | <literal>false</literal> <literal>true</literal> | <literal>false</literal>
@ -906,8 +907,9 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</entry> </entry>
<entry> <entry>
If enabled, the session will be automatically closed during the If enabled, the session will be automatically closed during the
after completion phase of the transaction. (Very useful when after completion phase of the transaction. Built-in and
using Hibernate with CMT.) utomatic session context management is preferred, see
<xref linkend="architecture-current-session"/>.
<para> <para>
<emphasis role="strong">eg.</emphasis> <emphasis role="strong">eg.</emphasis>
<literal>true</literal> | <literal>false</literal> <literal>true</literal> | <literal>false</literal>
@ -918,7 +920,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</tgroup> </tgroup>
</table> </table>
<table frame="topbot" id="configuration-misc-properties" revision="8"> <table frame="topbot" id="configuration-misc-properties" revision="9">
<title>Miscellaneous Properties</title> <title>Miscellaneous Properties</title>
<tgroup cols="2"> <tgroup cols="2">
<colspec colname="c1" colwidth="1*"/> <colspec colname="c1" colwidth="1*"/>
@ -930,6 +932,22 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</row> </row>
</thead> </thead>
<tbody> <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> <row>
<entry> <entry>
<literal>hibernate.query.factory_class</literal> <literal>hibernate.query.factory_class</literal>
@ -1415,11 +1433,11 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<listitem> <listitem>
<para> <para>
<emphasis>JTA Session binding:</emphasis> The Hibernate <literal>Session</literal> <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 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>. Let Hibernate take care of flushing and closing the
<literal>Session</literal> when your JTA transaction completes. Transaction <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> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -1496,7 +1514,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</para> </para>
<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. 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 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: <literal>TransactionManager</literal>, since J2EE does not standardize a single mechanism:
@ -1560,7 +1578,7 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
</sect2> </sect2>
<sect2 id="configuration-optional-jndi" revision="2"> <sect2 id="configuration-optional-jndi" revision="3">
<title>JNDI-bound <literal>SessionFactory</literal></title> <title>JNDI-bound <literal>SessionFactory</literal></title>
<para> <para>
@ -1594,46 +1612,41 @@ hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
<para> <para>
If you use a JNDI <literal>SessionFactory</literal>, an EJB or any other class may 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 obtain the <literal>SessionFactory</literal> using a JNDI lookup.
setup is not neccessary if you use the <literal>HibernateUtil</literal> helper class </para>
introduced in chapter one, which acts as a Singleton registry. However,
<literal>HibernateUtil</literal> is more common in a non-managed environment. <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> </para>
</sect2> </sect2>
<sect2 id="configuration-j2ee-currentsession" revision="3"> <sect2 id="configuration-j2ee-currentsession" revision="4">
<title>Automatic JTA and Session binding</title> <title>Current Session context management with JTA</title>
<para> <para>
We recommend that you bind the <literal>SessionFactory</literal> to JNDI in The easiest way to handle <literal>Session</literal>s and transactions is
a managend environment. For transaction and <literal>Session</literal> handling, Hibernates automatic "current" <literal>Session</literal> management.
you could use the already introduced <literal>HibernateUtil</literal> helper class. See the discussion of <xref linkend="architecture-current-session">current sessions</xref>.
However, EJBs might not execute in the same thread, which makes <literal>ThreadLocal</literal> Using the <literal>"jta"</literal> session context, if there is no Hibernate
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
<literal>Session</literal> associated with the current JTA transaction, one will <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 retrieved via <literal>getCurrentSession()</literal> in <literal>"jta"</literal> context
will be set to automatically flush before the transaction completes, close will be set to automatically flush before the transaction completes, close
after the transaction completes, and aggressively release JDBC connections after the transaction completes, and aggressively release JDBC connections
after each statement. This allows the <literal>Session</literal>s to 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, be managed by the lifecycle of the JTA transaction to which it is associated,
keeping user code clean of such management concerns. keeping user code clean of such management concerns. Your code can either use
</para> JTA programmatically through <literal>UserTransaction</literal>, or (recommended
for portable code) use the Hibernate <literal>Transaction</literal> API to set
<para> transaction boundaries. If you run in an EJB container, declarative transaction
If you, for example, use the DAO design pattern to write your persistence layer, demarcation with CMT is preferred.
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.
</para> </para>
</sect2> </sect2>

View File

@ -1,4 +1,4 @@
<chapter id="transactions" revision="1"> <chapter id="transactions" revision="2">
<title>Transactions And Concurrency</title> <title>Transactions And Concurrency</title>
<para> <para>
@ -6,24 +6,30 @@
easy to understand. Hibernate directly uses JDBC connections and JTA resources without 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 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. 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>
<para> <para>
However, in addition to automatic versioning, Hibernate also offers a (minor) API for Hibernate does not lock objects in memory. Your application can expect the behavior as
pessimistic locking of rows, using the <literal>SELECT FOR UPDATE</literal> syntax. This API defined by the isolation level of your database transactions. Note that thanks to the
is discussed later in this chapter. <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>
<para> <para>
We start the discussion of concurrency control in Hibernate with the granularity of We start the discussion of concurrency control in Hibernate with the granularity of
<literal>Configuration</literal>, <literal>SessionFactory</literal>, and <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> </para>
<sect1 id="transactions-basics"> <sect1 id="transactions-basics" revision="1">
<title>Session and transaction scopes</title> <title>Session and transaction scopes</title>
<para> <para>
@ -34,19 +40,19 @@
<para> <para>
A <literal>Session</literal> is an inexpensive, non-threadsafe object that should be 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> 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 (or a <literal>Datasource</literal>) unless it is needed, hence consume no
and close a <literal>Session</literal> even if you are not sure that data access will resources until used.
be needed to serve a particular request. (This becomes important as soon as you are
implementing some of the following patterns using request interception.)
</para> </para>
<para> <para>
To complete this picture you also have to think about database transactions. A 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 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 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>
<para> <para>
@ -67,7 +73,12 @@
units of work. (Note that this also means that auto-commit after every single 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 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, 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>
<para> <para>
@ -83,24 +94,42 @@
</para> </para>
<para> <para>
The challenge lies in the implementation: not only has the <literal>Session</literal> The challenge lies in the implementation. Hibernate provides built-in management of
and transaction to be started and ended correctly, but they also have to be accessible for the "current session" to simplify this pattern. All you have to do is start a
data access operations. The demarcation of a unit of work is ideally implemented using an transaction when a server request has to be processed, and end the transaction
interceptor that runs when a request hits the server and before the response will be send (i.e. before the response is send to the client. You can do this in any way you
a <literal>ServletFilter</literal>). We recommend to bind the <literal>Session</literal> to like, common solutions are <literal>ServletFilter</literal>, AOP interceptor with a
the thread that serves the request, using a <literal>ThreadLocal</literal> variable. This allows pointcut on the service methods, or a proxy/interception container. An EJB container
easy access (like accessing a static variable) in all code that runs in this thread. Depending is a standardized way to implement cross-cutting aspects such as transaction
on the database transaction demarcation mechanism you chose, you might also keep the transaction demarcation on EJB session beans, declaratively with CMT. If you decide to
context in a <literal>ThreadLocal</literal> variable. The implementation patterns for this use programmatic transaction demarcation, prefer the Hibernate <literal>Transaction</literal>
are known as <emphasis>ThreadLocal Session</emphasis> and <emphasis>Open Session in View</emphasis> API shown later in this chapter, for ease of use and code portability.
and can be found on the Hibernate Wiki. Of course, you'd have to find a way to implement an </para>
interceptor and set it up in your environment. See the Hibernate website for tips and examples.
<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> </para>
</sect2> </sect2>
<sect2 id="transactions-basics-apptx"> <sect2 id="transactions-basics-apptx" revision="1">
<title>Application transactions</title> <title>Long conversations</title>
<para> <para>
The session-per-request pattern is not the only useful concept you can use to design The session-per-request pattern is not the only useful concept you can use to design
@ -129,8 +158,8 @@
<para> <para>
We call this unit of work, from the point of view of the user, a long running 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 <emphasis>conversation</emphasis> (or <emphasis>application transaction</emphasis>).
this in your application. There are many ways how you can implement this in your application.
</para> </para>
<para> <para>
@ -142,9 +171,9 @@
</para> </para>
<para> <para>
Clearly, we have to use several database transactions to implement the application Clearly, we have to use several database transactions to implement the converastion.
transaction. In this case, maintaining isolation of business processes becomes the In this case, maintaining isolation of business processes becomes the
partial responsibility of the application tier. A single application transaction partial responsibility of the application tier. A single conversation
usually spans several database transactions. It will be atomic if only one of 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 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 simply read data (e.g. in a wizard-style dialog spanning several request/response
@ -157,7 +186,8 @@
<para> <para>
<emphasis>Automatic Versioning</emphasis> - Hibernate can do automatic <emphasis>Automatic Versioning</emphasis> - Hibernate can do automatic
optimistic concurrency control for you, it can automatically detect 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> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -172,19 +202,21 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<emphasis>Long Session</emphasis> - The Hibernate <literal>Session</literal> may <emphasis>Extended (or Long) Session</emphasis> - The Hibernate
be disconnected from the underlying JDBC connection after the database transaction <literal>Session</literal> may be disconnected from the underlying JDBC
has been committed, and reconnected when a new client request occurs. This pattern connection after the database transaction has been committed, and reconnected
is known as <emphasis>session-per-application-transaction</emphasis> and makes 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 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> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
<para> <para>
Both <emphasis>session-per-request-with-detached-objects</emphasis> and 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. we discuss them later in this chapter in the context of optimistic concurrency control.
</para> </para>
@ -317,7 +349,9 @@
the database can occur outside of a database transaction (this seems to confuse many developers 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 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 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>
<para> <para>
@ -325,13 +359,15 @@
and managed J2EE environments. In a non-managed environment, Hibernate is usually responsible for 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 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 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 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>
<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 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 your deployment environment. This API is actually optional, but we strongly encourage its use
unless you are in a CMT session bean. unless you are in a CMT session bean.
@ -370,7 +406,7 @@
</para> </para>
<sect2 id="transactions-demarcation-nonmanaged"> <sect2 id="transactions-demarcation-nonmanaged" revision="1">
<title>Non-managed environment</title> <title>Non-managed environment</title>
<para> <para>
@ -399,62 +435,51 @@ finally {
}]]></programlisting> }]]></programlisting>
<para> <para>
Or even like this: 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> </para>
<programlisting><![CDATA[// Non-managed environment idiom <para>
Session sess = factory.openSession(); 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 { try {
sess.getTransaction().begin(); factory.getCurrentSession().beginTransaction();
// do some work // do some work
... ...
sess.getTransaction().commit() factory.getCurrentSession().getTransaction().commit();
} }
catch (RuntimeException e) { catch (RuntimeException e) {
if ( sess.getTransaction().isActive() ) { factory.getCurrentSession().getTransaction().rollback();
sess.getTransaction().rollback();
}
throw e; // or display error message throw e; // or display error message
}
finally {
sess.close();
}]]></programlisting> }]]></programlisting>
<para> <para>
You don't have to <literal>flush()</literal> the <literal>Session</literal> explicitly - You will very likely never see these code snippets in a regular application;
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;
fatal (system) exceptions should always be caught at the "top". In other words, the 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 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 <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 different layers. The current context management by Hibernate can significantly
container services whenever they are available. Exception handling is discussed later in simplify this design, as all you need is access to a <literal>SessionFactory</literal>.
this chapter. Exception handling is discussed later in this chapter.
</para> </para>
<para> <para>
Note that you should select <literal>org.hibernate.transaction.JDBCTransactionFactory</literal> 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> </para>
</sect2> </sect2>
<sect2 id="transactions-demarcation-jta" revision="1"> <sect2 id="transactions-demarcation-jta" revision="2">
<title>Using JTA</title> <title>Using JTA</title>
<para> <para>
@ -489,61 +514,26 @@ finally {
}]]></programlisting> }]]></programlisting>
<para> <para>
Or: Or with automatic session context management:
</para> </para>
<programlisting><![CDATA[// BMT idiom <programlisting><![CDATA[// BMT idiom with getCurrentSession()
Session sess = factory.openSession();
try { try {
sess.getTransaction().begin(); factory.getCurrentSession().beginTransaction();
// do some work // do some work
... ...
sess.getTransaction().commit() factory.getCurrentSession().getTransaction().commit();
} }
catch (RuntimeException e) { catch (RuntimeException e) {
if ( sess.getTransaction().isActive() ) { factory.getCurrentSession().getTransaction().rollback();
sess.getTransaction().rollback();
}
throw e; // or display error message throw e; // or display error message
}
finally {
sess.close();
}]]></programlisting> }]]></programlisting>
<para> <para>
With CMT, transaction demarcation is done in session bean deployment descriptors, not programatically. 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 hence, the code is reduced to:
<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>
</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>.
</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> </para>
<programlisting><![CDATA[// CMT idiom <programlisting><![CDATA[// CMT idiom
@ -551,21 +541,29 @@ Session sess = factory.getCurrentSession();
// do some work // do some work
... ...
]]></programlisting> ]]></programlisting>
<para> <para>
In other words, all you have to do in a managed environment is call In a CMT?EJB even rollback happens automatically, since an unhandled <literal>RuntimeException</literal>
<literal>SessionFactory.getCurrentSession()</literal>, do your data access work, and leave thrown by a session bean method tells the container to set the global transaction to rollback.
the rest to the container. Transaction boundaries are set declaratively in the deployment <emphasis>This means you do not need to use the Hibernate <literal>Transaction</literal> API at
descriptors of your session bean. The lifecycle of the session is completely managed by all in CMT.</emphasis>
Hibernate.
</para> </para>
<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>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>
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 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 mode, which is then used by default. Due to a silly limitation of the JTA spec, it is not
automatically clean up any unclosed <literal>ScrollableResults</literal> or possible for Hibernate to automatically clean up any unclosed <literal>ScrollableResults</literal> or
<literal>Iterator</literal> instances returned by <literal>scroll()</literal> or <literal>Iterator</literal> instances returned by <literal>scroll()</literal> or
<literal>iterate()</literal>. You <emphasis>must</emphasis> release the underlying database <literal>iterate()</literal>. You <emphasis>must</emphasis> release the underlying database
cursor by calling <literal>ScrollableResults.close()</literal> or cursor by calling <literal>ScrollableResults.close()</literal> or
@ -680,9 +678,7 @@ try {
sess.getTransaction().commit() sess.getTransaction().commit()
} }
catch (RuntimeException e) { catch (RuntimeException e) {
if ( sess.getTransaction().isActive() ) {
sess.getTransaction().rollback(); sess.getTransaction().rollback();
}
throw e; // or display error message throw e; // or display error message
} }
finally { finally {
@ -707,7 +703,7 @@ finally {
checking uses version numbers, or timestamps, to detect conflicting updates checking uses version numbers, or timestamps, to detect conflicting updates
(and to prevent lost updates). Hibernate provides for three possible approaches (and to prevent lost updates). Hibernate provides for three possible approaches
to writing application code that uses optimistic concurrency. The use cases 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. also has the benefit of preventing lost updates in single database transactions.
</para> </para>
@ -719,17 +715,19 @@ finally {
database occurs in a new <literal>Session</literal> and the developer is responsible database occurs in a new <literal>Session</literal> and the developer is responsible
for reloading all persistent instances from the database before manipulating them. 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 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. database access. It is the approach most similar to entity EJBs.
</para> </para>
<programlisting><![CDATA[// foo is an instance loaded by a previous Session <programlisting><![CDATA[// foo is an instance loaded by a previous Session
session = factory.openSession(); session = factory.openSession();
Transaction t = session.beginTransaction(); Transaction t = session.beginTransaction();
int oldVersion = foo.getVersion(); int oldVersion = foo.getVersion();
session.load( foo, foo.getKey() ); // load the current state session.load( foo, foo.getKey() ); // load the current state
if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException(); if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
foo.setProperty("bar"); foo.setProperty("bar");
t.commit(); t.commit();
session.close();]]></programlisting> 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 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 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 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 confuse the users of the application, as they might experience lost updates without
error messages or a chance to merge conflicting changes. error messages or a chance to merge conflicting changes.
</para> </para>
@ -752,22 +750,22 @@ session.close();]]></programlisting>
Clearly, manual version checking is only feasible in very trivial circumstances Clearly, manual version checking is only feasible in very trivial circumstances
and not practical for most applications. Often not only single instances, but and not practical for most applications. Often not only single instances, but
complete graphs of modified ojects have to be checked. Hibernate offers automatic 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. as the design paradigm.
</para> </para>
</sect2> </sect2>
<sect2 id="transactions-optimistic-longsession"> <sect2 id="transactions-optimistic-longsession">
<title>Long session and automatic versioning</title> <title>Extended session and automatic versioning</title>
<para> <para>
A single <literal>Session</literal> instance and its persistent instances are A single <literal>Session</literal> instance and its persistent instances are
used for the whole application transaction. Hibernate checks instance versions used for the whole conversation, known as <emphasis>session-per-conversation</emphasis>.
at flush time, throwing an exception if concurrent modification is detected. Hibernate checks instance versions at flush time, throwing an exception if concurrent
It's up to the developer to catch and handle this exception (common options modification is detected. It's up to the developer to catch and handle this exception
are the opportunity for the user to merge changes or to restart the business (common options are the opportunity for the user to merge changes or to restart the
process with non-stale data). business conversation with non-stale data).
</para> </para>
<para> <para>
@ -778,27 +776,27 @@ session.close();]]></programlisting>
database transaction. database transaction.
</para> </para>
<programlisting><![CDATA[// foo is an instance loaded earlier by the Session <programlisting><![CDATA[// foo is an instance loaded earlier by the old session
session.reconnect(); // Obtain a new JDBC connection Transaction t = session.beginTransaction(); // Obtain a new JDBC connection, start transaction
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>
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> <para>
The <literal>foo</literal> object still knows which <literal>Session</literal> it was 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 loaded in. Beginning a new database transaction on an old session obtains a new connection
may supply one) and resumes the session. The method <literal>Session.disconnect()</literal> and resumes the session. Committing a database transaction disconnects a session
will disconnect the session from the JDBC connection and return the connection to the pool from the JDBC connection and returns the connection to the pool. After reconnection, to
(unless you provided the connection). After reconnection, to force a version check on data force a version check on data you aren't updating, you may call <literal>Session.lock()</literal>
you aren't updating, you may call <literal>Session.lock()</literal> with with <literal>LockMode.READ</literal> on any objects that might have been updated by another
<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. transaction. You don't need to lock any data that you <emphasis>are</emphasis> updating.
</para> 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
<para> modifications made in this conversation. Hence, only this last database transaction
If the explicit calls to <literal>disconnect()</literal> and <literal>reconnect()</literal> would include the <literal>flush()</literal> operation, and then also
are too onerous, you may instead use <literal>hibernate.connection.release_mode</literal>. <literal>close()</literal> the session to end the conversation.
</para> </para>
<para> <para>
@ -806,15 +804,30 @@ session.disconnect(); // Return JDBC connection ]]></programlisting>
be stored during user think time, e.g. an <literal>HttpSession</literal> should 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 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 (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 use this strategy only for a few request/response cycles. You should use a
recommended, as the <literal>Session</literal> will soon also have stale data. <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>
<para> <para>
Also note that you should keep the disconnected <literal>Session</literal> close 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 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 hold the <literal>Session</literal> in a three-tier environment, and don't transfer
even serialize it to a separate tier) to store it in the <literal>HttpSession</literal>. 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> </para>
</sect2> </sect2>

View File

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