2

I have configured Hibernate for my Spring application. I have a file called hibernateUtil.java that create a new session for Hibernate. The question is when should I call its getSession method? Is there any better approach to this?

Hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <property name="connection.url">
            jdbc:mysql://localhost:3306/mydb
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">12</property>

        <!-- SQL dialect -->
        <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>

        <property name="current_session_context_class">thread</property>


        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">update</property>

        <mapping class="com.myproject.model.business" />




    </session-factory>

</hibernate-configuration>

HibernateUtil.java

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

    private static ServiceRegistry serviceRegistry;
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
    private static SessionFactory sessionFactory;


    private static SessionFactory configureSessionFactory() {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();
            serviceRegistry = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties()).build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
            return sessionFactory;
        } catch (HibernateException e) {
            e.printStackTrace();
        }
        return sessionFactory;
    }

    static {
        try {
            sessionFactory = configureSessionFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private HibernateUtil() {
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static Session getSession() throws HibernateException {
        Session session = threadLocal.get();

        if (session == null || !session.isOpen()) {
            if (sessionFactory == null) {
                rebuildSessionFactory();
            }
            session = (sessionFactory != null) ? sessionFactory.openSession()
                    : null;
            threadLocal.set(session);
        }

        return session;


    }


    public static void rebuildSessionFactory() {
        try {
            sessionFactory = configureSessionFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
            if (session.isOpen()) {
                session.close();
            }
        }
    }
}

I've also found this tutorial but I am not sure if it is reliable or not. It suggested to use Spring bean configuration file for Hibernate configuration.

Jack
  • 6,430
  • 27
  • 80
  • 151
  • What is the purpose of having `HibernateUtil.getSession()` in the controller method? There is nothing in your controller code that requires a database interaction, so why would you want to get a session? A recommended pattern is to create the Session on a per HTTP request basis. This is explained in the [Hibernate documentation](http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch02.html#session-per-request). – manish Feb 27 '15 at 04:30
  • @manish I updated the question, I just put that in the controller to show the problem there is no specific reason for that. – Jack Feb 27 '15 at 04:55
  • @manish to show I do not know where and when I should call getsession method. – Jack Feb 27 '15 at 04:59
  • Move the `getSession` call to an HTTP `Filter`. – manish Feb 27 '15 at 04:59
  • @manish where can I find HTTP filter? as explained in the link you have sent, there should be a one to one relationship between transaction and session. What I do is before creating any transaction I first check to see if any session is already created if it is then use that session otherwise create a new session. What do you mean by HTTP filter? would you give me an example of that? – Jack Feb 27 '15 at 05:03
  • 1
    Take a look at [OpenSessionInViewFilter](https://github.com/spring-projects/spring-framework/blob/master/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java) from the Spring ORM module. Since you are already using Spring, you could consider adding the Spring ORM module to your application, getting rid of your custom `HibernateUtils` class and letting Spring manage your Hibernate sessions. – manish Feb 27 '15 at 05:08
  • @manish thats interesting thanks, however I just updated the question with another method of session management, – Jack Feb 27 '15 at 05:40
  • 1
    You are using Spring then let spring do the hard stuff for you. Ditch that `HibernateUtil` class and let spring worry about opening and closing sessions, this will save you headaches and really simplify your code. I strongly suggest a read of the [Spring reference guide](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html#orm-hibernate). – M. Deinum Mar 07 '15 at 20:37
  • @M.Deinum I read that but got confused, it talk about many different things, do you know of any tutorial that follow this? – Jack Mar 10 '15 at 00:13
  • @M.Deinum Ive found a tutorial to follow, I could configure the project but faced a problem that is mentioned here http://stackoverflow.com/questions/28955754/spring-fails-to-do-dependency-injection-for-sessionfactory – Jack Mar 10 '15 at 04:53

5 Answers5

1

If your application is a web app using java servlets, you could add a servlet request filter in which you can start a session or even a transaction. the same class can then be used to commit transaction and flush/close session. e.g (without error handling):

import javax.servlet.*;

public class HibernateSessionRequestFilter implements Filter {

public void doFilter(ServletRequest request, ServletResponse response,
                  FilterChain chain) throws IOException, ServletException {

    Session session=HibernateUtil.getSession();
    session.beginTransaction();

    // Call the next filter (continue request processing)
    chain.doFilter(request, response);

    session.flush();
    session.getTransaction().commit();
}
Maverik
  • 47
  • 4
1

Generally one would go by creating a generic dao implementation and let all the other daos extend this generic dao.(Please note that this is not that verbose, just for referring):

public interface GenericDAO<T, ID extends Serializable> {
    T save(T entity);
    void delete(T entity);
    }

Example implementation:

    public class GenericHibernateDAO<T, ID extends Serializable>
            implements GenericDAO<T, ID> {
        private Class<T> persistentClass;

        public GenericHibernateDAO() {
            this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                    .getGenericSuperclass()).getActualTypeArguments()[0];
        }

        private SessionFactory sessionFactory;

        public void setSessionFactory(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
        }

         public Session getSession()
        {
             return sessionFactory.getCurrentSession();
        }

        @Override
        public T save(T entity)
        {
            getSession().save(entity);
            return entity;
        }
        @Override
        public void delete(T entity) {
            getSession().delete(entity);        
        }
}

So, for example you create your Dao something like:

public class SampleHibernateDao extends
        GenericHibernateDAO<DomainObj, DomainObjId> implements SampleDAO {

@Override
    public List<Object> findAnything(String find)
            throws HibernateException {

        Query query = getSession()
                .createQuery(....)
}

}

I think you'll get a general idea.

Also, use spring to configure your sessionfactory like:

<!-- DB settings -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">

        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/xxxx" />
        <property name="username" value="root" />
        <property name="password" value="root" />
        <property name="validationQuery" value="SELECT 1" />
        <property name="testOnBorrow" value="true" />
    </bean>

    <!-- Hibernate Settings -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="com.xxx.xxx" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.connection.zeroDateTimeBehavior">convertToNull</prop>
            </props>
        </property>
        <property name="annotatedClasses">
            <list>

                <value>com.xx.xxx.xxx.Domain</value>
            </list>
        </property>

    </bean>

    <tx:annotation-driven transaction-manager="hibernateTransactionManager" />

    <bean id="hibernateTransactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
Sandeep B
  • 765
  • 1
  • 6
  • 19
0

Not sure what is rebuildSessionFactory() method. SessionFactory is Hibernates concept of a single datastore and is threadsafe so that many threads can access it concurrently and request for sessions and immutable cache of compiled mappings for a single database. A SessionFactory is usually only built once at startup

Sessions are a Hibernate construct used to mediate connections with the database. The session opens a single database connection when it is created, and holds onto it until the session is closed. Every object that is loaded by Hibernate from the database is associated with the session, allowing Hibernate to automatically persist objects that are modified, and allowing Hibernate to implement functionality such as lazy-loading.

public class HibernateUtil { 

    public static final ThreadLocal local = new ThreadLocal(); 

    public static Session currentSession() throws HibernateException { 
       Session session = (Session) local.get(); 
       //open a new session if this thread has no session 
       if(session == null) { 
          session = sessionFactory.openSession(); 
          local.set(session);     
       } 
      return session; 
   } 
} 

Also please check the difference between Detached, Persistent and Transient objects. Not sure why you are opening hibernate session in Controller.

Swathi
  • 602
  • 4
  • 17
  • Updated the question, no specific reason for having that code in controller, I just want to give an example. which looks like is not a good one. I know that there should be a one to one relationship between transaction and session. What I do is before creating any transaction I first check to see if any session is already created if it is then use that session otherwise create a new session. Whats your idea about this https://github.com/spring-projects/spring-framework/blob/master/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.java – Jack Feb 27 '15 at 05:17
0

You should obtain a session when (and where) you want a transaction. The idea is that you need a session for a transaction. And a session not being threadsafe, each thread or transaction should obtain its own instance.

Having said that, if you are using container managed persistence in a spring webapp, Spring or JPA annotations could inject that for you.

The code below is from https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html

A typical transaction should use the following idiom:

Session sess = factory.openSession();
 Transaction tx;
 try {
     tx = sess.beginTransaction();
     //do some work
     ...
     tx.commit();
 }
 catch (Exception e) {
     if (tx!=null) tx.rollback();
     throw e;
 }
 finally {
     sess.close();
 }
Atul
  • 2,673
  • 2
  • 28
  • 34
  • Thats correct however it is always creating a new session. The problem is creating new session is expensive so it is better to have a session management. I just updated the question with a separate method to how I am managing the sessions. – Jack Feb 27 '15 at 05:38
  • 1
    @Jack Again from hibernate docs site - "If the Session throws an exception, the transaction must be rolled back and the session discarded. The internal state of the Session might not be consistent with the database after the exception occurs." Take a note of this when writing the code. – Atul Feb 27 '15 at 05:55
  • I see, then how can I create sessionFactory object? Also, in my current code the session will be set for threadlocal. what should I do with that? – Jack Feb 27 '15 at 06:01
  • Does your application conetext or beans xml define sessionFactory bean as a spring configured bean? If it does, then you don't have to create session factory. It can be injected where you want it. Also, I think session being ThreadLocal gives you thread safety. So would not bother much about that. Session per request is a common usage. http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch02.html#session-per-request So, I would get a session from factory every time I go for a transaction. – Atul Mar 03 '15 at 05:12
  • I would suggest so. Spring managing bean lifecycle will get rid of much headache. – Atul Mar 03 '15 at 11:47
  • How can I configure that? do you know of any reliable tutorial or resource? – Jack Mar 04 '15 at 01:45
  • @Jack http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html – Atul Mar 04 '15 at 07:13
0

I managed to remove the HibernateUtil and use Spring to manage my hibernate sessions by following M. Deinum's comment and this tutorial.

Add following to the project-servler.xml file along with adding required dependencies.

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />
    </bean>

   <tx:annotation-driven />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<bean id="userDao" class="net.codejava.spring.dao.UserDAOImpl">
<constructor-arg>
    <ref bean="sessionFactory" />
</constructor-arg>

After I added above lines, it ran into a dependency injection error that is mentioned here.

Community
  • 1
  • 1
Jack
  • 6,430
  • 27
  • 80
  • 151