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.

View the original post : 
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3946931#3946931

Reply to the post : 
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3946931


-------------------------------------------------------
All the advantages of Linux Managed Hosting--Without the Cost and Risk!
Fully trained technicians. The highest number of Red Hat certifications in
the hosting industry. Fanatical Support. Click to learn more
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=107521&bid=248729&dat=121642
_______________________________________________
JBoss-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to