Problem with spring quartz
I'm trying to invoke method based on some interval time, here are some beans inside applicationContext.xml
<bean id="MngtTarget"
class="com.management.engine.Implementation"
abstract="false" lazy-init="true" autowire="default" dependency-check="default">
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="MngtTarget" />
开发者_JS百科 <property name="targetMethod" value="findItemByPIdEndDate"/>
</bean>
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="jobDetail" />
<!-- 10 seconds -->
<property name="startDelay" value="10000" />
<!-- repeat every 50 seconds -->
<property name="repeatInterval" value="20000" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger" />
</list>
</property>
</bean>
Here is the method I'm trying to invoke :
public List<Long> I need findItemByPIdEndDate() throws Exception {
List<Long> list = null;
try{
Session session = sessionFactory.getCurrentSession();
Query query = session.getNamedQuery("endDateChecker");
list = query.list();
for(int i=0; i<list.size(); i++)
{
System.out.println(list.get(i));
}
System.out.println("Total " + list.size());
}catch (HibernateException e){
throw new DataAccessException(e.getMessage());
}
return list;
}
Here is the exception message that I get :
Invocation of method 'findItemByPIdEndDate' on target class [class com.management.engine.Implementation] failed; nested exception is No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
I've spent time googling alot so far also I've tried to modify my method like this :
public List<Long> I need findItemByPIdEndDate() throws Exception {
List<Long> list = null;
try{
Session session = sessionFactory.openSession();
Query query = session.getNamedQuery("endDateChecker");
list = query.list();
for(int i=0; i<list.size(); i++)
{
System.out.println(list.get(i));
}
System.out.println("Total " + list.size());
session.close();
}catch (HibernateException e){
throw new DataAccessException(e.getMessage());
}
return list;
}
And I get different error msg, I get : Invocation of method 'findItemByPIdEndDate' on target class [class com.management.engine.Implementation] failed; nested exception is could not execute query]
, anyone knows what is this all about, any suggestions ? thank you
Also my queries.hbm.xml
<hibernate-mapping>
<sql-query name="endDateChecker">
<return-scalar column="PId" type="java.lang.Long"/>
<![CDATA[select
item_pid as PId
from
item
where
end_date < trunc(sysdate)]]>
</sql-query>
</hibernate-mapping>
For the second error ("could not execute the query"), I don't know and I'm really wondering what the session looks like.
In deed, AFAIK, the persistent context is not available to Quartz Jobs as nothing take care of establishing a Hibernate Session for them (Quartz runs outside the context of Servlets and the open session in view pattern doesn't apply here). This is why you get the first error ("No hibernate session bound to thread").
One solution for this is described in AOP – Spring – Hibernate Sessions for background threads / jobs. In this post, the author shows how you can use Spring AOP proxies to wire a hibernate interceptor that gives you access to the persistence context and it takes cares of closing and opening the sessions for you.
Didn't test it myself though, but it should work.
I too was facing the same "HibernateException: No Hibernate Session bound to thread" exception
2012-01-13 13:16:15.005 DEBUG MyQuartzJob Caught an exception
org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:687)
at com.company.somemodule.dao.hibernate.AbstractHibernateDaoImpl.getSession(AbstractHibernateDaoImpl.java:107)
at com.company.somemodule.dao.hibernate.SomeDataDaoImpl.retrieveSomeData(SomeDataDaoImpl.java:264)
and I solved it by following the example here.
Relevant code
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import com.company.somemodule.dao.SomeDataDao;
import com.company.somemodule.SomeData;
public class MyQuartzJob extends QuartzJobBean implements Runnable {
private boolean existingTransaction;
private JobExecutionContext jobExecCtx;
private static Logger logger = LoggerFactory.getLogger(MyQuartzJob.class);
private SomeDataDao someDataDao; //set by Spring
private Session session;
private SessionFactory hibernateSessionFactory; //set by Spring
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException
this.jobExecCtx = ctx;
run();
}
private void handleHibernateTransactionIntricacies() {
session = SessionFactoryUtils.getSession(hibernateSessionFactory, true);
existingTransaction = SessionFactoryUtils.isSessionTransactional(session, hibernateSessionFactory);
if (existingTransaction) {
logger.debug("Found thread-bound Session for Quartz job");
} else {
TransactionSynchronizationManager.bindResource(hibernateSessionFactory, new SessionHolder(session));
}
}
private void releaseHibernateSessionConditionally() {
if (existingTransaction) {
logger.debug("Not closing pre-bound Hibernate Session after TransactionalQuartzTask");
} else {
TransactionSynchronizationManager.unbindResource(hibernateSessionFactory);
SessionFactoryUtils.releaseSession(session, hibernateSessionFactory);
}
}
@Override
public void run() {
// ..
// Do the required to avoid HibernateException: No Hibernate Session bound to thread
handleHibernateTransactionIntricacies();
// Do the transactional operations
try {
// Do DAO related operations ..
} finally {
releaseHibernateSessionConditionally();
}
}
public void setHibernateSessionFactory(SessionFactory hibernateSessionFactory) {
this.hibernateSessionFactory = hibernateSessionFactory;
}
public void setSomeDataDao(SomeDataDao someDataDao ) {
this.someDataDao = someDataDao ;
}
}
Relevant bean configuration inside applicationContext.xml
<bean name="myJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="com.somecompany.worker.MyQuartzJob" />
<property name="jobDataAsMap">
<map>
<entry key="hibernateSessionFactory" value-ref="sessionFactory" />
<entry key="someDataDao" value-ref="someDataDao" />
</map>
</property>
</bean>
There's bug spring https://jira.spring.io/browse/SPR-9020 And there's workaround. Configure session with hibernate.current_session_context_class property with this class: https://gist.github.com/seykron/4770724
精彩评论