Reducing Session Creation Impact with ThreadLocal
You can reduce the impact of retrieving a new Session object for each thread by reusing the Session for a given object. As described in Chapter 6 and Chapter 9, a Session is not sharable across threads. The code in Listing 12.3 shows a Hibernate-recommended mechanism for maintaining a per-thread Session variable. The real work of this code is done in the java.lang.ThreadLocal class, which simplifies the use of a per-thread variable.
Listing 12.3. THReadLocal Example
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
sessionFactory =
new Configuration().configure()
.buildSessionFactory();
} catch (HibernateException ex) {
throw new RuntimeException(
"Exception building SessionFactory: "
+ ex.getMessage(), ex);
}
}
public static final java.lang.ThreadLocal
session = new java.lang. ThreadLocal();
public static Session currentSession() throws
HibernateException {
Session s = (Session) session.get();
// Open a new Session, if this Thread has none yet
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void discardSession() throws
HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
With luck, you should already have your Session management contained in a specific class with a static method, as shown in Chapter 2. The biggest difficulty with the pattern shown in Listing 12.3 is that a Session object can be rendered into an untenable state if a transaction-related exception is shown (Hibernate explicitly does not allow reuse of a Session object in this situation). This is why an additional discardSession() method is shown above; you need to ensure that the Session object is discarded if your application throws a transaction-related exception, as shown in the discardSession() method.
|