Hibernate Session Factory

Lilit Mkrtchyan picture Lilit Mkrtchyan · Oct 13, 2013 · Viewed 21.3k times · Source

In our web application we have a HibernateSessionFactory class, that is opening and closing connections. Everything is okay, but when we are updating data in the database, it doesn't change in our application. Unfortunately, we see old data from the database. How can I fix it?

public class HibernateSessionFactory {

    private static final ThreadLocal threadLocal = new ThreadLocal();
    private static org.hibernate.SessionFactory sessionFactory;

    private static Configuration configuration = new Configuration();
    private static ServiceRegistry serviceRegistry; 

    private static final Logger log = Logger.getLogger(HibernateSessionFactory.class);

    static {
        try {
            configuration.configure();
            serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
            . buildServiceRegistry();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        } catch (Exception e) {
            log.error("Error Creating SessionFactory",e);

        }
    }

    private HibernateSessionFactory() {
    }

    public static Session getSession() throws HibernateException {
        Session 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 {
            configuration.configure();
            serviceRegistry = new ServiceRegistryBuilder(). applySettings(configuration.getProperties()) 
            .buildServiceRegistry();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        } catch (Exception e) {
            log.error("Error Creating SessionFactory",e);
        }
    }

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

        }
    }

    public static org.hibernate.SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static Configuration getConfiguration() {
        return configuration;
    }

}

Answer

LMG picture LMG · Oct 13, 2013

Hibernate is a sofisticated and complex framework for building a layer between your program and the database, providing an object oriented model to help object oriented programs in their job.

In order to do this, and to be more performat of course, it creates a cache which stores somehow some of the data coming from the database, or going to the database.

I think that this problem is NOT concerning the connection to the database but rather how you save and retrive data. I'll try to explain my self better: when you query database to save data you do the following steps:

  1. open session
  2. open transaction
  3. build object
  4. flush and save object in session
  5. commit transaction
  6. close transaction
  7. close session

eg

public Boolean saveNewCliente(Cliente c) {
    Session s = getSession();
    Transaction t = null;
    try {
        t = s.beginTransaction();
        s.save(c);
        s.flush();
        t.commit();
        s.close();
        return true;
    } catch (Exception e) {
         if (t!=null) t.rollback();
        System.out.println(e.getMessage());
        return false;
    }
    finally{
        s.close();
    }

}

A common pitfall happens when you query database to fetch data, is to leave the part relating the transaction out of your "query" steps. As well for saving data you have to

  1. open session
  2. open transaction
  3. build query / criteria
  4. execute query over session
  5. close transaction
  6. close session

If you don't follow this steps is possible that you have stale data in your application, but not in your database. A check may be to execute your update/save-query and check manually in the database if the data has changed/created. If your application then loads stale data you know you do the fetch-query in the wrong way(without using transaction). Here's a snipped of example

    public Cliente get(Integer id) {
    Session s = getSession();
    Transaction tx = s.beginTransaction();
    try {
        System.out.println("get cliente by id");
        Cliente res = new Cliente();
        res = (Cliente) s.get(Cliente.class, id);
        tx.commit();
        return res;
    } catch (Exception e) {
        tx.rollback();
        System.out.println(e.getMessage());
        return null;
    }finally{
        s.close();
    }
}

If you want to furthermore investigate you can suspend the usage of cache by hibernate, you can do it in the following way, but remember that if data is cached there is a reason ;) This can be useful as a quick test in order to proceed in discovering if the error is due to wrong query usage.

You should add this to your hibernate config xml

<!-- to disable cache -->
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>