Spring + Hibernate populating holder class with values from DB

◇◆丶佛笑我妖孽 提交于 2019-12-12 06:47:40

问题


For my web app I will loading a few details from the static DB tables which I plan to load when the container starts up on a HolderClass in a singleton bean. I will inject this class wherever I wish to use the static data. So basically I want to avoid loading the static data everytime from DB

Current Implementation:

public Class CountryHolder(){
    List<Country> allCountries;

    public void init(){
       this.countries = loadAllCountries;
    }

    public List<Country> loadAllCountries(){
     // Perform DB select query using JDBC template
    }

The above implementation works perfectly fine that is the init method loads the list of Countries for my bean. But now I have migrated to Hibernate and Country is a Persisten Entity.

Hibernate:

@Transactional(readOnly ="true")
public List<Country> loadAllCountries(){
   return countryDao.findAll();
}

Please note I have skipped the code where I am injecting the dao and jdbc template. But the issue is that since I am calling this method in init method Hibernate complains about no session found to this although I have declared it as a readOnly transaction.

Please advise


回答1:


First of all, since Spring doesn't do persistence itself, it cannot specify what readOnly should exactly mean. This attribute is only a hint to the provider, the behavior depends on, in this case, Hibernate.

If you specify readOnly as true, the flush mode will be set as FlushMode.NEVER in the current Hibernate Session preventing the session from commiting the transaction.

Furthermore, setReadOnly(true) will be called on the JDBC Connection, which is also a hint to the underlying database. If your database supports it (most likely it does), this has basically the same effect as FlushMode.NEVER, but it's stronger since you cannot even flush manually.

It will be more helpful if you post Hibernate context?

Updated

What you think about using ApplicationContext or DI

My idea to use an bean class which will be get loaded at the time of spring container is loading.In that bean class you will connect to DB fetch records and use where you want to use without going to DB each time.

I am doing this in my project where I am fetching some Menus from DB when server context get loaded and use it without roundTriping to DB each time.




回答2:


Okay then I will just post what I did to load Masters from DB on server context loading.

HibernateHelper.java

public final class HibernateHelper 
{
private static SessionFactory sessionFactory;

static 
{
    try {
        // Create the SessionFactory from standard (hibernate.cfg.xml)
        // config file.

        Configuration cfg = new Configuration();

        cfg.configure("hibernate.cfg.xml");

        ServiceRegistry sr = new ServiceRegistryBuilder().applySettings(cfg.getProperties)).buildServiceRegistry();
        SessionFactory tempSessionFactory = cfg.buildSessionFactory(sr);
        sessionFactory = tempSessionFactory;

        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
}


public Session getSession() 
{
    SessionFactory sessionFactory = getSessionFactory();
        return sessionFactory.openSession();
}

private static SessionFactory getSessionFactory() 
{
    return sessionFactory;
}
}

HibernateHelper class will help to buildSessionFactory by reading hibernate.cfg.xml.This class having getSession()which returnsession`.

HibernateHelper_DI.xml

<bean id="Hhelper" class="util.HibernateHelper" />

An DI xml file which is responsible for creating singalton bean of HibernateHelper.

MasterHelper.java

public final class MasterHelper implements ApplicationContextAware 
{
       private static getMasterServiceImpl runtimeServiceImpl;
       private static List<Master> masters=null;

       public static List<Master> getMasters()
       {
         if(masters==null)
         {
          loadMasters();
         }
         return masters;
       }

       private static void loadMasters()
       {
          try
          {      
             if(masters==null){      
            masters=runtimeServiceImpl.getMasters();            
            }
          }
          catch(Exception e)
          {
           masters=null;
           throw e;
          }    
       }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {

            runtimeServiceImpl= (getMasterServiceImpl) applicationContext
                    .getBean("getMasterService");
         }   


}

getMasterService_DI.xml

<bean id="getMasterService" class="service.getMasterServiceImpl" />

An DI xml file which is responsible for creating singalton bean of getMasterServiceImpl.

MasterHelper_DI.xml

<bean id="MasterHelper" class="service.MasterHelper" />

An DI xml file which is responsible for creating singalton bean of MasterHelper.

By this config. spring knows from where DI files is get read.

root-context.xml

<import resource="classpath:DI/*.xml" />

web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

When context loading is going on, with the help of web.xml and root-context.xml spring reads DI files and make beans accordingly.

When HibernateHelper bean is created sessionfactory is also created and kept in static object.In the same fashion when MasterHelper bean is created.

When you call MasterHelper.getMasters(); for the first time anywhere in web application it will goes to DB load the masters and assign to static masters.Next time when you call MasterHelper.getMasters(); it will check for null condition to static master.

if you want at the time of bean creation you want to load masters then you can use change method setApplicationContext() in MasterHelper as follows:

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {

        runtimeServiceImpl= (getMasterServiceImpl) applicationContext
                .getBean("getMasterService");
                loadMasters(); //IMPOTANT TO CALL HERE ONLY,BCOZ loadMasters NEED BEAN OF       getMasterServiceImpl
     }   

Hope This will help you.

All above code is written manually at here only so there may be some syntax error(s) are there, please correct if any found



来源:https://stackoverflow.com/questions/21131746/spring-hibernate-populating-holder-class-with-values-from-db

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!