Hibernate太懒了

时间:2013-07-11 08:44:35

标签: hibernate

我有一个父/子@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 

2 个答案:

答案 0 :(得分:3)

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

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

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

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

  • 采用OpenSessionInView模式。当要处理请求时(通常在Filter中),此模式会打开Hibernate会话,并在完全处理之前保持打开状态。考虑到这种方法可能不适合您当前的设计(可能需要重新设计),并且应该谨慎使用,因为它有一些可能会让事情变得混乱的陷阱。

答案 1 :(得分:0)

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

交易(因此,Hibernate会话)应该保持开放,以适应工作单元的范围。例如,事务应该在Application Service方法调用之前和之后打开/提交,以便在该app服务方法中完成的每个工作都将在一个事务中。 (OpenSessionInView分享类似的理由,它只是“工作单位”在这种情况下甚至更长)