我有一个父/子@OneToMany
,其中集合是Set
(没有重复)。如果我尝试从服务器上的Parent访问子进程,我会收到以下错误。
如果我通过request.setAttribute
将Parent传递给客户端并使用JSTL访问Parent,我可以直接访问Child对象成员。家长/孩子有getter / Setters。
我正在使用Tomcat 6.0.32,Spring 3.1.0,JDK6,Hibernate 3.
父
@Entity
@Table(name="SUSER")
public class SUser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int su_id;
@Column(name="displayname", nullable=true,
columnDefinition="varchar", length=50, insertable=true, updatable=true)
private String displayname;
@Column(name="last_activity", nullable=true, columnDefinition="datetime",
insertable=true, updatable=true)
private String last_activity;
@Column(name="ldapuser", nullable=true, columnDefinition="varchar",
length=50, insertable=true, updatable=true)
private String ldapuser;
@OneToMany
@org.hibernate.annotations.IndexColumn(name="SU_ID")
@JoinColumn(name="su_id", insertable=true, updatable=true)
private Set<SUserAttributes> suattr = new HashSet<SUserAttributes>();
儿童
@Entity
@Table(name="SUSER_ATTRIBUTES")
public class SUserAttributes {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int sua_id;
@Column(name="su_id")
private int su_id;
@Column(name="sua_key", nullable=true, columnDefinition="varchar",
length=64, insertable=true, updatable=true)
private String sua_key;
@Column(name="sua_value", nullable=true, columnDefinition="varchar",
length=128, insertable=true, updatable=true)
private String sua_value;
DAO
package com.oasis.implementation.dao;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.oasis.implementation.ClientInfo;
import com.oasis.implementation.SUser;
public class SUserDaoImpl implements SUserDao {
@SuppressWarnings("unused")
private static Logger logger = Logger
.getLogger(ClientDownloadsDaoImpl.class);
@Autowired
@Qualifier("implementationSessionFactory")
private SessionFactory sessionFactory;
@SuppressWarnings("unchecked")
@Override
public List<SUser> getAllSUsers(){
List<SUser> suList = null;
Session session = null;
try
{
session = sessionFactory.openSession();
session.beginTransaction();
suList = session.createQuery("from SUser").list();
session.getTransaction().commit();
}
catch (RuntimeException e)
{
System.out.println (e.getMessage());
}
finally
{
if (session != null)
{
session.close();
}
}
return suList;
}
@Override
public List<SUser> getSUserById(int su_id) {
Session session = null;
SUser sUser = null;
LinkedList<SUser> suList = new LinkedList<SUser>();
try {
session = sessionFactory.openSession();
session.beginTransaction();
sUser = (SUser) session.get(SUser.class, su_id);
suList.add(sUser);
session.getTransaction().commit();
} catch (RuntimeException e) {
System.out.println(e.getMessage());
} finally {
if (session != null) {
session.close();
}
}
return suList;
}
@Override
public List<SUser> getUserByLdap(String ldapuser){
Session session = null;
int user_id = 0;
List<SUser> suList = null;
try
{
session = sessionFactory.openSession();
session.beginTransaction();
SQLQuery sqlq = session.createSQLQuery("select su_id from
suser where ldapuser = '" + ldapuser + "'");
user_id = (Integer)sqlq.uniqueResult();
suList = getSUserById(user_id);
session.getTransaction().commit();
}
catch (RuntimeException e)
{
System.out.println (e.getMessage());
}
finally
{
if (session != null)
{
session.close();
}
}
return suList;
}
}
错误消息
Hibernate: select suser0_.su_id as su1_11_0_, suser0_.displayname as
displayn2_11_0_, suser0_.last_activity as last3_11_0_, suser0_.ldapuser as l
dapuser11_0_ from SUSER suser0_ where suser0_.su_id=?
ERROR - failed to lazily initialize a collection of role: com.oasis.implementation.SUser.suattr, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.oasis.implementation.SUser.suattr, no session or
session was closed
at
答案 0 :(得分:3)
这个错误正在发生,因为一旦Hibernate会话关闭,你正试图访问一个延迟加载的集合(这意味着尚未真正从数据库中获取集合)。所以,没有办法回到数据库来获取孩子。你可以:
在Session
仍处于打开状态时强制加载关联,并调用Hibernate.initialize(parent.getSuattr());
使用显式join fetch
语句为该用例创建特定查询。
如果您在查询父级时总是要查询子项,请将映射修改为急切地获取关联。
采用OpenSessionInView模式。当要处理请求时(通常在Filter
中),此模式会打开Hibernate会话,并在完全处理之前保持打开状态。考虑到这种方法可能不适合您当前的设计(可能需要重新设计),并且应该谨慎使用,因为它有一些可能会让事情变得混乱的陷阱。
答案 1 :(得分:0)
您的代码最大的问题是,您打开了一个会话/事务并使用DAO finder方法关闭/提交它。
交易(因此,Hibernate会话)应该保持开放,以适应工作单元的范围。例如,事务应该在Application Service方法调用之前和之后打开/提交,以便在该app服务方法中完成的每个工作都将在一个事务中。 (OpenSessionInView分享类似的理由,它只是“工作单位”在这种情况下甚至更长)