解决延迟初始化异常的优化方法

Posted

技术标签:

【中文标题】解决延迟初始化异常的优化方法【英文标题】:Optimized way to solve lazy initialization exception 【发布时间】:2013-09-07 02:06:32 【问题描述】:

我正在做一个结合struts+spring+hibernate的项目。 Hibernate 是我最喜欢的一个框架,但我遇到了延迟初始化异常的问题。 我必须解决这个问题,但我不想放弃的是

我不能从我的项目中释放 DTO,它有助于在层之间进行通信。 我不想将持久性对象访问到服务层。 我不想丢失将 Persistence 对象转换为数据传输对象的实用程序类。

这是我已经完成的编码实现。 我在服务层调用这个方法

sectionsservice.getAllSections();

DAO 实现是这样的

public List<SectionsTO> getAllSections() 
    List<SectionsTO> sectionsto_list=new ArrayList<SectionsTO>();
    List<Sections> sections_list=htemp.loadAll(Sections.class);

    try 
        SessionFactory factory=HibernateUtil.getSessionFactory();
        Session session=factory.openSession();
        Transaction tx=session.beginTransaction();
            Query qry=session.createQuery("from Sections sections");
            List list=qry.list();
            Iterator it=list.iterator();
            while(it.hasNext()) 
                Sections sections=(Sections)it.next();
                SectionsTO sectionsto=**PropertyUtil**.getSectionsTOFromSections(sections);
                sectionsto_list.add(sectionsto);
            
        tx.commit();
        session.close();
        factory.close();
    
    catch(Exception e) 
        e.printStackTrace();
    
    return sectionsto_list;

这里是 PropertyUtil 类的实现

public static SectionsTO getSectionsTOFromSections(Sections sections) 
    SectionsTO sectionsto=new SectionsTO();
    sectionsto.setSection_id(sections.getSection_id());
    sectionsto.setSection_name(sections.getSection_name());
    sectionsto.setSection_desc(sections.getSection_desc());
    sectionsto.setThreads(sections.getThreads());
    sectionsto.setPosts(sections.getPosts());
    sectionsto.setLast_post(sections.getLast_post());
    sectionsto.setLast_post_by(PropertyUtil.getMembersTOFromMembers(sections.getLast_post_by()));
    sectionsto.setQuestion_id(sections.getQuestion_id());
    Set<Questions> questions_set=sections.getQuestions_set();
    Set<QuestionsTO> questions_set_to=new HashSet<QuestionsTO>();
    Iterator<Questions> it=questions_set.iterator();
    while(it.hasNext()) 
        QuestionsTO questionsto=PropertyUtil.getQuestionsTOFromQuestions(it.next());
        questions_set_to.add(questionsto);
    
    return sectionsto;

这是我得到的错误的堆栈跟踪

 SEVERE: Servlet.service() for servlet [action] in context with path [/TechForum] threw exception [org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.cac.hibernate.Sections.questions_set, no session or session was closed] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.cac.hibernate.Sections.questions_set, 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.toString(PersistentSet.java:309)
    at java.lang.String.valueOf(Unknown Source)
    at java.io.PrintStream.println(Unknown Source)
    at org.apache.tomcat.util.log.SystemLogHandler.println(SystemLogHandler.java:269)
    at com.cac.dao.HibernateSectionsDAO.getAllSections(HibernateSectionsDAO.java:93)
    at com.cac.service.SectionsServiceImpl.getAllSections(SectionsServiceImpl.java:48)
    at com.cac.struts.RegisterAction.fetch_sections(RegisterAction.java:107)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:269)
    at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:170)
    at org.springframework.web.struts.DelegatingActionProxy.execute(DelegatingActionProxy.java:113)
    at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:425)
    at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:228)
    at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
    at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:306)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:198)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:244)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:379)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:259)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:281)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

持久化类(Section)和传输对象(SectionsTO)是这样的 部分

 private int section_id;
    private String section_name;
    private String section_desc;
    private int threads;
    private int posts;
    private String last_post;
    private Members last_post_by;
    private Date last_post_date;
    private int question_id;
    private Set<Questions> questions_set;
    //setter
    //getter

SectionsTO

private int section_id;
    private String section_name;
    private String section_desc;
    private int threads;
    private int posts;
    private String last_post;
    private MembersTO last_post_by;
    private Date last_post_date;
    private int question_id;
    private Set<QuestionsTO> questionsto_set;
    //setter
    //getter

问题是,如果我对集合执行lazy="true",我将得到一个延迟初始化异常,而如果我执行lazy="false",由于propertyutil 类实现,它会急切地加载所有表。 从过去的 48 小时开始,我一直坚持这一点。 所以请给我一些优化的方法。

【问题讨论】:

不确定这是否是您想要的,但您可能会觉得 ***.com/questions/1600215/… 很有趣 @MarcinŁoś 不,我不想执行分页。这是关于我坚持延迟初始化异常的编码设计。 在哪一行得到延迟初始化异常?你可以发布堆栈跟踪吗?能否同时发布SectionsSectionsTO 的源代码? 你能识别 HibernateSectionsDAO 第 93 行吗? 这条线在做什么? List&lt;Sections&gt; sections_list=htemp.loadAll(Sections.class); 【参考方案1】:

如果您想使用lazy="true",您可以使用运行时关联获取策略来解决这个问题。 Hibernate 允许您在映射文件中指定默认获取策略,可以在运行时在代码中覆盖该策略。

在您的映射中定义lazy="true",这将导致关联对象或集合的延迟获取。现在,无论您希望在哪里急切地获取关联的对象或集合,都可以覆盖此默认获取策略,如下所示:

在 HQL 中,可以使用 from 子句中的 fetch 关键字通过外连接急切地获取关联:

from Sections sections left join fetch sections.questions_set

使用 Criteria API 也可以完成同样的事情:

session.createCriteria(Sections.class)
.setFetchMode("questions_set", FetchMode.EAGER).list();

执行时,这两个查询都将返回一个 Section 实例列表,它们的 question_set 集合已完全初始化。

使用这些获取策略,关联不会一直被急切地加载,但您可以(重新)定义要在运行时使用的策略。

【讨论】:

OP 不使用 Criteria API。

以上是关于解决延迟初始化异常的优化方法的主要内容,如果未能解决你的问题,请参考以下文章

使用hibernate搜索找不到延迟初始化异常的解决方案

关于并发场景下,通过双重检查锁实现延迟初始化的优化问题隐患的记录

延迟初始化异常

Linux网卡延迟初始化错误解决方法

Effective Java 之-----关于延迟初始化

即使在 HQL 查询中使用 Join Fetch,休眠延迟初始化异常