1 2 Previous Next 18 Replies Latest reply on May 31, 2006 4:05 AM by Manik Surtani

    Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING

    Borut ?agar Newbie

      Hi.

      Can OPTIMISTIC LOCKING be used with Hibernate 3.1.x or is Hibernate 3.2 (with it's OptimisticTreeCacheProvider) a requirement for it?

      Because if I enable OL in treecache.xml I am getting messages like the one below:

      16:52:34,281 INFO [OptimisticNodeInterceptor] CRUD Method _put(GlobalTransaction:<null>:41, /org/hibernate/cache/UpdateTimestampsCache/EVENT_LOG, item, 11473592142, true, 0) called - don't know how to handle!



      I am using JBossCache 1.3sp2 and Hibernate 3.1.3.

      Regards,
      Borut

        • 1. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
          Manik Surtani Master

          Yes, you need the provider from 3.2 (which you could backport from the 3.2 src tree to 3.1.x) to use opt locking.

          • 2. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
            Jaka Jaksic Newbie

            We are having severe problems using JBossCache 1.3's optimistic locking with Hibernate. We tried with Hibernate 3.2 CR2 as well as backporting the optimistic provider to 3.1.3 -- problems are the same.

            The first problem was with cache invalidation within a JTA transaction. Namely, cache invalidation wasn't performed outside the scope of transaction, and because transaction was already committed at that moment, errors occured. I first thought this was a bug in Hibernate's OptimisticTreeCache, so I reported the issue here: http://opensource.atlassian.com/projects/hibernate/browse/HHH-1764
            (check it out as it contains a detailed description). I also fixed this problem by adding a tx.suspend() call to Hibernate's class. However, according to this wiki page: http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheOptionsAPI, the failSilently option, which Hibernate does use in this place, should also have the effect of cache bypassing the transaction, but this just doesn't happen -- cache invalidation happens within JTA transaction and an exception is thrown (or perhaps it's just logged, but that's still unacceptable, since this happens after *every* commit). So now I believe the Hibernate guys are innocent and that the bug lies within JBossCache ;)


            This was the first problem, for which I could create a workaround, so it's not that critical. Now comes the real trouble, which I couldn't even get to understand, much less solve...

            After using optimistic locking in semi-production environment for a while, we started getting "DataNode version is newer than workspace node" errors. If I understand correctly, this should only occur when two versions of an object are more or less simultaneously read, modified and committed. However, we are getting these errors in places and with objects where we don't do any modification at all. One type of object that causes these errors is in fact modified nowhere in the entire application (after creation) and its cache is configured read-only, but we still get these errors!

            What's worse, it seems that once an object triggers this error, the errors always occur from that point on, whenever that same object is used. For example, if MyClass first causes the error at version 4-5, it goes like this:

            [MyClass#123] version DefaultDataVersion(5) is newer than workspace node DefaultDataVersion(4)
            ...
            [MyClass#123] version DefaultDataVersion(6) is newer than workspace node DefaultDataVersion(5)
            ...


            The object never starts working again unless the application is restarted.

            And something else is also very interesting. We get this same error on the root node (fqn="/")!

            2006-05-18 08:47:45,613 INFO [org.jboss.cache.interceptors.OptimisticValidatorInterceptor] DataNode [/] version DefaultDataVersion(30) is newer than workspace node DefaultDataVersion(29)
            2006-05-18 08:47:45,626 ERROR [org.hibernate.transaction.JTATransaction] JTA commit failed
            org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl[FormatId=257, GlobalId=server1/15236, BranchQual=, localId=15236] status=STATUS_NO_TRANSACTION; - nested throwable: (java.lang.RuntimeException: )
            ...
            Caused by: org.jboss.cache.CacheException: unable to validate nodes
             at org.jboss.cache.interceptors.OptimisticValidatorInterceptor.validateNodes(OptimisticValidatorInterceptor.java:109)
             at org.jboss.cache.interceptors.OptimisticValidatorInterceptor.invoke(OptimisticValidatorInterceptor.java:64)
             at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
             at org.jboss.cache.interceptors.OptimisticLockingInterceptor.invoke(OptimisticLockingInterceptor.java:87)
             at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
             at org.jboss.cache.interceptors.InvalidationInterceptor.invoke(InvalidationInterceptor.java:54)
             at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
             at org.jboss.cache.interceptors.TxInterceptor.runPreparePhase(TxInterceptor.java:781)
             at org.jboss.cache.interceptors.TxInterceptor$LocalSynchronizationHandler.beforeCompletion(TxInterceptor.java:1043)
             ... 71 more


            This error happens only once, soon after application start, and this is the only one we can reproduce in a development environment (but not figure out what causes it and why). Other errors seem random, but they happen too frequently, and once they occur, they don't go away...

            Please help! Right now we can't possibly use optimistic locking in production and we have to go back to 1.2.4 and pessimistic.


            Regards,
            Jaka

            • 3. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
              Manik Surtani Master

              Hi,

              Looking into this. Can you provide any clues as to what triggers the errors repeating themselves? Do you have a unit test that reproduces this?

              Thanks,
              Manik

              • 4. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                Jaka Jaksic Newbie

                No, we don't have any clues whatsoever. We already spent quite a lot of time trying to find the reason ourselves, but with no luck. Most of these errors appear what seems completely at random after a longer period of application run time. The only clue that might help is perhaps that if we use pessimistic locking, we are getting errors like this:

                2006-05-22 12:15:22,520 ERROR [org.jboss.cache.lock.IdentityLock] write lock for /org/hibernate/cache/UpdateTimestampsCache/TASK_INSTANCE_PARAM could not be acquired after 0 ms. Locks: Read lock owners: {}
                Write lock owner: GlobalTransaction:<192.168.170.170:50108>:1458
                 (caller=GlobalTransaction:<192.168.170.170:50108>:1457, lock info: write owner=GlobalTransaction:<192.168.170.170:50108>:1458 (activeReaders=0, activeWriter=Thread[TP-Processor1,5,jboss], waitingReaders=0, waitingWriters=0, waitingUpgrader=0))
                2006-05-22 12:15:22,520 INFO [org.jboss.cache.interceptors.TxInterceptor] There was a problem handling this request
                org.jboss.cache.lock.TimeoutException: write lock for /org/hibernate/cache/UpdateTimestampsCache/TASK_INSTANCE_PARAM could not be acquired after 0 ms. Locks: Read lock owners: {}
                Write lock owner: GlobalTransaction:<192.168.170.170:50108>:1458
                 (caller=GlobalTransaction:<192.168.170.170:50108>:1457, lock info: write owner=GlobalTransaction:<192.168.170.170:50108>:1458 (activeReaders=0, activeWriter=Thread[TP-Processor1,5,jboss], waitingReaders=0, waitingWriters=0, waitingUpgrader=0))
                 at org.jboss.cache.lock.IdentityLock.acquireWriteLock(IdentityLock.java:185)
                 at org.jboss.cache.Node.acquireWriteLock(Node.java:557)
                 at org.jboss.cache.Node.acquire(Node.java:517)
                 at org.jboss.cache.interceptors.PessimisticLockInterceptor.lock(PessimisticLockInterceptor.java:199)
                 at org.jboss.cache.interceptors.PessimisticLockInterceptor.invoke(PessimisticLockInterceptor.java:132)
                 at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
                 at org.jboss.cache.interceptors.UnlockInterceptor.invoke(UnlockInterceptor.java:32)
                 at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
                 at org.jboss.cache.interceptors.InvalidationInterceptor.invoke(InvalidationInterceptor.java:54)
                 at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
                 at org.jboss.cache.interceptors.TxInterceptor.handleNonTxMethod(TxInterceptor.java:328)
                 at org.jboss.cache.interceptors.TxInterceptor.invoke(TxInterceptor.java:139)
                 at org.jboss.cache.interceptors.Interceptor.invoke(Interceptor.java:67)
                 at org.jboss.cache.interceptors.CacheMgmtInterceptor.invoke(CacheMgmtInterceptor.java:153)
                 at org.jboss.cache.TreeCache.invokeMethod(TreeCache.java:4804)
                 at org.jboss.cache.TreeCache.putFailFast(TreeCache.java:3207)
                 at org.hibernate.cache.TreeCache.put(TreeCache.java:74)
                 at org.hibernate.cache.UpdateTimestampsCache.preinvalidate(UpdateTimestampsCache.java:54)
                 at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:244)
                 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
                 at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
                 at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
                 at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
                 at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
                 at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
                 at org.hibernate.transaction.JTATransaction.commit(JTATransaction.java:135)


                "Lock could not be acquired after 0 ms." Our lock timeout is set appropriately (and doesn't help if we increase it to infinity), in fact we are using the http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHibernate.

                These errors happen with frequency similar to that of the errors that we get with optimistic locking, so there may be something in common. However, the pessimistic locking errors, other than filling our logs, don't seem to cause any problems in the application (which is strange). We've been getting them for months - ever since switching from JDBC to JTA transactions, I think, and there were no bug reports whatsoever. So this is the configuration we're using now, but of course we don't like it this way. Getting rid of these errors was also the main reason we wanted to switch to optimistic locking. However, the errors we got with optimistic locking proved quite fatal, so we switched back to pessimistic the same day.

                I hope this gives you some ideas. There may be something wrong with our Hibernate or Cache configuration, but that is unlikely, since we're not using them in any unusual way. We already gave up on this, but if you have any ideas how we could solve this together, we'll be happy to help.

                Regards,
                Jaka

                • 5. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                  Jaka Jaksic Newbie

                  What I wanted to say was that we are using the Hibernate recommended treecache configuration from http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossCacheHibernate.

                  • 6. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                    Manik Surtani Master

                    Hi,

                    Thanks for your comments. Your issue with pess. locking is unrelated. It's to do with Hibernate using putFailFast() on JBoss Cache, which should suppress and ignore such failures. Hibernate does not care if cache put()'s fail, and hence overrides the timeout with 0. The error message should be suppressed in this case since this is not an error but expected behaviour in this use case.

                    I'm still looking into this issue with opt. locking. Basically from what I gather, it is only a matter of time before you start seeing this? Do you have a lot of concurrent writes to the data?

                    Cheers,
                    Manik



                    • 7. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                      Jaka Jaksic Newbie

                      No, I don't think so. This is a (J)BPM application where each user has their own tasks etc., so concurrent modifications of the same data should be very rare. In any case, with only a couple of users (~20) using the application, as there were at the time we tested, it would be impossible to get that many concurrent modification errors in such a short time. And more importantly, we were getting these errors with objects that are modified very rarely or even never at all. Really, one type of these objects is never ever modified after being created, so how could it be "concurrently modified"???

                      Regarding those pessimistic locking errors: they seem to be suppressed in the way that they don't cause any malfunctioning, but why are they logged as ERROR? JBossCache 1.2.4 at least logged just the error alone, without the stack trace, but 1.3 logs the entire stack, which is really inappropriate for expected behaviour. Can this be switched off somehow?

                      • 8. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                        Manik Surtani Master

                         



                        Regarding those pessimistic locking errors: they seem to be suppressed in the way that they don't cause any malfunctioning, but why are they logged as ERROR? JBossCache 1.2.4 at least logged just the error alone, without the stack trace, but 1.3 logs the entire stack, which is really inappropriate for expected behaviour. Can this be switched off somehow?


                        This is what I mean. They should be suppressed in 1.3.x, rather than embellished. This is expected behaviour.



                        • 9. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                          Jaka Jaksic Newbie

                          I'm sorry to bother, Manik, but I'm really confused by your last sentence.

                          What do you mean by "they should be suppressed"?

                          a) That JBossCache 1.3 should have suppressed them, but doesn't, so this will be fixed in a later version.
                          b) That we should somehow suppress them (don't know how, other by disabling logging for org.jboss.cache.lock.IdentityLock).
                          c) That Hibernate should be fixed to suppress them.


                          As about those optimistic locking errors, do you have any ideas what might be causing them? (not rushing, just curious)


                          Regards,
                          Jaka

                          • 10. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                            Manik Surtani Master

                            And the correct answer is ... a)

                            :-) Sorry if I was unclear earlier.

                            At the moment I have no idea what may be causing your opt. locking errors - in fact I can't even recreate them. What else can you tell me about your setup? Are you using replication, invalidation or local mode? And sync or async communications?

                            Cheers,
                            Manik

                            • 11. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                              Jaka Jaksic Newbie

                              We were using INVALIDATION_ASYNC, although there's only one server (this is our staging server which has the same setup as production servers).

                              One thing that might be a bit odd about our setup is that some of our Hibernate classes' cache is set to read only, because the objects are not modified after they are created. This is an optimization which causes Hibernate to complain with warnings during startup but other than that it doesn't seem to have any negative effects.

                              Here's the whole configuration file:

                              <server>
                              
                               <classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
                              
                              
                               <!-- ==================================================================== -->
                               <!-- Defines TreeCache configuration -->
                               <!-- ==================================================================== -->
                              
                               <mbean code="org.jboss.cache.TreeCache"
                               name="jboss.cache:service=TreeCache">
                              
                               <depends>jboss:service=Naming</depends>
                               <depends>jboss:service=TransactionManager</depends>
                              
                               <!--
                               Configure the TransactionManager
                               -->
                               <attribute name="TransactionManagerLookupClass">org.jboss.cache.GenericTransactionManagerLookup</attribute>
                              
                              
                               <!--
                               Node locking scheme:
                               OPTIMISTIC
                               PESSIMISTIC (default)
                               -->
                               <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
                              
                               <!--
                               Note that this attribute is IGNORED if your NodeLockingScheme above is OPTIMISTIC.
                              
                               Isolation level : SERIALIZABLE
                               REPEATABLE_READ (default)
                               READ_COMMITTED
                               READ_UNCOMMITTED
                               NONE
                               -->
                               <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
                              
                               <!--
                               Valid modes are LOCAL
                               REPL_ASYNC
                               REPL_SYNC
                               INVALIDATION_ASYNC
                               INVALIDATION_SYNC
                               -->
                               <attribute name="CacheMode">INVALIDATION_ASYNC</attribute>
                              
                               <!--
                               Just used for async repl: use a replication queue
                               -->
                               <attribute name="UseReplQueue">false</attribute>
                              
                               <!--
                               Replication interval for replication queue (in ms)
                               -->
                               <attribute name="ReplQueueInterval">0</attribute>
                              
                               <!--
                               Max number of elements which trigger replication
                               -->
                               <attribute name="ReplQueueMaxElements">0</attribute>
                              
                               <!-- Name of cluster. Needs to be the same for all clusters, in order
                               to find each other
                               -->
                               <attribute name="ClusterName">TreeCache-Cluster</attribute>
                              
                               <!-- JGroups protocol stack properties. Can also be a URL,
                               e.g. file:/home/bela/default.xml
                               <attribute name="ClusterProperties"></attribute>
                               -->
                              
                               <attribute name="ClusterConfig">
                               <config>
                               <!-- UDP: if you have a multihomed machine,
                               set the bind_addr attribute to the appropriate NIC IP address -->
                               <!-- UDP: On Windows machines, because of the media sense feature
                               being broken with multicast (even after disabling media sense)
                               set the loopback attribute to true -->
                               <UDP mcast_addr="228.1.2.3" mcast_port="48866"
                               ip_ttl="64" ip_mcast="true"
                               mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
                               ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
                               loopback="false"/>
                               <PING timeout="2000" num_initial_members="3"
                               up_thread="false" down_thread="false"/>
                               <MERGE2 min_interval="10000" max_interval="20000"/>
                               <!-- <FD shun="true" up_thread="true" down_thread="true" />-->
                               <FD_SOCK/>
                               <VERIFY_SUSPECT timeout="1500"
                               up_thread="false" down_thread="false"/>
                               <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
                               max_xmit_size="8192" up_thread="false" down_thread="false"/>
                               <UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
                               down_thread="false"/>
                               <pbcast.STABLE desired_avg_gossip="20000"
                               up_thread="false" down_thread="false"/>
                               <FRAG frag_size="8192"
                               down_thread="false" up_thread="false"/>
                               <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
                               shun="true" print_local_addr="true"/>
                               <pbcast.STATE_TRANSFER up_thread="true" down_thread="true"/>
                               </config>
                               </attribute>
                              
                               <!--
                               Whether or not to fetch state on joining a cluster
                               NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
                               -->
                               <attribute name="FetchInMemoryState">false</attribute>
                              
                               <!--
                               Number of milliseconds to wait until all responses for a
                               synchronous call have been received.
                               -->
                               <attribute name="SyncReplTimeout">20000</attribute>
                              
                               <!-- Max number of milliseconds to wait for a lock acquisition -->
                               <attribute name="LockAcquisitionTimeout">15000</attribute>
                              
                               <!--
                               The max amount of time (in milliseconds) we wait until the
                               initial state (ie. the contents of the cache) are retrieved from
                               existing members in a clustered environment
                               -->
                               <attribute name="InitialStateRetrievalTimeout">20000</attribute>
                              
                               <!-- Name of the eviction policy class. -->
                               <attribute name="EvictionPolicyClass"></attribute>
                              
                               <!--
                               Indicate whether to use marshalling or not. Set this to true if you are running under a scoped
                               class loader, e.g., inside an application server. Default is "false".
                               -->
                               <attribute name="UseMarshalling">false</attribute>
                              
                               </mbean>
                              </server>


                              • 12. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                                Manik Surtani Master

                                I've had this running for a while now (200 concurrent reader threads, each in a loop of 2000 iterations) and it always works fine every time. This is using LOCAL cache mode though, but since you see it with a single cache in the cluster it should not make a diff.

                                What else can you tell me about your read/write usage patterns?

                                • 13. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                                  Manik Surtani Master

                                  ok, attempting to recreate the full stack now with Hibernate 3.2.CR2. Which DB backend are you using?

                                  • 14. Re: Hibernate, JBoss Cache 1.3 and OPTIMISTIC LOCKING
                                    Jaka Jaksic Newbie

                                    Your numbers are impressive, but we are able to strike up those errors with far less traffic... ;)

                                    By the way, you were testing only read operations? I feel like those errors are somehow indirectly caused by write operations (although not necessarily on objects being modified -- don't ask...).

                                    We are using session-in-view pattern. The most I can do here is show you our code that handles Hibernate sessions and transactions. There are just a few functions.

                                    Whenever a Hibernate session is first requested within a request, we check the UserTransaction and reset it if necessary:

                                    private static final TransactionManager transactionManager;
                                     static {
                                     transactionManager = ((SessionFactoryImplementor) GlobalContext.getHibernateSessionFactory()).getTransactionManager();
                                     }
                                    
                                     public static boolean resetUserTransaction() {
                                     if (transactionManager == null) return false;
                                     try {
                                     final int status = transactionManager.getStatus();
                                     switch (status) {
                                     case Status.STATUS_MARKED_ROLLBACK:
                                     case Status.STATUS_ACTIVE:
                                     case Status.STATUS_PREPARED:
                                     case Status.STATUS_PREPARING:
                                     transactionManager.rollback();
                                     return true;
                                     }
                                     } catch (SystemException e) {
                                     log.error("Error resetting UserTransaction.", e);
                                     }
                                     return false;
                                     }


                                    Without this code, the UserTransaction sometimes gets left in a state which makes it unusable during the next request.

                                    After this is done, a new session is created and a transaction is started. This is the entire method:

                                    public static Session getHibernateSession() {
                                     final RequestContextInstance currentThreadContext = getOrCreateThreadContext();
                                     SessionImpl session = currentThreadContext.hibernateSession;
                                     if ((session == null) || (!session.isOpen())) {
                                     resetUserTransaction();
                                     try {
                                     session = (SessionImpl) GlobalContext.getHibernateSessionFactory().openSession(new SubjectRoleInterceptor());
                                     session.setFlushMode(FlushMode.COMMIT);
                                     } catch (Exception e) {
                                     currentThreadContext.errorMessage = e.getMessage();
                                     throw new RuntimeException("Error opening Hibernate session.", e);
                                     } finally {
                                     // Store the session in request context even in case of an error,
                                     // so that it will try to be closed at the end of the request.
                                     currentThreadContext.hibernateSession = session;
                                     }
                                     }
                                     final Transaction transaction = session.getTransaction();
                                     if (transaction == null || !transaction.isActive()) {
                                     try {
                                     session.beginTransaction();
                                     } catch (Exception e) {
                                     log.warn("Error starting transaction.");
                                     }
                                     }
                                     return session;
                                     }


                                    The session is then kept in a threadlocal variable for the duration of the request, after which it is closed and the transaction is committed if no errors occured during the request:

                                    public static boolean closeHibernateSession() {
                                     final RequestContextInstance currentThreadContext = getThreadContext();
                                     if (currentThreadContext == null) return false;
                                     final SessionImpl session = currentThreadContext.hibernateSession;
                                     if (session == null) return false;
                                     currentThreadContext.hibernateSession = null;
                                     if (session.isOpen()) {
                                     try {
                                     if (session.isTransactionInProgress()) {
                                     try {
                                     final Transaction transaction = session.getTransaction();
                                     transaction.rollback();
                                     } catch (HibernateException e) {
                                     log.error("Error during Hibernate transaction rollback.", e);
                                     }
                                     }
                                     session.close();
                                    GlobalContext.getHibernateSessionFactory());
                                     } catch (Throwable t) {
                                     log.error("Error closing Hibernate session. Will try to close the connection.", t);
                                     final Connection connection = session.connection();
                                     if (connection != null) {
                                     try {
                                     // At least close the connection if we could not close the session.
                                     connection.close();
                                     } catch (SQLException e) {
                                     log.error("Error closing database connection after unsuccessful attempt to close Hibernate session.", e);
                                     }
                                     }
                                     }
                                     resetUserTransaction();
                                     return true;
                                     } else {
                                     resetUserTransaction();
                                     return false;
                                     }
                                     }


                                    This is mostly all of our session handling code, the rest of the application code always just calls getHibernateSession() and gets a valid session. Most of the time there is just one transaction within a request. In some rare cases we flush the changes (= commit and reopen the transaction) in the middle of the request and continue. This is the code that handles this:

                                    public static boolean flushHibernateSession() {
                                     final RequestContextInstance currentThreadContext = getThreadContext();
                                     if (currentThreadContext == null) return false;
                                     final SessionImpl session = currentThreadContext.hibernateSession;
                                     if (session == null || session.isClosed()) return true;
                                    
                                     // If there was no error during the request, flush
                                     // the updates, otherwise discard them.
                                     if (currentThreadContext.errorMessage == null) {
                                     // If there an active transaction is present,
                                     // commit it, otherwise do a simple flush.
                                     if (session.isTransactionInProgress()) { // returns true when ACTIVE or MARKED_ROLLBACK
                                     try {
                                     final Transaction transaction = session.getTransaction();
                                     if (transaction.isActive()) {
                                     transaction.commit();
                                     return true;
                                     } else { // must be MARKED_ROLLBACK
                                     log.info("Transaction is MARKED_ROLLBACK - doing rollback instead of commit.");
                                     transaction.rollback();
                                     }
                                     } catch (HibernateException e) {
                                     currentThreadContext.errorMessage = e.getMessage();
                                     log.error("Error flushing Hibernate transaction. See previous exception for details.");
                                     }
                                     } else {
                                     try {
                                     session.flush();
                                     return true;
                                     } catch (HibernateException e) {
                                     currentThreadContext.errorMessage = e.getMessage();
                                     log.error("Error flushing Hibernate session. See previous exception for details.");
                                     }
                                     }
                                     } else {
                                     if (session.isTransactionInProgress()) {
                                     try {
                                     final Transaction transaction = session.getTransaction();
                                     transaction.rollback();
                                     } catch (HibernateException e) {
                                     log.error("Error during Hibernate transaction rollback.", e);
                                     }
                                     }
                                     session.clear();
                                     }
                                    
                                     // If no return true statement occured so far,
                                     // it means there must have been an error.
                                     return false;
                                     }


                                    There, now this is really all we ever do, the rest is just regular Hibernate use.

                                    Seeing your last post: our database is PostgreSQL 8.0.

                                    1 2 Previous Next