Reputation: 85
I am developing jsf application and using hibernate as back end. I want create session factory and close it once through out application. I am creating Session factory with util class.
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
public class HibernateUtil
{
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
static
{
try
{
Configuration configuration = new Configuration().configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
catch (HibernateException he)
{
System.err.println("Error creating Session: " + he);
throw new ExceptionInInitializerError(he);
}
}
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}
public static void closeFactory() {
if (sessionFactory != null) {
try {
sessionFactory.close();
} catch (HibernateException ignored) {
log.error("Couldn't close SessionFactory", ignored);
}
}
}
In my every method of DAO classes I am opening session factory and closing it. So where i can open/close the session factory only once for application. Thanks in advance.
Upvotes: 4
Views: 25845
Reputation: 319
Where to open and where to close SessionFactory in my Application
You are using singleton session factory object. So you can call the getSessionFactory() method with class name. So that you do need to create object for session factory every time.
Your DAO class methods should like this
Method in DAO class
public boolean createUser(NewUserDTO newUserDTO) {
try {
sessionFactory = DBUtils.getSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
session.save(newUserDTO);
session.getTransaction().commit();
} catch (RuntimeException runtimeException) {
LOGGER.error(runtimeException);
transaction.rollback();
return false;
} finally {
if (session != null) {
session.close();
}
}
return true;
}
And session must be closed for every method. So that you are not creating session factory for every class.
Upvotes: -2
Reputation: 1
its not enough to close the session. You must additonally close the factory.
session.close();
session.getSessionFactory().close();
Upvotes: 0
Reputation: 1043
The best way is by using ThreadLocal
.
public class MyUtil {
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
private static final ThreadLocal<Session> threadLocal;
static {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
threadLocal = new ThreadLocal<Session>();
} catch(Throwable t){
t.printStackTrace();
throw new ExceptionInInitializerError(t);
}
}
public static Session getSession() {
Session session = threadLocal.get();
if(session == null){
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
public static void closeSession() {
Session session = threadLocal.get();
if(session != null){
session.close();
threadLocal.set(null);
}
}
public static void closeSessionFactory() {
sessionFactory.close();
StandardServiceRegistryBuilder.destroy(serviceRegistry);
}
}
Here, the SessionFactory
is initialized only once using the static
block.
Hence, whenever the main
class makes a call to getSession()
, the presence of Session object is first checked in the threadLocal
object.
Therefore, this program provides thread-safety.
After each operation, closeSession()
will close the session and set the threadLocal
object to null.
Finally call the closeSessionFactory()
.
Upvotes: 2
Reputation: 149125
The rule is that you should have one and only one SessionFactory throughout your application.
Where to open and close it depends on what the application is :
You can also use a singleton and create it in static method as you do and close it at the end like above.
But please do not close the session factory at the end of a DAO method.
For Sessions, you get one at the beginning of a unit of work through openSession
, and close it after commit or rollback (in case of exception you must rollback and immediately close the session). But Hibernate manual states : The scope of a Hibernate org.hibernate.Session is flexible but you should never design your application to use a new Hibernate org.hibernate.Session for every database operation. Even though it is used in the following examples, consider session-per-operation an anti-pattern.
Normally, you will use one single session per what needs a transaction. For example in a Web application, session per request is a common design.
But you could also use a higher level framework like Spring, that will do all SessionFactory and Session management for you.
Upvotes: 11
Reputation: 2807
SessionFactory: The job of SessionFactory is to handle all the sessions in the application. Generally, there is only one sessionFactory in the application which allows to create as many as sessions required to perform CRUD operations.
SessionFactory is immutable & threadsafe. Therefore multiple threads can access the same sessionFactory object.
static {
try {
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(
configuration.getProperties()).build();
sessionFactory = auditConfiguration.buildSessionFactory(serviceRegistry);
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
Session: Session is a light weight and a non-threadsafe object. Hence, session cannot be shared between multiple threads. It should be created for every transaction on DB either Create, Read, Update or Delete & must be closed when transaction is done.
try {
Session session = sessionFactory.openSession();
// do some CRUD operation
} catch(Exception ex) {
// On error, revert all changes done
if (transaction != null) {
transaction.rollback();
}
} finally {
if (session != null) {
session.close();
}
}
So I suggest u to open/close session
instead of sessionFactory
.
Upvotes: 5
Reputation: 4516
So where i can open/close the session factory only once for application.
A session factory is instantiated only once per application & gets destroyed when the app shuts down. A session factory is a factory of session so it's setup only once.
Regarding sessions, you should open & close a session in every method. You should not have too many open sessions.
So its a must that you close the session after the transaction.
When you don't close your Hibernate sessions and therefore do not release JDBC connections after every transaction, you have what is typically called Connection leak. So, after a number of requests (depending on the size of your connection pool) the server will not be able to acquire a connection to respond your request. Actually, server will be waiting for connections to be released and be available on pool again and it will seem to be hanging.
Upvotes: 0