Spring MVC,Hibernate:Lazy初始化异常

时间:2015-06-16 15:08:05

标签: java spring hibernate spring-mvc lazy-loading

我正在开发一个Spring-MVC应用程序,其中我有3个类,GroupCanvas,GroupSection,GroupNotes。 GroupCanvas与GroupSection具有一对多映射,GroupSection与GroupNotes具有一对多映射。我试图根据GroupCanvas的主键检索笔记,但我得到了一个Hibernate Lazy Initialization Exception。我尝试了关于网络的建议,主要是SO,但它们似乎都没有帮助。这是代码。

DAO方法抛出错误:

 @Override
    public List<GroupNotes> searchNotesByDays(int days, int mcanvasid) {
        Session session = this.sessionFactory.getCurrentSession();
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DAY_OF_YEAR, -days);
        long daysAgo = cal.getTimeInMillis();
        Timestamp nowMinusDaysAsTimestamp = new Timestamp(daysAgo);
        Query query = session.createQuery("from GroupSection as n where n.currentcanvas.mcanvasid=:mcanvasid");
        query.setParameter("mcanvasid", mcanvasid);
        List<GroupSection> sectionList = query.list();
        List<GroupNotes> notesList = new ArrayList<GroupNotes>();
        for (GroupSection e : sectionList) {
            Query query1 = session.createQuery("from GroupNotes as n where n.ownednotes.msectionid=:msectionid and n.noteCreationTime >:limit");
            query1.setParameter("limit", nowMinusDaysAsTimestamp);
            query1.setParameter("msectionid",e.getMsectionid());
            notesList.addAll(query1.list());
        }
        return notesList;
    }

GroupCanvas模型:

@Entity
@Table(name = "membercanvas")
public class GroupCanvas{

variables, getters, setters ignored
    @OneToMany(mappedBy = "currentcanvas",fetch=FetchType.LAZY, cascade = CascadeType.REMOVE)
    @JsonIgnore
    private Set<GroupSection> ownedsection = new HashSet<>();

    public Set<GroupSection> getOwnedsection() {
        return this.ownedsection;
    }

    public void setOwnedsection(Set<GroupSection> ownedsection) {
        this.ownedsection = ownedsection;
    }
}

GroupSection模型类:

@Entity
@Table(name = "membersection")
public class GroupSection {
 @ManyToOne
    @JoinColumn(name = "groupcanvasid",nullable = false)
    @JsonIgnore
    private GroupCanvas currentcanvas;

    public GroupCanvas getCurrentcanvas() {
        return this.currentcanvas;
    }

    public void setCurrentcanvas(GroupCanvas currentcanvas) {
        this.currentcanvas = currentcanvas;
    }

    public int getCurrentCanvasId(){
        return this.currentcanvas.getMcanvasid();
    }


    @OneToMany(mappedBy = "ownednotes", fetch = FetchType.EAGER,cascade = CascadeType.REMOVE)
    @JsonIgnore
    private Set<GroupNotes> sectionsnotes = new HashSet<>();

    public Set<GroupNotes> getSectionsnotes(){
        return this.sectionsnotes;
    }

    public void setSectionsnotes(Set<GroupNotes> sectionsnotes){
        this.sectionsnotes=sectionsnotes;
    }
}

GroupNotes:

@Entity
@Table(name="groupnotes")
public class GroupNotes{
   @ManyToOne
    @JoinColumn(name = "msectionid")
    @JsonIgnore
    private GroupSection ownednotes;

    public GroupSection getOwnednotes(){return this.ownednotes;}

    public void setOwnednotes(GroupSection ownednotes){this.ownednotes=ownednotes;}
}

错误日志:

org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: com.journaldev.spring.model.GroupCanvas.ownedsection, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownednotes"]->com.journaldev.spring.model.GroupSection["currentcanvas"]->com.journaldev.spring.model.GroupCanvas["ownedsection"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.journaldev.spring.model.GroupCanvas.ownedsection, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.journaldev.spring.model.GroupNotes["ownednotes"]->com.journaldev.spring.model.GroupSection["currentcanvas"]->com.journaldev.spring.model.GroupCanvas["ownedsection"])
    org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.writeInternal(MappingJackson2HttpMessageConverter.java:256)

我做错了什么,请让我知道。如果需要更多信息,请发表评论。

1 个答案:

答案 0 :(得分:1)

您的JSON转换器在Hibernate会话完成后执行。 JSON转换器盲目地访问所有getter和setter,甚至是懒惰的。因此,当Hibernate尝试初始化GroupCanvas#ownedSection时,没有可用的会话,因此抛出此异常。

可能的解决方案:

  1. 不要在Hibernate托管对象上直接执行JSON转换器。创建DTO对象以执行此任务。 DTO对象没有逻辑,是纯java bean,很适合这个角色。但缺点是你必须维护另一个类层次结构。好处确实超过了缺点。以下帖子可以帮助您实现这一方法:

    DTO pattern : Best way to copy properties between two Objects

  2. 使用注释将某些字段标记为不可序列化。例如,JsonIgnore。这样做的缺点是,如果在不同的API中需要此字段,则无法使用此字段。

  3. 如果可以从您的模型中删除其中一个back-ref(notes-&gt; section / section-&gt; canvas),那么这使得它对序列化“更友好”。在其他工作中,JSON不适用于循环引用,因此双向/循环结构的数量越少越好。如果不是循环引用的可能性,那么您可以初始化序列化所需的所有数据,包括GroupCanvas。

相关问题