alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (transactions.xml)

This example Hibernate source code file (transactions.xml) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

a, hibernate, hibernate, if, in, in, it, jdbc, jta, the, the, this, this, you

The Hibernate transactions.xml source code

<?xml version='1.0' encoding="UTF-8"?>
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
  ~ indicated by the @author tags or express copyright attribution
  ~ statements applied by the authors.  All third-party contributions are
  ~ distributed under license by Red Hat Middleware LLC.
  ~
  ~ This copyrighted material is made available to anyone wishing to use, modify,
  ~ copy, or redistribute it subject to the terms and conditions of the GNU
  ~ Lesser General Public License, as published by the Free Software Foundation.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->

<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "../HIBERNATE_-_Relational_Persistence_for_Idiomatic_Java.ent">
%BOOK_ENTITIES;

]>

<chapter id="transactions" revision="2">
    <title>Transactions and Concurrency

    <para>
        The most important point about Hibernate and concurrency control is that it is
        easy to understand. Hibernate directly uses JDBC connections and JTA resources without
        adding any additional locking behavior. It is recommended that you spend some time with the
        JDBC, ANSI, and transaction isolation specification of your database management system.
    </para>

    <para>
        Hibernate does not lock objects in memory. Your application can expect the behavior as
        defined by the isolation level of your database transactions. Through
        <literal>Session, which is also a transaction-scoped cache, Hibernate
        provides repeatable reads for lookup by identifier and entity queries and not
        reporting queries that return scalar values.
    </para>

    <para>
        In addition to versioning for automatic optimistic concurrency control, Hibernate also
        offers, using the
        <literal>SELECT FOR UPDATE syntax, a (minor) API for pessimistic locking of rows.  Optimistic concurrency control and
        this API are discussed later in this chapter.
    </para>

    <para>
        The discussion of concurrency control in Hibernate begins with the granularity of
        <literal>Configuration, SessionFactory, and
        <literal>Session, as well as database transactions and long conversations.
    </para>

    <section id="transactions-basics" revision="1">
        <title>Session and transaction scopes

        <para>
            A <literal>SessionFactory is an expensive-to-create, threadsafe object, 
            intended to be shared by all application threads. It is created once, usually on
            application startup, from a <literal>Configuration instance.
        </para>

        <para>
            A <literal>Session is an inexpensive, non-threadsafe object that should be
            used once and then discarded for: a single request, a conversation or a single unit of work.
            A <literal>Session will not obtain a JDBC Connection,
            or a <literal>Datasource, unless it is needed. It will not consume any
            resources until used.
        </para>

        <para>
            In order to reduce lock contention in the database, a database transaction has to be as short as possible. 
            Long database transactions will prevent your application from scaling
            to a highly concurrent load. It is not recommended that you hold a
            database transaction open during user think time until the unit of work is
            complete.
        </para>

        <para>
            What is the scope of a unit of work? Can a single Hibernate <literal>Session
            span several database transactions, or is this a one-to-one relationship of scopes? When
            should you open and close a <literal>Session and how do you demarcate the
            database transaction boundaries? These questions are addressed in the following sections.
        </para>

        <section id="transactions-basics-uow" revision="1">
            <title>Unit of work

            <para>
                First, let's define a unit of work.  A unit of work is a
                design pattern described by Martin Fowler as
                <quote>
                    [maintaining] a list of objects affected by a business
                    transaction and coordinates the writing out of changes
                    and the resolution of concurrency problems.
                </quote>PoEAA
                In other words, its a series of operations we wish to carry out
                against the database together.  Basically, it is a transaction,
                though fulfilling a unit of work will often span multiple
                physical database transactions (see <xref linkend="transactions-basics-apptx"/>).
                So really we are talking about a more abstract notion of a
                transaction.  The term "business transaction" is also sometimes
                used in lieu of unit of work.
            </para>

            <para>
                Do not use the <emphasis>session-per-operation antipattern:
                do not open and close a <literal>Session for every simple database call in
                a single thread. The same is true for database transactions. Database calls
                in an application are made using a planned sequence; they are grouped into atomic
                units of work. This also means that auto-commit after every single
                SQL statement is useless in an application as this mode is intended for ad-hoc SQL
                console work. Hibernate disables, or expects the application server to disable,
                auto-commit mode immediately. Database transactions are never optional. All
                communication with a database has to occur inside a transaction. 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 more maintainable
                and extensible.
            </para>

            <para>
                The most common pattern in a multi-user client/server application is
                <emphasis>session-per-request. In this model, a request from the client
                is sent to the server, where the Hibernate persistence layer runs. A new Hibernate
                <literal>Session is opened, and all database operations are executed in this unit
                of work. On completion of the work, and once the response for the client has been prepared,
                the session is flushed and closed. Use a single database transaction to
                serve the clients request, starting and committing it when you open and close the
                <literal>Session. The relationship between the two is one-to-one and this
                model is a perfect fit for many applications.
            </para>

            <para>
                The challenge lies in the implementation. Hibernate provides built-in management of
                the "current session" to simplify this pattern. Start a
                transaction when a server request has to be processed, and end the transaction
                before the response is sent to the client. Common solutions are <literal>ServletFilter, AOP interceptor with a
                pointcut on the service methods, or a proxy/interception container. An EJB container
                is a standardized way to implement cross-cutting aspects such as transaction
                demarcation on EJB session beans, declaratively with CMT. If you
                use programmatic transaction demarcation, for ease of use and code portability use the Hibernate <literal>Transaction
                API shown later in this chapter.
            </para>

            <para>
                Your application code can access a "current session" to process the request
                by calling <literal>sessionFactory.getCurrentSession(). 
		You will always get a <literal>Session 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>
                You can extend the scope of a <literal>Session 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 achieved by implementing
                your own interceptor. However, this will be difficult
                if you rely on EJBs with container-managed transactions. 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 relating to
                this <emphasis>Open Session in View pattern.
             </para>

        </section>

        <section id="transactions-basics-apptx" revision="1">
            <title>Long conversations

            <para>
                The session-per-request pattern is not the only way of designing
                units of work. Many business processes require a whole series of interactions with the user that are
                interleaved with database accesses. In web and enterprise applications, it is
                not acceptable for a database transaction to span a user interaction. Consider the following
                example:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        The first screen of a dialog opens. The data seen by the user has been loaded in
                        a particular <literal>Session and database transaction. The user is free to
                        modify the objects.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        The user clicks "Save" after 5 minutes and expects their modifications to be made
                        persistent. The user also expects that they were the only person editing this information and
                        that no conflicting modification has occurred.
                    </para>
                </listitem>
            </itemizedlist>

            <para>
                From the point of view of the user, we call this unit of work a long-running
                <emphasis>conversation or application transaction.
                There are many ways to implement this in your application.
            </para>

            <para>
                A first naive implementation might keep the <literal>Session and database
                transaction open during user think time, with locks held in the database to prevent
                concurrent modification and to guarantee isolation and atomicity. This is 
                an anti-pattern, since lock contention would not allow the application to scale with
                the number of concurrent users.
            </para>

            <para>
                You have to use several database transactions to implement the conversation.
                In this case, maintaining isolation of business processes becomes the
                partial responsibility of the application tier. A single conversation
                usually spans several database transactions. It will be atomic if only one of
                these database transactions (the last one) stores the updated data. All others
                simply read data (for example, in a wizard-style dialog spanning several request/response
                cycles). This is easier to implement than it might sound, especially if
                you utilize some of Hibernate's features:
            </para>

            <itemizedlist>
                <listitem>
                    <para>
                        <emphasis>Automatic Versioning: Hibernate can perform automatic
                        optimistic concurrency control for you. It can automatically detect
                        if a concurrent modification occurred during user think time. Check for this at 
			the end of the conversation.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <emphasis>Detached Objects: if you decide to use the
                        <emphasis>session-per-request pattern, all loaded instances
                        will be in the detached state during user think time. Hibernate allows you to
                        reattach the objects and persist the modifications. The pattern is called
                        <emphasis>session-per-request-with-detached-objects. Automatic
                        versioning is used to isolate concurrent modifications.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <emphasis>Extended (or Long) Session: the Hibernate
                        <literal>Session can be disconnected from the underlying JDBC
                        connection after the database transaction has been committed and reconnected
                        when a new client request occurs. This pattern is known as
                        <emphasis>session-per-conversation and makes
                        even reattachment unnecessary. Automatic versioning is used to isolate
                        concurrent modifications and the <literal>Session will not
                        be allowed to be flushed automatically, but explicitly.
                    </para>
                </listitem>
            </itemizedlist>

            <para>
                Both <emphasis>session-per-request-with-detached-objects and
                <emphasis>session-per-conversation have advantages and disadvantages.
                These disadvantages are discussed later in this chapter in the context of optimistic concurrency control.
            </para>

        </section>

        <section id="transactions-basics-identity">
            <title>Considering object identity

            <para>
                An application can concurrently access the same persistent state in two
                different <literal>Sessions. However, an instance of a persistent class
                is never shared between two <literal>Session instances. It is for this reason that there are
                two different notions of identity:
            </para>

            <variablelist spacing="compact">
                <varlistentry>
                    <term>Database Identity
                    <listitem>
                        <para>
                            <literal>foo.getId().equals( bar.getId() )
                        </para>
                    </listitem>
                </varlistentry>
                <varlistentry>
                    <term>JVM Identity
                    <listitem>
                        <para>
                            <literal>foo==bar
                        </para>
                    </listitem>
                </varlistentry>
            </variablelist>

            <para>
                For objects attached to a <emphasis>particular Session
                (i.e., in the scope of a <literal>Session), the two notions are equivalent and
                JVM identity for database identity is guaranteed by Hibernate. While the application
                might concurrently access the "same" (persistent identity) business object in two different
                sessions, the two instances will actually be "different" (JVM identity). Conflicts are
                resolved using an optimistic approach and automatic versioning at flush/commit time.
            </para>

            <para>
                This approach leaves Hibernate and the database to worry about concurrency. It also provides
                the best scalability, since guaranteeing identity in single-threaded units of work means that it does not
                need expensive locking or other means of synchronization. The application does not need to
                synchronize on any business object, as long as it maintains a single thread per
                <literal>Session. Within a Session the application can safely use
                <literal>== to compare objects.
            </para>

            <para>
                However, an application that uses <literal>== outside of a Session
                might produce unexpected results. This might occur even in some unexpected places. For example,
                if you put two detached instances into the same <literal>Set, both might have the same
                database identity (i.e., they represent the same row). JVM identity, however, is by definition not
                guaranteed for instances in a detached state. The developer has to override the <literal>equals()
                and <literal>hashCode() methods in persistent classes and implement
                their own notion of object equality. There is one caveat: never use the database
                identifier to implement equality. Use a business key that is a combination of unique, usually
                immutable, attributes. The database identifier will change if a transient object is made
                persistent. If the transient instance (usually together with detached instances) is held in a
                <literal>Set, changing the hashcode breaks the contract of the Set.
                Attributes for business keys do not have to be as stable as database primary keys; you only
                have to guarantee stability as long as the objects are in the same <literal>Set. See
                the Hibernate website for a more thorough discussion of this issue. Please note that this is not
                a Hibernate issue, but simply how Java object identity and equality has to be implemented.
            </para>

        </section>

        <section id="transactions-basics-issues">
            <title>Common issues

             <para>
                 Do not use the anti-patterns <emphasis>session-per-user-session or
                 <emphasis>session-per-application (there are, however, rare exceptions to
                 this rule). Some of the following issues might also arise within the recommended
                 patterns, so ensure that you understand the implications before making a design decision:
             </para>

            <itemizedlist>
                <listitem>
                    <para>
                        A <literal>Session is not thread-safe. Things that work
                        concurrently, like HTTP requests, session beans, or Swing workers, will cause race
                        conditions if a <literal>Session instance is shared. If you keep your
                        Hibernate <literal>Session in your HttpSession (this is discussed
                        later in the chapter), you should consider synchronizing access to your Http session. Otherwise,
                        a user that clicks reload fast enough can use the same <literal>Session in
                        two concurrently running threads.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        An exception thrown by Hibernate means you have to rollback your database transaction
                        and close the <literal>Session immediately (this is discussed in more detail later in the chapter).
                        If your <literal>Session is bound to the application, you have to stop
                        the application. Rolling back the database transaction does not put your business
                        objects back into the state they were at the start of the transaction. This means that the
                        database state and the business objects will be out of sync. Usually this is not a
                        problem, because exceptions are not recoverable and you will have to start over after
                        rollback anyway.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        The <literal>Session caches every object that is in a persistent state (watched
                        and checked for dirty state by Hibernate).  If you keep it open for a long time or simply load too
                        much data, it will grow endlessly until you
                        get an OutOfMemoryException. One solution is to call <literal>clear() and evict()
                        to manage the <literal>Session cache, but you should consider a
                        Stored Procedure if you need mass data operations. Some solutions are shown in
                        <xref linkend="batch"/>. Keeping a Session open for the duration
                        of a user session also means a higher probability of stale data.
                    </para>
                </listitem>
            </itemizedlist>

        </section>

    </section>

    <section id="transactions-demarcation">
        <title>Database transaction demarcation

        <para>
            Database, or system, transaction boundaries are always necessary. No communication with
            the database can occur outside of a database transaction (this seems to confuse many developers
            who are used to the auto-commit mode). Always use clear transaction boundaries, even for
            read-only operations. Depending on your isolation level and database capabilities this might not
            be required, but there is no downside if you always demarcate transactions explicitly. Certainly,
            a single database transaction is going to perform better than many small transactions, even
            for reading data.
        </para>

        <para>
            A Hibernate application can run in non-managed (i.e., standalone, simple Web- or Swing applications)
            and managed J2EE environments. In a non-managed environment, Hibernate is usually responsible for
            its own database connection pool. The application developer has to manually set transaction
            boundaries (begin, commit, or rollback database transactions) themselves. A managed environment
            usually provides container-managed transactions (CMT), with the transaction assembly defined declaratively
            (in deployment descriptors of EJB session beans, for example). Programmatic transaction demarcation is
            then no longer necessary.
        </para>

        <para>
            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 use programmatic transaction demarcation. Hibernate offers a wrapper
            API called <literal>Transaction that translates into the native transaction system of
            your deployment environment. This API is actually optional, but we strongly encourage its use
            unless you are in a CMT session bean.
        </para>

        <para>
            Ending a <literal>Session usually involves four distinct phases:
        </para>

        <itemizedlist spacing="compact">
            <listitem>
                <para>
                    flush the session
                </para>
            </listitem>
            <listitem>
                <para>
                    commit the transaction
                </para>
            </listitem>
            <listitem>
                <para>
                    close the session
                </para>
            </listitem>
            <listitem>
                <para>
                    handle exceptions
                </para>
            </listitem>
        </itemizedlist>

        <para>
            We discussed Flushing the session earlier, so we will now have a closer look at transaction
            demarcation and exception handling in both managed and non-managed environments.
        </para>


        <section id="transactions-demarcation-nonmanaged" revision="2">
            <title>Non-managed environment

            <para>
                If a Hibernate persistence layer runs in a non-managed environment, database connections
                are usually handled by simple (i.e., non-DataSource) connection pools from which
	            Hibernate obtains connections as needed. The session/transaction handling idiom looks
	            like this:
            </para>

            <programlisting role="JAVA">

            <para>
                You do not have to <literal>flush() the Session explicitly:
                the call to <literal>commit() automatically triggers the synchronization depending
	            on the <link linkend="objectstate-flushing">FlushMode for the session.
                A call to <literal>close() marks the end of a session. The main implication
                of <literal>close() 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>
                As outlined earlier, a much more flexible solution is Hibernate's built-in "current session" context
                management:
            </para>

            <programlisting role="JAVA">

            <para>
                You will not see these code snippets in a regular application;
                fatal (system) exceptions should always be caught at the "top". In other words, the
                code that executes Hibernate calls in the persistence layer, and the code that handles
                <literal>RuntimeException (and usually can only clean up and exit), are in
                different layers. The current context management by Hibernate can significantly
                simplify this design by accessing a <literal>SessionFactory.
                Exception handling is discussed later in this chapter.
            </para>

           <para>
                You should select <literal>org.hibernate.transaction.JDBCTransactionFactory,
                which is the default, and for the second example select <literal>"thread" as your
                <literal>hibernate.current_session_context_class.
            </para>
            
        </section>

        <section id="transactions-demarcation-jta" revision="3">
            <title>Using JTA

            <para>
                If your persistence layer runs in an application server (for example, behind EJB session beans),
                every datasource connection obtained by Hibernate will automatically be part of the global
                JTA transaction. You can also install a standalone JTA implementation and use it without
                EJB. Hibernate offers two strategies for JTA integration.
            </para>

            <para>
                If you use bean-managed transactions (BMT), Hibernate will tell the application server to start
                and end a BMT transaction if you use the <literal>Transaction API. The
                transaction management code is identical to the non-managed environment.
            </para>
            
           <programlisting role="JAVA">

           <para>
                If you want to use a transaction-bound <literal>Session, that is, the
               <literal>getCurrentSession() functionality for easy context propagation,
               use the JTA <literal>UserTransaction API directly:
            </para>

            <programlisting role="JAVA">

            <para>
                With CMT, transaction demarcation is completed in session bean deployment descriptors, not programmatically.
                The code is reduced to:
            </para>

            <programlisting role="JAVA">

            <para>
                In a CMT/EJB, even rollback happens automatically. An unhandled <literal>RuntimeException
                thrown  by a session bean method tells the container to set the global transaction to rollback.
                <emphasis>You do not need to use the Hibernate Transaction API at
                all with BMT or CMT, and you get automatic propagation of the "current" Session bound to the
                transaction.</emphasis>
            </para>

            <para>
                When configuring Hibernate's transaction factory, choose <literal>org.hibernate.transaction.JTATransactionFactory
                if you use JTA directly (BMT), and <literal>org.hibernate.transaction.CMTTransactionFactory
                in a CMT session bean.  Remember to also set
                <literal>hibernate.transaction.manager_lookup_class. Ensure
                that your <literal>hibernate.current_session_context_class is either unset (backwards
                compatibility), or is set to <literal>"jta".
            </para>

            <para>
                The <literal>getCurrentSession() operation has one downside in a JTA environment.
                There is one caveat to the use of <literal>after_statement connection release
                mode, which is then used by default. Due to a limitation of the JTA spec, it is not
                possible for Hibernate to automatically clean up any unclosed <literal>ScrollableResults or
                <literal>Iterator instances returned by scroll() or 
                <literal>iterate(). You must release the underlying database 
                cursor by calling <literal>ScrollableResults.close() or 
                <literal>Hibernate.close(Iterator) explicitly from a finally 
                block. Most applications can easily avoid using <literal>scroll() or 
                <literal>iterate() from the JTA or CMT code.)
            </para>

        </section>

        <section id="transactions-demarcation-exceptions">
            <title>Exception handling

            <para>
                If the <literal>Session throws an exception, including any
                <literal>SQLException, immediately rollback the database
                transaction, call <literal>Session.close() and discard the
                <literal>Session instance. Certain methods of Session
                will <emphasis>not leave the session in a consistent state. No
                exception thrown by Hibernate can be treated as recoverable. Ensure that the
                <literal>Session will be closed by calling close()
                in a <literal>finally block.
            </para>

            <para>
                The <literal>HibernateException, which wraps most of the errors that
                can occur in a Hibernate persistence layer, is an unchecked exception. It was not
                in older versions of Hibernate. In our opinion, we should not force the application
                developer to catch an unrecoverable exception at a low layer. In most systems, unchecked
                and fatal exceptions are handled in one of the first frames of the method call
                stack (i.e., in higher layers) and either an error message is presented to the application
                user or some other appropriate action is taken. Note that Hibernate might also throw
                other unchecked exceptions that are not a <literal>HibernateException. These 
                are not recoverable and appropriate action should be taken.
            </para>

            <para>
                Hibernate wraps <literal>SQLExceptions thrown while interacting with the database
                in a <literal>JDBCException. In fact, Hibernate will attempt to convert the exception
                into a more meaningful subclass of <literal>JDBCException.  The underlying
                <literal>SQLException is always available via JDBCException.getCause().
                Hibernate converts the <literal>SQLException into an appropriate 
                <literal>JDBCException subclass using the SQLExceptionConverter 
                attached to the <literal>SessionFactory. By default, the 
                <literal>SQLExceptionConverter is defined by the configured dialect.  However, it is
                also possible to plug in a custom implementation. See the javadocs for the
                <literal>SQLExceptionConverterFactory class for details.  The standard 
                <literal>JDBCException subtypes are:
            </para>

            <itemizedlist spacing="compact">
                <listitem>
                    <para>
                        <literal>JDBCConnectionException: indicates an error
                        with the underlying JDBC communication.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <literal>SQLGrammarException: indicates a grammar
                        or syntax problem with the issued SQL.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <literal>ConstraintViolationException: indicates some
                        form of integrity constraint violation.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <literal>LockAcquisitionException: indicates an error
                        acquiring a lock level necessary to perform the requested operation.
                    </para>
                </listitem>
                <listitem>
                    <para>
                        <literal>GenericJDBCException: a generic exception
                        which did not fall into any of the other categories.
                    </para>
                </listitem>
            </itemizedlist>

        </section>

        <section id="transactions-demarcation-timeout">
            <title>Transaction timeout

            <para>
                An important feature provided by a managed environment like EJB,
                that is never provided for non-managed code, is transaction timeout. Transaction
                timeouts ensure that no misbehaving transaction can indefinitely tie up 
                resources while returning no response to the user. Outside a managed (JTA)
                environment, Hibernate cannot fully provide this functionality. However,
                Hibernate can at least control data access operations, ensuring that database
                level deadlocks and queries with huge result sets are limited by a defined
                timeout. In a managed environment, Hibernate can delegate transaction timeout
                to JTA. This functionality is abstracted by the Hibernate 
                <literal>Transaction object.
            </para>
            
            <programlisting role="JAVA">

            <para>
                <literal>setTimeout() cannot be called in a CMT bean,
                where transaction timeouts must be defined declaratively.
            </para>
            
        </section>
        
    </section>

    <section id="transactions-optimistic">
        <title>Optimistic concurrency control

        <para>
            The only approach that is consistent with high concurrency and high
            scalability, is optimistic concurrency control with versioning. Version
            checking uses version numbers, or timestamps, to detect conflicting updates
            and to prevent lost updates. Hibernate provides three possible approaches
            to writing application code that uses optimistic concurrency. The use cases
            we discuss are in the context of long conversations, but version checking
            also has the benefit of preventing lost updates in single database transactions.
        </para>

        <section id="transactions-optimistic-manual">
            <title>Application version checking

            <para>
                In an implementation without much help from Hibernate, each interaction with the
                database occurs in a new <literal>Session and the developer is responsible
                for reloading all persistent instances from the database before manipulating them.
                The application is forced to carry out its own version checking to ensure
                conversation transaction isolation. This approach is the least efficient in terms of
                database access. It is the approach most similar to entity EJBs.
            </para>

            <programlisting role="JAVA">

            <para>
                The <literal>version property is mapped using <version>,
                and Hibernate will automatically increment it during flush if the entity is
                dirty.
            </para>

            <para>
                If you are operating in a low-data-concurrency environment, and do not
                require version checking, you can use this approach and skip the version
                check. In this case, <emphasis>last commit wins is the default
                strategy for long conversations. Be aware that this might
                confuse the users of the application, as they might experience lost updates without
                error messages or a chance to merge conflicting changes.
            </para>

            <para>
                Manual version checking is only feasible in trivial circumstances
                and not practical for most applications. Often not only single instances, but
                complete graphs of modified objects, have to be checked. Hibernate offers automatic
                version checking with either an extended <literal>Session or detached instances
                as the design paradigm.
            </para>

        </section>

        <section id="transactions-optimistic-longsession">
            <title>Extended session and automatic versioning

            <para>
                A single <literal>Session instance and its persistent instances that are
                used for the whole conversation are known as <emphasis>session-per-conversation.
                Hibernate checks instance versions at flush time, throwing an exception if concurrent
                modification is detected. It is up to the developer to catch and handle this exception. 
                Common options are the opportunity for the user to merge changes or to restart the
                business conversation with non-stale data.
            </para>

            <para>
                The <literal>Session is disconnected from any underlying JDBC connection
                when waiting for user interaction. This approach is the most efficient in terms
                of database access. The application does not version check or
                reattach detached instances, nor does it have to reload instances in every
                database transaction.
            </para>

            <programlisting role="JAVA">
            <para>
                The <literal>foo object knows which Session it was
                loaded in. Beginning a new database transaction on an old session obtains a new connection
                and resumes the session. Committing a database transaction disconnects a session
                from the JDBC connection and returns the connection to the pool. After reconnection, to
                force a version check on data you are not updating, you can call <literal>Session.lock()
                with <literal>LockMode.READ on any objects that might have been updated by another
                transaction. You do not need to lock any data that you <emphasis>are updating.
                Usually you would set <literal>FlushMode.MANUAL on an extended Session,
                so that only the last database transaction cycle is allowed to actually persist all
                modifications made in this conversation. Only this last database transaction
                will include the <literal>flush() operation, and then
                <literal>close() the session to end the conversation.
            </para>
            
            <para>
                This pattern is problematic if the <literal>Session is too big to
                be stored during user think time (for example, an <literal>HttpSession should
                be kept as small as possible). As the <literal>Session is also the
                first-level cache and contains all loaded objects, we can probably
                use this strategy only for a few request/response cycles. Use a
                <literal>Session only for a single conversation as it will soon
                have stale data.
            </para>

            <note>
           <title>Note
	   <para>Earlier versions of Hibernate required explicit disconnection and reconnection
                of a <literal>Session. These methods are deprecated, as beginning and
                ending a transaction has the same effect.
	    </para>
            </note>

            <para>
                Keep the disconnected <literal>Session close
                to the persistence layer. Use an EJB stateful session bean to
                hold the <literal>Session in a three-tier environment. Do not transfer
                it to the web layer, or even serialize it to a separate tier, to store it in the
                <literal>HttpSession.
            </para>

            <para>
                The extended session pattern, or <emphasis>session-per-conversation, is
                more difficult to implement with automatic current session context management.
                You need to supply your own implementation of the <literal>CurrentSessionContext
                for this. See the Hibernate Wiki for examples.
            </para>

        </section>

        <section id="transactions-optimistic-detached">
            <title>Detached objects and automatic versioning

            <para>
                Each interaction with the persistent store occurs in a new <literal>Session.
                However, the same persistent instances are reused for each interaction with the database.
                The application manipulates the state of detached instances originally loaded in another
                <literal>Session and then reattaches them using Session.update(),
                <literal>Session.saveOrUpdate(), or Session.merge().
            </para>

            <programlisting role="JAVA">

            <para>
                Again, Hibernate will check instance versions during flush, throwing an
                exception if conflicting updates occurred.
            </para>

            <para>
                You can also call <literal>lock() instead of update(),
                and use <literal>LockMode.READ (performing a version check and bypassing all
                caches) if you are sure that the object has not been modified.
            </para>

        </section>

        <section id="transactions-optimistic-customizing">
            <title>Customizing automatic versioning

            <para>
                You can disable Hibernate's automatic version increment for particular properties and 
                collections by setting the <literal>optimistic-lock mapping attribute to 
                <literal>false. Hibernate will then no longer increment versions if the 
                property is dirty.
            </para>

            <para>
                Legacy database schemas are often static and cannot be modified. Or, other applications
                might access the same database and will not know how to handle version numbers or
                even timestamps. In both cases, versioning cannot rely on a particular column in a table.
                To force a version check with a
                comparison of the state of all fields in a row but without a version or timestamp property mapping, 
		turn on <literal>optimistic-lock="all"
                in the <literal><class> mapping. This conceptually only works
                if Hibernate can compare the old and the new state (i.e., if you use a single long
                <literal>Session and not session-per-request-with-detached-objects).
            </para>

            <para>
                Concurrent modification can be permitted in instances where the changes that have been
                made do not overlap. If you set <literal>optimistic-lock="dirty" when mapping the
                <literal><class>, Hibernate will only compare dirty fields during flush.
            </para>

            <para>
                In both cases, with dedicated version/timestamp columns or with a full/dirty field
                comparison, Hibernate uses a single <literal>UPDATE statement, with an
                appropriate <literal>WHERE clause, per entity to execute the version check
                and update the information. If you use transitive persistence to cascade reattachment
                to associated entities, Hibernate may execute unnecessary updates. This is usually
                not a problem, but <emphasis>on update triggers in the database might be
                executed even when no changes have been made to detached instances. You can customize
                this behavior by setting  <literal>select-before-update="true" in the
                <literal><class> mapping, forcing Hibernate to SELECT
                the instance to ensure that changes did occur before updating the row.
            </para>

        </section>

    </section>

    <section id="transactions-locking">
        <title>Pessimistic locking

        <para>
            It is not intended that users spend much time worrying about locking strategies. It is usually
            enough to specify an isolation level for the JDBC connections and then simply let the
            database do all the work. However, advanced users may wish to obtain
            exclusive pessimistic locks or re-obtain locks at the start of a new transaction.
        </para>

        <para>
            Hibernate will always use the locking mechanism of the database; it never lock objects
            in memory.
        </para>

        <para>
            The <literal>LockMode class defines the different lock levels that can be acquired
            by Hibernate. A lock is obtained by the following mechanisms:
        </para>

        <itemizedlist spacing="compact">
            <listitem>
                <para>
                    <literal>LockMode.WRITE is acquired automatically when Hibernate updates or inserts
                    a row.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>LockMode.UPGRADE can be acquired upon explicit user request using
                    <literal>SELECT ... FOR UPDATE on databases which support that syntax.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>LockMode.UPGRADE_NOWAIT can be acquired upon explicit user request using a
                    <literal>SELECT ... FOR UPDATE NOWAIT under Oracle.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>LockMode.READ is acquired automatically when Hibernate reads data
                    under Repeatable Read or Serializable isolation level. It can be re-acquired by explicit user
                    request.
                </para>
            </listitem>
        <listitem>
        <para>
            <literal>LockMode.NONE represents the absence of a lock. All objects switch to this
            lock mode at the end of a <literal>Transaction. Objects associated with the session
            via a call to <literal>update() or saveOrUpdate() also start out
            in this lock mode.
        </para>
        </listitem>
        </itemizedlist>

        <para>
            The "explicit user request" is expressed in one of the following ways:
        </para>

        <itemizedlist spacing="compact">
            <listitem>
                <para>
                    A call to <literal>Session.load(), specifying a LockMode.
                </para>
            </listitem>
            <listitem>
                <para>
                    A call to <literal>Session.lock().
                </para>
            </listitem>
            <listitem>
                <para>
                    A call to <literal>Query.setLockMode().
                </para>
            </listitem>
        </itemizedlist>

        <para>
            If <literal>Session.load() is called with UPGRADE or
            <literal>UPGRADE_NOWAIT, and the requested object was not yet loaded by
            the session, the object is loaded using <literal>SELECT ... FOR UPDATE.
            If <literal>load() is called for an object that is already loaded with
            a less restrictive lock than the one requested, Hibernate calls
            <literal>lock() for that object.
        </para>

        <para>
            <literal>Session.lock() performs a version number check if the specified lock
            mode is <literal>READ, UPGRADE or
            <literal>UPGRADE_NOWAIT. In the case of UPGRADE or
            <literal>UPGRADE_NOWAIT, SELECT ... FOR UPDATE is used.
        </para>

        <para>
            If the requested lock mode is not supported by the database, Hibernate uses an appropriate
            alternate mode instead of throwing an exception. This ensures that applications are
            portable.
        </para>

    </section>

    <section id="transactions-connection-release">
        <title>Connection release modes

        <para>
            One of the legacies of Hibernate 2.x JDBC connection management 
            meant that a <literal>Session would obtain a connection when it was first
            required and then maintain that connection until the session was closed.
            Hibernate 3.x introduced the notion of connection release modes that would instruct a session
            how to handle its JDBC connections.  The following discussion is pertinent
            only to connections provided through a configured <literal>ConnectionProvider.
            User-supplied connections are outside the breadth of this discussion.  The different
            release modes are identified by the enumerated values of
            <literal>org.hibernate.ConnectionReleaseMode:
        </para>

        <itemizedlist spacing="compact">
            <listitem>
                <para>
                    <literal>ON_CLOSE: is the legacy behavior described above. The
                    Hibernate session obtains a connection when it first needs to perform some JDBC access
                    and maintains that connection until the session is closed.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>AFTER_TRANSACTION: releases connections after a
                    <literal>org.hibernate.Transaction has been completed.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>AFTER_STATEMENT (also referred to as aggressive release):
                    releases connections after every statement execution. This aggressive releasing
                    is skipped if that statement leaves open resources associated with the given session.
                    Currently the only situation where this occurs is through the use of
                    <literal>org.hibernate.ScrollableResults.
                </para>
            </listitem>
        </itemizedlist>

        <para>
            The configuration parameter <literal>hibernate.connection.release_mode is used
            to specify which release mode to use.  The possible values are as follows:
        </para>

        <itemizedlist spacing="compact">
            <listitem>
                <para>
                    <literal>auto (the default): this choice delegates to the release mode
                    returned by the <literal>org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()
                    method.  For JTATransactionFactory, this returns ConnectionReleaseMode.AFTER_STATEMENT; for
                    JDBCTransactionFactory, this returns ConnectionReleaseMode.AFTER_TRANSACTION.  Do not
                    change this default behavior as failures due to the value of this setting
                    tend to indicate bugs and/or invalid assumptions in user code.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>on_close: uses ConnectionReleaseMode.ON_CLOSE.  This setting
                    is left for backwards compatibility, but its use is discouraged.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>after_transaction: uses ConnectionReleaseMode.AFTER_TRANSACTION.
                    This setting should not be used in JTA environments.  Also note that with
                    ConnectionReleaseMode.AFTER_TRANSACTION, if a session is considered to be in auto-commit
                    mode, connections will be released as if the release mode were AFTER_STATEMENT.
                </para>
            </listitem>
            <listitem>
                <para>
                    <literal>after_statement: uses ConnectionReleaseMode.AFTER_STATEMENT.  Additionally,
                    the configured <literal>ConnectionProvider is consulted to see if it supports this
                    setting (<literal>supportsAggressiveRelease()).  If not, the release mode is reset
                    to ConnectionReleaseMode.AFTER_TRANSACTION.  This setting is only safe in environments where
                    we can either re-acquire the same underlying JDBC connection each time you make a call into
                    <literal>ConnectionProvider.getConnection() or in auto-commit environments where
                    it does not matter if we re-establish the same connection.
                </para>
            </listitem>
        </itemizedlist>

    </section>

</chapter>

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate transactions.xml source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.