javaspringhibernatesessionfactory

Hibernate Sessionfactory restart | Spring


My requirement is as follows:

I need to restart(or rebuild) hibernate session factory in my Spring web application at frequent intervals with the new HBM files I get from outside.

Currently my Sessionfactory class is as follows with a SessionFactory Proxy to intercept 'OpenSession' call.

There I am checking for a condition to restart and rebuilding sessionFactory.

My problem here is , in concurrent environment the other users who are in middle of other transaction is getting affected during this restart.

Is there anyway to carryout the restart by checking all the transactions and open sessions and carry out rebuilding session factory once all other completes?

or any other solution exists.

Code:

public class DataStoreSessionFactory extends LocalSessionFactoryBean
{


   private boolean restartFactory = false;



   @Override
   protected void postProcessConfiguration(Configuration config) throws HibernateException
   {
      super.postProcessConfiguration(config);
      updateHBMList(config);
   }


   private void updateHBMList(final Configuration config)
   {

      config.addXML(modelRegistry.generateMapping());
   }

   @Override
   public SessionFactory getObject()
   {

      Object obj = super.getObject();

      /*
       * Invocation handler for the proxy
       */
      SessionFactoryProxy proxy = new SessionFactoryProxy(this, (SessionFactory) obj);

      /**
       * All the methods invoked on the returned session factory object will pass through this proxy's invocation
       * handler
       */
      SessionFactory sessionFactory = (SessionFactory) Proxy.newProxyInstance(getClass().getClassLoader(),
                                                                              new Class[] { SessionFactory.class },
                                                                              proxy);
      return sessionFactory;
   }

   static class SessionFactoryProxy implements InvocationHandler
   {


      private SessionFactory sessionFactory;

      private LocalSessionFactoryBean factoryBean;

      public SessionFactoryProxy(LocalSessionFactoryBean factoryBean, SessionFactory sessionFactory)
      {
         this.factoryBean = factoryBean;
         this.sessionFactory = sessionFactory;
      }

      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
      {
         /**
          * Only if the method invoked is openSession - check if the session factory should be restarted, and only then
          * invoke the requested method
          */
         if (method.getName().equals("openSession"))
         {
            restartSessionFactoryIfNecessary();
         }
         return method.invoke(sessionFactory, args);
      }

      private void restartSessionFactoryIfNecessary()
      {
         restartSessionFactory();
         /*if (((DataStoreSessionFactory) factoryBean).isRestartFactory())
         {
            restartSessionFactory();
         }*/
      }

      private synchronized void restartSessionFactory()
      {
         log.info("Restarting session...");
         factoryBean.destroy();
         try
         {
            factoryBean.afterPropertiesSet();
            sessionFactory = factoryBean.getObject();
         }
         catch (Exception e)
         {
            log.error("Error while restarting session: " + e.getMessage());
            throw new RuntimeException(e);
         }
      }
   }

Thanks, Appasamy


Solution

  • You can following SessionFactoryUtils to determine whether a transaction is taking place in Session factory and then decide to restart the session factory or not: You will need to import--> org.springframework.orm.hibernate.SessionFactoryUtils in you file, and use the following API.

    static boolean  hasTransactionalSession(SessionFactory sessionFactory); 
    

    Above API returns whether there is a transactional Hibernate Session for the current thread, that is, a Session bound to the current thread by Spring's transaction facilities.There is also another API just in case if you need to check if a session is transactional in session factory currently:

    static boolean isSessionTransactional(Session session,SessionFactory sessionFactory);
    

    Above API returns whether the given particular Hibernate Session is transactional, that is, bound to the current thread by Spring's transaction facilities.