Announcement Announcement Module
Collapse
No announcement yet.
Help with HibernateDaoSupport and LazyInitException Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help with HibernateDaoSupport and LazyInitException

    Hi all,

    I'm trying to use a Dao package that I developed using HibernateDaoSupport, in a non web-app. The Dao works fine in a Spring-MVC web app (using OSIV Interceptor), but I can't for the life of me, figure out how to use it in a regular app without getting tons of LazyInitializationExceptions all over the place.

    The application is basically just a bunch of (Spring-configured) Quartz jobs. So let's say I have a job that has to print out all of a given user's Roles to a log file. (simple enough).

    Here's the Job's executeInternal code:
    Code:
    		User u = AppContext.getUserDao().get("phil");
    		Set<Role> roles = u.getRoles();
    		for(Role r : roles){
    			System.out.println(r.getRoleName());
    		}
    Here, the call to u.getRoles() doesn't throw an exception, but returns a proxied (uninitialized) collection. When I try to iterate over the collection, I get LazyInitializationException, session was closed.

    Since I never explicitly opened a session, I assume Spring is managing that somehow, automagically. In the log file, I see that SessionFactoryUtils is closing the session. How do I prevent this from happening?

    Here is my applicationContext.xml, with the UserDao and hibernate config:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    
        <description>Configuration file for Dao (Hibernate config).</description>
    
        <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
            <property name="jndiName" value="java:comp/env/subDB"/>
        </bean>
    
        <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
            <property name="mappingResources" ref="mappingResources"/>
            <property name="hibernateProperties" ref="hibernateProperties"/>
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <!--  Hibernate Properties -->
        <bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
            <property name="properties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="hibernate.max_fetch_depth">4</prop>
    
                    <prop key="hibernate.hibernate.cache.use_query_cache">true</prop>
                    <prop key="hibernate.jdbc.batch_size">50</prop>
                    <prop key="hibernate.connection_release_mode">auto</prop>
    
                    <!-- Use EHCache as secondary cache-->
                    <prop key="hibernate.cache.use_query_cache">true</prop>
                    <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                    <prop key="hibernate.cache.provider_configuration_file_resource_path">com/testproject/dao/hibernate/ehcache.xml</prop>
                </props>
            </property>
        </bean>
    
        <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
            <constructor-arg>
                <ref bean="sessionFactory"/>
            </constructor-arg>
        </bean>
    
        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
            <property name="sessionFactory" ref="sessionFactory"/>
        </bean>
    
        <!--  hibernate mapping files (in dao JAR) -->
        <bean id="mappingResources" class="org.springframework.beans.factory.config.ListFactoryBean">
            <property name="sourceList">
                <list>
                    <value>com/testproject/entities/Role.hbm.xml</value>
                    <value>com/testproject/entities/User.hbm.xml</value>
                </list>
            </property>
        </bean>
    
        <bean id="userDao" class="com.testproject.dao.hibernate.HibernateUserDao">
            <property name="hibernateTemplate">
                <ref bean="hibernateTemplate"/>
            </property>
        </bean>
        <bean id="roleDao" class="com.testproject.dao.hibernate.HibernateRoleDao">
            <property name="hibernateTemplate">
                <ref bean="hibernateTemplate"/>
            </property>
        </bean>
    </beans>
    And here's the code for the Basic HibernateDao, which extends org.springframework.orm.hibernate3.support.Hiberna teDaoSupport:

    Code:
    public abstract class HibernateDao<T extends Persistable, ID extends Serializable> extends HibernateDaoSupport implements Dao<T, ID> {
    
    	private Class<T> persistentClass;
    
    	@SuppressWarnings("unchecked")
    	protected List<T> findByNamedParam(String hql, String[] paramNames, Object[] paramValues) {
    		return getHibernateTemplate().findByNamedParam(hql, paramNames, paramValues);
    	}
    
    	public Class<T> getPersistentClass() {
    		return persistentClass;
    	}
    
    	protected void setPersistentClass(Class<T> persistentClass) {
    		this.persistentClass = persistentClass;
    	}
    
    	public List<T> findAll() {
    		return findByCriteria();
    	}
    
    	@SuppressWarnings("unchecked")
    	public List<T> findByExample(T exampleInstance, String[] excludeProperty) {
    		Criteria crit = getSession().createCriteria(getPersistentClass());
    		Example example = Example.create(exampleInstance);
    		for (String exclude : excludeProperty) {
    			example.excludeProperty(exclude);
    		}
    		crit.add(example);
    		return crit.list();
    	}
    
    	@SuppressWarnings("unchecked")
    	protected Query getQueryWithParameters(String hql, String[] paramNames, Object[] paramValues) {
    		Query q = getSession().createQuery(hql);
    		for (int i = 0; i < paramNames.length; i++) {
    			if (paramValues[i] instanceof Collection) {
    				q.setParameterList(paramNames[i], (Collection) paramValues[i]);
    			} else {
    				q.setParameter(paramNames[i], paramValues[i]);
    			}
    		}
    		return q;
    	}
    
    	@SuppressWarnings("unchecked")
    	protected List<T> findByCriteria(Criterion... criterion) {
    		Criteria crit = getSession().createCriteria(getPersistentClass());
    		for (Criterion c : criterion) {
    			crit.add(c);
    		}
    		return crit.list();
    	}
    
    	@SuppressWarnings("unchecked")
    	public HibernateDao() {
    		// back up the inheritance tree until we hit a superclass that is an
    		// instance of ParameterizedType.
    		Class clazz = getClass();
    		while (!(clazz.getGenericSuperclass() instanceof ParameterizedType)) {
    			clazz = clazz.getSuperclass();
    		}
    
    		// Get the Persistable class represented by the Type parameter 'T'
    		// (Array index 0). Gotta love generics.
    		this.persistentClass = (Class<T>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
    		DaoRegistry.register(this);
    	}
    
    	public void delete(ID id) {
    		// getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_AUTO);
    		T o = get(id);
    		if (o != null)
    			getSession().delete(o);
    		// getHibernateTemplate().delete(o);
    		// getHibernateTemplate().flush();
    	}
    
    	public void delete(ID[] idList) {
    		// getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_AUTO);
    		getHibernateTemplate().deleteAll(get(idList));
    		// getHibernateTemplate().flush();
    	}
    
    	@SuppressWarnings("unchecked")
    	public List<T> get(ID[] idList) {
    		String hql = "from " + persistentClass.getName() + " where id in (:idList) order by id desc";
    		/*
    		 * does this ORDER BY clause even make sense? Test this.
    		 */
    		String[] pNames = new String[] { "idList" };
    		Object[] pValues = new Object[] { idList };
    
    		return getHibernateTemplate().findByNamedParam(hql, pNames, pValues);
    	}
    
    	@SuppressWarnings("unchecked")
    	public T get(ID id) {
    		return (T) getHibernateTemplate().get(getPersistentClass(), id);
    	}
    
    	@Override
    	public void delete(T o) {
    		// getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_AUTO);
    		getHibernateTemplate().delete(o);
    		// getHibernateTemplate().flush();
    	}
    
    	@Override
    	public void save(T o) {
    		// getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_AUTO);
    		getHibernateTemplate().saveOrUpdate(o);
    		// getHibernateTemplate().flush();
    	}
    
    }
    The UserDao class extends this base class, with no custom methods:

    Code:
    public class HibernateUserDao extends HibernateDao<User, String>  implements UserDao {}
    Things I've tried already:
    - OSIV: Won't work, since there is no "view". This is a Quartz job.
    - Opening the view "manually", by calling SessionFactoryUtils.getSession(sessionFactory, true): Doesn't work. HibernateDaoSupport just opens another session.
    - Setting "lazy=false" in my User.hbm.xml: This works, but I would have to do it for all associations, in all my hbm.xml files, which obviously won't work, since Hibernate will attempt to load the entire database into memory.

    Can anyone recommend some way I could replicate the behavior of the OSIV interceptor, but instead of opening the session at the beginning of a request, opening it at the beginning of a Quartz Job, and closing it once the job is finished? Can I do this somehow in a JobListener, in such a way that the underlying HibernateDaoSupport framework will use the existing, open session, and the not close it?

    thanks,

  • #2
    Here's the log file. Couldn't submit it in the previous post (post too long).

    Code:
    2009-05-19 13:38:00,001 [INFO ] concurrentVetoTriggerListener - Trigger fired. Executing Job 'Test.Hibernate.
    2009-05-19 13:38:00,001 [DEBUG] core.JobRunShell  - Calling execute on job DEFAULT.Test.Hibernate
    2009-05-19 13:38:00,001 [INFO ] Test.Hibernate    - Starting Job 'Test.Hibernate'
    2009-05-19 13:38:00,002 [DEBUG] support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userDao'
    2009-05-19 13:38:00,002 [DEBUG] hibernate3.SessionFactoryUtils - Opening Hibernate Session
    2009-05-19 13:38:00,002 [DEBUG] impl.SessionImpl  - opened session at timestamp: 5090323169288192
    2009-05-19 13:38:00,002 [DEBUG] loader.Loader     - loading entity: [com.airbornemobile.aggregation.entities.User#phil]
    2009-05-19 13:38:00,002 [DEBUG] jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
    2009-05-19 13:38:00,002 [DEBUG] jdbc.ConnectionManager - opening JDBC connection
    2009-05-19 13:38:00,002 [DEBUG] hibernate.SQL     - select user0_.login as login14_0_, user0_.accountId as accountId14_0_, user0_.fullName as fullName14_0_, user0_.password as password14_0_, user0_.enabled as enabled14_0_, user0_.email as email14_0_, user0_.newPassword as newPassw7_14_0_, user0_.pwToken as pwToken14_0_ from submissions.User user0_ where user0_.login=?
    Hibernate: select user0_.login as login14_0_, user0_.accountId as accountId14_0_, user0_.fullName as fullName14_0_, user0_.password as password14_0_, user0_.enabled as enabled14_0_, user0_.email as email14_0_, user0_.newPassword as newPassw7_14_0_, user0_.pwToken as pwToken14_0_ from submissions.User user0_ where user0_.login=?
    2009-05-19 13:38:00,002 [DEBUG] jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
    2009-05-19 13:38:00,003 [DEBUG] loader.Loader     - result row: EntityKey[com.airbornemobile.aggregation.entities.User#phil]
    2009-05-19 13:38:00,003 [DEBUG] jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
    2009-05-19 13:38:00,003 [DEBUG] jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
    2009-05-19 13:38:00,003 [DEBUG] engine.TwoPhaseLoad - resolving associations for [com.airbornemobile.aggregation.entities.User#phil]
    2009-05-19 13:38:00,004 [DEBUG] engine.TwoPhaseLoad - done materializing entity [com.airbornemobile.aggregation.entities.User#phil]
    2009-05-19 13:38:00,004 [DEBUG] engine.StatefulPersistenceContext - initializing non-lazy collections
    2009-05-19 13:38:00,004 [DEBUG] loader.Loader     - done entity load
    2009-05-19 13:38:00,004 [DEBUG] jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
    2009-05-19 13:38:00,004 [DEBUG] hibernate3.HibernateTemplate - Eagerly flushing Hibernate session
    2009-05-19 13:38:00,004 [DEBUG] def.AbstractFlushingEventListener - processing flush-time cascades
    2009-05-19 13:38:00,004 [DEBUG] def.AbstractFlushingEventListener - dirty checking collections
    2009-05-19 13:38:00,004 [DEBUG] engine.Collections - Collection found: [com.airbornemobile.aggregation.entities.User.submissions#phil], was: [com.airbornemobile.aggregation.entities.User.submissions#phil] (uninitialized)
    2009-05-19 13:38:00,004 [DEBUG] engine.Collections - Collection found: [com.airbornemobile.aggregation.entities.User.managedAccounts#phil], was: [com.airbornemobile.aggregation.entities.User.managedAccounts#phil] (uninitialized)
    2009-05-19 13:38:00,004 [DEBUG] engine.Collections - Collection found: [com.airbornemobile.aggregation.entities.User.roles#phil], was: [com.airbornemobile.aggregation.entities.User.roles#phil] (uninitialized)
    2009-05-19 13:38:00,004 [DEBUG] def.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
    2009-05-19 13:38:00,004 [DEBUG] def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 3 collections
    2009-05-19 13:38:00,004 [DEBUG] pretty.Printer    - listing entities:
    2009-05-19 13:38:00,004 [DEBUG] pretty.Printer    - com.airbornemobile.aggregation.entities.User{enabled=true, email=[email protected], newPassword=null, roles=<uninitialized>, pwToken=null, account=com.airbornemobile.aggregation.entities.Account#1, submissions=<uninitialized>, login=phil, managedAccounts=<uninitialized>, fullName=Test User (mod: 1242753180006), password=9044124}
    2009-05-19 13:38:00,004 [DEBUG] hibernate3.SessionFactoryUtils - Closing Hibernate Session
    2009-05-19 13:38:00,004 [DEBUG] jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
    2009-05-19 13:38:00,004 [DEBUG] jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
    2009-05-19 13:38:00,004 [ERROR] hibernate.LazyInitializationException - failed to lazily initialize a collection of role: com.airbornemobile.aggregation.entities.User.roles, no session or session was closed
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.airbornemobile.aggregation.entities.User.roles, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    	at com.airbornemobile.aggregation.jobs.HibernateTestJob.jobAction(HibernateTestJob.java:44)
    	at com.airbornemobile.scheduling.ChainableJobBean.executeInternal(ChainableJobBean.java:81)
    	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
    	at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
    	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
    2009-05-19 13:38:00,028 [ERROR] core.JobRunShell  - Job DEFAULT.Test.Hibernate threw an unhandled Exception: 
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.airbornemobile.aggregation.entities.User.roles, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    	at com.airbornemobile.aggregation.jobs.HibernateTestJob.jobAction(HibernateTestJob.java:44)
    	at com.airbornemobile.scheduling.ChainableJobBean.executeInternal(ChainableJobBean.java:81)
    	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
    	at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
    	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
    2009-05-19 13:38:00,053 [ERROR] core.ErrorLogger  - Job (DEFAULT.Test.Hibernate threw an exception.
    org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.airbornemobile.aggregation.entities.User.roles, no session or session was closed]
    	at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
    	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
    Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.airbornemobile.aggregation.entities.User.roles, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:343)
    	at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:86)
    	at org.hibernate.collection.PersistentSet.iterator(PersistentSet.java:163)
    	at com.airbornemobile.aggregation.jobs.HibernateTestJob.jobAction(HibernateTestJob.java:44)
    	at com.airbornemobile.scheduling.ChainableJobBean.executeInternal(ChainableJobBean.java:81)
    	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
    	at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
    	... 1 more
    2009-05-19 13:38:00,078 [INFO ] concurrentVetoTriggerListener - Job 'Test.Hibernate' will fire again at Tue May 19 13:38:05 EDT 2009

    Comment


    • #3
      Maybe this can help: http://www.javalobby.org/java/forums/t62077.html
      btw, HibernateDaoSupport is soon to be deprecated as far as I know.

      Comment


      • #4
        Thanks ctapobep. I keep seeing everywhere that HibernateDaoSupport is not recommended, but I've yet to see a compelling reason why that might be.

        Anyways, I've gone ahead and removed the HibernateDaoSupport, and added a SessionFactory property, which I initialized via Spring. Here's the updated HibernateDao base class, with a couple of choice snippets copied directly from HibernateDaoSupport:
        Code:
        public abstract class HibernateDao<T extends Persistable, ID extends Serializable> extends AbstractLogger implements Dao<T, ID> {
        
        	private Class<T> persistentClass;
        	private SessionFactory sessionFactory;
        
        	@SuppressWarnings("unchecked")
        	protected List<T> findByNamedParam(String hql, String[] paramNames, Object[] paramValues) {
        		Query query = getSession().createQuery(hql);
        		if (paramValues != null) {
        			for (int i = 0; i < paramValues.length; i++) {
        				applyNamedParameterToQuery(query, paramNames[i], paramValues[i]);
        			}
        		}
        		return query.list();
        	}
        
        	protected Session getSession() {
        		return sessionFactory.getCurrentSession();
        	}
        
        	@SuppressWarnings("unchecked")
        	protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value) throws HibernateException {
        
        		if (value instanceof Collection) {
        			queryObject.setParameterList(paramName, (Collection) value);
        		} else if (value instanceof Object[]) {
        			queryObject.setParameterList(paramName, (Object[]) value);
        		} else {
        			queryObject.setParameter(paramName, value);
        		}
        	}
        
        	public Class<T> getPersistentClass() {
        		return persistentClass;
        	}
        
        	protected void setPersistentClass(Class<T> persistentClass) {
        		this.persistentClass = persistentClass;
        	}
        
        	public List<T> findAll() {
        		return findByCriteria();
        	}
        
        	@SuppressWarnings("unchecked")
        	public List<T> findByExample(T exampleInstance, String[] excludeProperty) {
        		Criteria crit = getSession().createCriteria(getPersistentClass());
        		Example example = Example.create(exampleInstance);
        		for (String exclude : excludeProperty) {
        			example.excludeProperty(exclude);
        		}
        		crit.add(example);
        		return crit.list();
        	}
        
        	@SuppressWarnings("unchecked")
        	protected Query getQueryWithParameters(String hql, String[] paramNames, Object[] paramValues) {
        		Query q = getSession().createQuery(hql);
        		for (int i = 0; i < paramNames.length; i++) {
        			if (paramValues[i] instanceof Collection) {
        				q.setParameterList(paramNames[i], (Collection) paramValues[i]);
        			} else {
        				q.setParameter(paramNames[i], paramValues[i]);
        			}
        		}
        		return q;
        	}
        
        	@SuppressWarnings("unchecked")
        	protected List<T> findByCriteria(Criterion... criterion) {
        		Criteria crit = getSession().createCriteria(getPersistentClass());
        		for (Criterion c : criterion) {
        			crit.add(c);
        		}
        		return crit.list();
        	}
        
        	@SuppressWarnings("unchecked")
        	public HibernateDao() {
        		// back up the inheritance tree until we hit a superclass that is an
        		// instance of ParameterizedType.
        		Class clazz = getClass();
        		while (!(clazz.getGenericSuperclass() instanceof ParameterizedType)) {
        			clazz = clazz.getSuperclass();
        		}
        
        		// Get the Persistable class represented by the Type parameter 'T'
        		// (Array index 0). Gotta love generics.
        		this.persistentClass = (Class<T>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
        		DaoRegistry.register(this);
        	}
        
        	public void delete(ID id) {
        		// getHibernateTemplate().setFlushMode(HibernateTemplate.FLUSH_AUTO);
        		T o = get(id);
        		if (o != null)
        			getSession().delete(o);
        		// getHibernateTemplate().delete(o);
        		// getHibernateTemplate().flush();
        	}
        
        	public void delete(ID[] idList) {
        		List<T> list = get(idList);
        		for (T o : list) {
        			getSession().delete(o);
        		}
        	}
        
        	public List<T> get(ID[] idList) {
        		String hql = "from " + persistentClass.getName() + " where id in (:idList) order by id desc";
        		/*
        		 * does this ORDER BY clause even make sense? Test this.
        		 */
        		String[] pNames = new String[] { "idList" };
        		Object[] pValues = new Object[] { idList };
        
        		return findByNamedParam(hql, pNames, pValues);
        	}
        
        	@SuppressWarnings("unchecked")
        	public T get(ID id) {
        		return (T) getSession().get(getPersistentClass(), id);
        	}
        
        	@Override
        	public void delete(T o) {
        		getSession().delete(o);
        	}
        
        	@Override
        	public void save(T o) {
        		getSession().saveOrUpdate(o);
        	}
        
        	public SessionFactory getSessionFactory() {
        		return sessionFactory;
        	}
        
        	public void setSessionFactory(SessionFactory sessionFactory) {
        		this.sessionFactory = sessionFactory;
        	}
        
        }
        Unfortunately, this gives a different Exception:
        Code:
        2009-05-19 14:30:45,024 [INFO ] concurrentVetoTriggerListener - Trigger fired. Executing Job 'Test.Hibernate.
        2009-05-19 14:30:45,027 [DEBUG] core.JobRunShell  - Calling execute on job DEFAULT.Test.Hibernate
        2009-05-19 14:30:45,036 [INFO ] Test.Hibernate    - Starting Job 'Test.Hibernate'
        2009-05-19 14:30:45,037 [DEBUG] support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'userDao'
        2009-05-19 14:30:45,041 [DEBUG] hibernate3.SessionFactoryUtils - Opening Hibernate Session
        2009-05-19 14:30:45,069 [DEBUG] impl.SessionImpl  - opened session at timestamp: 5090336133292032
        2009-05-19 14:30:45,069 [DEBUG] hibernate3.SessionFactoryUtils - Closing Hibernate Session
        2009-05-19 14:30:45,070 [ERROR] core.JobRunShell  - Job DEFAULT.Test.Hibernate threw an unhandled 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:542)
        	at com.airbornemobile.aggregation.dao.hibernate.HibernateDao.getSession(HibernateDao.java:45)
        	at com.airbornemobile.aggregation.dao.hibernate.HibernateDao.get(HibernateDao.java:149)
        	at com.airbornemobile.aggregation.jobs.HibernateTestJob.jobAction(HibernateTestJob.java:42)
        	at com.airbornemobile.scheduling.ChainableJobBean.executeInternal(ChainableJobBean.java:81)
        	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
        	at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
        2009-05-19 14:30:45,216 [DEBUG] utils.ExceptionHelper - Detected JDK support for nested exceptions.
        2009-05-19 14:30:45,216 [ERROR] core.ErrorLogger  - Job (DEFAULT.Test.Hibernate threw an exception.
        org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here]
        	at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
        	at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:525)
        Caused by: 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:542)
        	at com.airbornemobile.aggregation.dao.hibernate.HibernateDao.getSession(HibernateDao.java:45)
        	at com.airbornemobile.aggregation.dao.hibernate.HibernateDao.get(HibernateDao.java:149)
        	at com.airbornemobile.aggregation.jobs.HibernateTestJob.jobAction(HibernateTestJob.java:42)
        	at com.airbornemobile.scheduling.ChainableJobBean.executeInternal(ChainableJobBean.java:81)
        	at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86)
        	at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        	... 1 more
        2009-05-19 14:30:45,246 [INFO ] concurrentVetoTriggerListener - Job 'Test.Hibernate' will fire again at Tue May 19 14:30:50 EDT 2009
        So The phrase "non-transactional" caught my eye. How can I set an AOP TransactionInterceptor on a Quartz Job, when the job is only instantiated at run-time by the Scheduler? The job itself is not directly referenced from the ContextLoader...

        Comment


        • #5
          Use HibernateTemplate and you will forget about transactions

          Comment


          • #6
            I've found a less-than-perfect, but working solution, so I thought I'd post it here, in the hopes that some future developer won't have to suffer for a week the way I have...

            The problem, at it's root, was that I was using a DAO layer, and an application layer, but no Services / Business layer.

            The "application layer" was a Quartz job, instantiated by the scheduler at runtime, and therefore not available to the Spring ContextConfigLoader at config-time. Makes sense.

            Unfortunately, this meant that the actual Quartz job could not be made the target of any Hibernate or Transaction Interceptor.

            The hackneyed and annoying solution: Wrap all calls to the DAO in a "Services" layer. Instantiate the service class at config-time, and pass a reference to it in the Quartz JobDetailBean's JobDataAsMap property. I believe there are several different terms for this (Business objects? Facade? Services layer?).

            I got the idea from here.

            This was not a Hibernate Problem, nor a Spring problem, but had more to do with how Quartz instantiates jobs at run-time, rather than holding a reference at startup.

            Thanks to everyone for their help!

            Comment

            Working...
            X