我正在研究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;
}
}
组注释:
@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)
我做错了,请告诉我。如果需要更多信息,请发表评论。
最佳答案
Hibernate会话完成后,将执行JSON转换器。 JSON转换器盲目地访问所有的getter和setter,甚至是惰性的。因此,当Hibernate尝试初始化GroupCanvas#ownedSection时,没有可用的会话,因此会引发此异常。
可能的解决方案:
不要在Hibernate受管对象上直接执行JSON转换器。创建DTO对象以完成此工作。 DTO对象没有逻辑,并且是纯Java Bean,非常适合此角色。但是缺点是您必须维护另一个类层次结构。好处大于缺点。以下帖子可以帮助您实现此方法:
DTO pattern : Best way to copy properties between two Objects
使用注释将某些字段标记为不可序列化。例如,JsonIgnore。这样做的缺点是,如果在其他API中始终需要此字段,则不能使用它。
如果可以从模型中消除后向引用之一(notes-> section / section-> canvas),则可以“更友好”地进行序列化。在其他作品中,JSON不能与循环引用一起很好地工作,因此双向/循环构造的数量越少越好。如果不是为了进行循环引用,则可以初始化序列化所需的所有数据,包括GroupCanvas。