问题
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 return
session`.
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