views:

500

answers:

1

I've done quite a bit a research on this with no luck, but all the answers have a tendency to point toward the session context settings in the config file. What is odd is that I get a session connection the very first time I hit the page (and therefore, a successful result set), but then when I reload I get the following exception: org.hibernate.SessionException: Session is closed!

Here are my config settings that are not DB connection string related:

<property name="hibernate.show_sql">false</property>
<property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>        
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.cache.use_query_cache">false</property>
<property name="hibernate.cache.use_minimal_puts">false</property>

Here is an example of a call I make that produces the situation I described above.

public T get(int id) {
    session.beginTransaction();
    T type;
    try {
        type = getTypeClass().cast(session.get(getTypeClass(), id));
    } catch (ClassCastException classCastException) {
        throw new ClassCastException(classCastException.getMessage());
    }
    session.getTransaction().commit();
    return type;
}

The session variable reference is to a static field that contains the current session. All of the session connection details are textbook reference manual. For example, here is my Hibernate session utility:

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactoryUtil {

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}
A: 

When you get a Session with sessionFactory.getCurrentSession(), the Session is flushed and closed automatically when the transaction is commited (see Sessions and transactions for more details on this). So, here I suspect that 1. you get the Session once for all (this would explain why the first call works and why subsequent calls fail) which is wrong and 2. you seem to use the session-per-operation anti-pattern which is even worse.

In a web application, you should use a session-per-request strategy which means that "a single Session and a single database transaction implement the processing of a particular request event". Again, refer to the Sessions and transactions document.

And if you want to remove transaction demarcation from your data access code, then you could use an interceptor to start a database transaction at the begin of each request and commit it at the end of the request. Have a look at the Open Session in View for an implementation of this pattern (with a sample DAO demonstrating the benefits).

Pascal Thivent
The problem with all this is: 1) The reference documentation uses a basic example which they immediately tell you afterward is incorrect for production scenarios (leaving much to be desired regarding common scenarios). 2) Transactions are almost always operational, but the documentation shows one transaction per session per request. Since when does anyone use one transaction for an entire request scope? You might have three separate transactions you need to roll back during the request. This is one area where Hibernate needs to do a better job with documentation.
hal10001
In the end the issue was related to how I was handling the session variable reference. I'll probably move the open/close session handling into a filter, and then manage the individual transactions per operation (or set of operations).
hal10001
@hal10001 I do not agree that transactions are almost always operational, you do **not** want to commit the "half of a request" (the session-per-operation is not called an anti-pattern for nothing), using one transaction per request is the way to go.
Pascal Thivent