Hi all;
This seems to be a common issue, but all my searching and reading has not found the particular solution that works for us.
We're trying to use Hibernate as our persistance layer for a large enterprisey system. We have annotated POJOs generated from a database using the maven appfuse plugin. We are also trying to follow Appfuse's design, namely:
- Annotated POJOs
- DAO layer (Hibernate)
- Manager layer (abstracts actual DAO implementation from users)
We are trying to use Spring to wire everything together, but running into the dreaded LazyInitializationException: no session or session was closed.
We thought we could just use Spring's declarative transactions to handle everything for us, but we cannot seem to get things working correctly, either inside of a web container or running standalone. I've read quite a bit about the OpenSessionInViewFilter, and we may pursue that for use on our webapp (running on Weblogic Server), but we need our Hibernate configuration to run stand-alone as well.
Stepping through debugger (or log files), it seems that the sequence of events is something like:
- Spring creates a transaction
- Spring creates a Hibernate Session
- JDBC connection established
- SQL run, collections are lazy loaded/proxied
- HibernateTemple does NOT close the session
- Spring thinks the transaction is complete
- Spring closes the Hibernate Session
- Spring closes the transaction
- User tries to access a lazy loaded collection and gets an exception
We're using Hibernate3, Spring 2.0, connecting to an Oracle database. Eventually we want to be able to run this on a Weblogic Server 9.2.
Thanks in advance for any advice!
Sample code:
Code:
// ApplicationContextFactory statically loads our ClassPathXmlApplicationContext and gives it back to you
MyManagerImpl myManager = (MyManagerImpl) ApplicationContextFactory
.getBean("myManager");
MyObject obj = myManager.get( 123L );
// Now Spring has closed the Hibernate Session
// Single property access is just fine
obj.getName();
// collection access throws LazyInitializationErro
obj.getOtherObject().getSomeProperty();
applicationContext.xml:
Code:
<!-- SessionFactory for hibernate -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.default_schema=${hibernate.default_schema}
</value>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- wrap anything from manager package in a Spring transaction -->
<aop:config>
<aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* *..manager.*Manager.*(..))" order="2"/>
</aop:config>
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- Enable @Transactional support -->
<tx:annotation-driven/>
<!-- Enable @AspectJ support -->
<aop:aspectj-autoproxy/>
<!-- sample DAO -->
<bean id="myDao" class="com.myapp.db.dao.hibernate.MyHibernateDao">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<!-- sample Manager -->
<bean id="myManager" class="com.myapp.db.manager.impl.MyManagerImpl">
<constructor-arg ref="myDao" />
</bean>
MyObject:
Code:
@Entity
@Table(name="MY_OBJECTS")
public class MyObject extends BaseObject implements Serializable {
private Long idPk;
private String name;
private OtherObject otherObject;
private Set<SomeOtherObject> someOtherObjects = new HashSet<SomeOtherObjects>(0);
@Id
@Column(name="MY_OBJECT_ID_PK", unique=true, nullable=false, precision=18, scale=0)
public Long getIdPk() {return this.idPk;}
...
@ManyToOne(fetch=FetchType.LAZY)
public OtherObject getOtherObject() {return this.otherObject;}
...
@OneToMany(cascadeType=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="myObject")
public Set<SomeOtherObject> getSomeOtherObjects() {return this.someOtherObjects;}
...
}
MyHibernateDao:
Code:
public class MyHibernateDao
extends GenericDaoHibernate<MyObject, Long>
implements MyDao
{
public MyHibernateDao() {
super(MyObject.class);
}
}
MyManagerImpl:
Code:
public class MyManagerImpl
extends GenericManagerImpl<MyObject, Long>
implements MyManager
{
private MyDao m_MyDao;
public MyManagerImpl(MyDao a_MyDao) {
super(a_MyDao);
m_MyDao = a_MyDao;
}
}
GenericDaoHibernate:
Code:
public class GenericDaoHibernate<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {
protected final Log log = LogFactory.getLog(getClass());
private Class<T> persistentClass;
public GenericDaoHibernate() {}
public GenericDaoHibernate(Class<T> persistentClass) {
this.persistentClass = persistentClass;
}
public boolean exists(PK id) {
T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);
if (entity == null) {
return false;
} else {
return true;
}
}
public T get(PK id) {
T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);
if (entity == null) {
// log.warn("Uh oh, '" + this.persistentClass + "' object with id '"
// + id + "' not found...");
throw new ObjectRetrievalFailureException(this.persistentClass, id);
}
return entity;
}
public List<T> getAll() {
return super.getHibernateTemplate().loadAll(this.persistentClass);
}
public void remove(PK id) {
super.getHibernateTemplate().delete(this.get(id));
}
public void save(T object) {
super.getHibernateTemplate().saveOrUpdate(object);
}
}
GenericManagerImpl:
Code:
public class GenericManagerImpl<T, PK extends Serializable> implements GenericManager<T, PK> {
protected final Log log = LogFactory.getLog(getClass());
protected GenericDao<T, PK> genericDao;
public GenericManagerImpl() {}
public GenericManagerImpl(GenericDao<T, PK> genericDao) {
this.genericDao = genericDao;
}
public List<T> getAll() {
return genericDao.getAll();
}
public T get(PK id) {
return genericDao.get(id);
}
public boolean exists(PK id) {
return genericDao.exists(id);
}
public void save(T object) {
genericDao.save(object);
}
public void remove(PK id) {
genericDao.remove(id);
}
}