1

我有一个父/子@OneToMany,其中集合是Set(没有重复)。如果我尝试从服务器上的父级访问子级,我会收到以下错误。

如果我通过将 Parent 传递给客户端request.setAttribute并使用 JSTL 访问 Parent,我可以直接访问 Child 对象成员。父/子有 getter/Setter。

我正在使用 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;

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 
4

2 回答 2

3

发生此错误是因为您在 Hibernate 会话关闭后尝试访问延迟加载的集合(这意味着该集合尚未真正从数据库中获取)。所以,没有办法回到数据库来取孩子。您可以:

  • Session在仍然打开时强制加载关联,并调用Hibernate.initialize(parent.getSuattr());

  • join fetch使用显式语句为该用例创建特定查询。

  • 如果您在查询父项时总是要查询子项,请修改映射以急切地获取关联。

  • 采用OpenSessionInView模式。此模式在请求即将被处理时(通常在 a 中Filter)打开一个 Hibernate 会话,并保持打开状态直到它被完全处理。考虑到这种方法可能不适合您当前的设计(可能需要重新设计),并且应该谨慎使用,因为它有一些真正会搞砸的陷阱。

于 2013-07-11T08:55:42.050 回答
0

您的代码的最大问题是,您在 DAO finder 方法中打开了一个会话/事务并关闭/提交它。

事务(以及因此的休眠会话)应该在工作单元的范围内保持开放。例如,事务应该在应用服务方法调用之前和之后打开/提交,以便在该应用服务方法中完成的每项工作都在一个事务中。(OpenSessionInView 有类似的理由,只是在这种情况下“工作单元”更长)

于 2013-07-12T01:43:04.433 回答