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"
|
<!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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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—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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue