org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:148)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
at cmazxiaoma.model.School_$$_jvstaa_0.toString(School_$$_jvstaa_0.java)
複製程式碼
解決了Could not initialize proxy - no session的異常,我們再去跑一下單元測試,出現了更大的錯誤"StackOverflowError"
java.lang.StackOverflowError
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:131)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108)
at org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:75)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108)
複製程式碼
我們可以通過日誌看到sql的輸出,發現了sql重複執行了好多次。以下我擷取了前10條sql記錄。
Hibernate: select student0_.id as id1_1_0_, student0_.created_dt as created_2_1_0_, student0_.is_del as is_del3_1_0_, student0_.school_id as school_i4_1_0_, student0_.student_name as student_5_1_0_, student0_.updated_dt as updated_6_1_0_ from tbl_student student0_ where student0_.id=?
Hibernate: select school0_.id as id1_0_0_, school0_.created_dt as created_2_0_0_, school0_.is_del as is_del3_0_0_, school0_.school_name as school_n4_0_0_, school0_.updated_dt as updated_5_0_0_ from tbl_school school0_ where school0_.id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select school0_.id as id1_0_0_, school0_.created_dt as created_2_0_0_, school0_.is_del as is_del3_0_0_, school0_.school_name as school_n4_0_0_, school0_.updated_dt as updated_5_0_0_ from tbl_school school0_ where school0_.id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
複製程式碼
Hibernate: select student0_.id as id1_1_0_, student0_.created_dt as created_2_1_0_, student0_.is_del as is_del3_1_0_, student0_.school_id as school_i4_1_0_, student0_.student_name as student_5_1_0_, student0_.updated_dt as updated_6_1_0_ from tbl_student student0_ where student0_.id=?
student=Student{id='1', studentName='捲毛'}
複製程式碼
當我們去訪問Student的School詳情資訊時,才會去查詢School資訊。
@Test
public void query() {
Student student = studentDao.findOne("1");
System.out.println("student=" + student);
School school = student.getSchool();
System.out.println("school=" + school);
}
複製程式碼
Hibernate: select student0_.id as id1_1_0_, student0_.created_dt as created_2_1_0_, student0_.is_del as is_del3_1_0_, student0_.school_id as school_i4_1_0_, student0_.student_name as student_5_1_0_, student0_.updated_dt as updated_6_1_0_ from tbl_student student0_ where student0_.id=?
student=Student{id='1', studentName='捲毛'}
Hibernate: select school0_.id as id1_0_0_, school0_.created_dt as created_2_0_0_, school0_.is_del as is_del3_0_0_, school0_.school_name as school_n4_0_0_, school0_.updated_dt as updated_5_0_0_ from tbl_school school0_ where school0_.id=?
school=School{id='1', schoolName='WE學校'}
複製程式碼
hashCode()方法造成的死迴圈
我們去查詢School的資訊
@Test
public void query() throws Exception {
School school = schoolDao.findOne("1");
System.out.println(school);
Set<Student> studentList = school.getStudentList();
System.out.println("studentList=" + studentList);
}
複製程式碼
特麼,又發現了死迴圈。我們可以發現執行了查詢學校資訊的sql,成功輸出了學習資訊後,才發生死迴圈。
Hibernate: select school0_.id as id1_0_0_, school0_.created_dt as created_2_0_0_, school0_.is_del as is_del3_0_0_, school0_.school_name as school_n4_0_0_, school0_.updated_dt as updated_5_0_0_ from tbl_school school0_ where school0_.id=?
School{id='1', schoolName='WE學校'}
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select school0_.id as id1_0_0_, school0_.created_dt as created_2_0_0_, school0_.is_del as is_del3_0_0_, school0_.school_name as school_n4_0_0_, school0_.updated_dt as updated_5_0_0_ from tbl_school school0_ where school0_.id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
Hibernate: select studentlis0_.school_id as school_i4_1_0_, studentlis0_.id as id1_1_0_, studentlis0_.id as id1_1_1_, studentlis0_.created_dt as created_2_1_1_, studentlis0_.is_del as is_del3_1_1_, studentlis0_.school_id as school_i4_1_1_, studentlis0_.student_name as student_5_1_1_, studentlis0_.updated_dt as updated_6_1_1_ from tbl_student studentlis0_ where studentlis0_.school_id=?
複製程式碼
通過進一步,看到棧異常的錯誤定位在School類和Student類中的hashCode()。
java.lang.StackOverflowError
at cmazxiaoma.model.School.hashCode(School.java:22)
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:84)
at cmazxiaoma.model.School_$$_jvstc33_0.hashCode(School_$$_jvstc33_0.java)
at cmazxiaoma.model.Student.hashCode(Student.java:20)
複製程式碼
// School類的hashCode()方法
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $schoolName = this.getSchoolName();
result = result * 59 + ($schoolName == null ? 43 : $schoolName.hashCode());
Object $studentList = this.getStudentList();
result = result * 59 + ($studentList == null ? 43 : $studentList.hashCode());
Object $createdDt = this.getCreatedDt();
result = result * 59 + ($createdDt == null ? 43 : $createdDt.hashCode());
Object $updatedDt = this.getUpdatedDt();
result = result * 59 + ($updatedDt == null ? 43 : $updatedDt.hashCode());
Object $isDel = this.getIsDel();
result = result * 59 + ($isDel == null ? 43 : $isDel.hashCode());
return result;
}
// Student類中的hashCode()方法
public int hashCode() {
int PRIME = true;
int result = 1;
Object $id = this.getId();
int result = result * 59 + ($id == null ? 43 : $id.hashCode());
Object $studentName = this.getStudentName();
result = result * 59 + ($studentName == null ? 43 : $studentName.hashCode());
Object $schoolId = this.getSchoolId();
result = result * 59 + ($schoolId == null ? 43 : $schoolId.hashCode());
Object $school = this.getSchool();
result = result * 59 + ($school == null ? 43 : $school.hashCode());
Object $createdDt = this.getCreatedDt();
result = result * 59 + ($createdDt == null ? 43 : $createdDt.hashCode());
Object $updatedDt = this.getUpdatedDt();
result = result * 59 + ($updatedDt == null ? 43 : $updatedDt.hashCode());
Object $isDel = this.getIsDel();
result = result * 59 + ($isDel == null ? 43 : $isDel.hashCode());
return result;
}
複製程式碼
HashSet的hashCode()方法來自與父類AbstractSet。
public int hashCode() {
int h = 0;
Iterator<E> i = iterator();
while (i.hasNext()) {
E obj = i.next();
if (obj != null)
h += obj.hashCode();
}
return h;
}
複製程式碼
@Override
public boolean equals(Object o) {
if (this == o) returntrue;
if (!(o instanceof School)) returnfalse;
if (!super.equals(o)) returnfalse;
School school = (School) o;
if (!getId().equals(school.getId())) returnfalse;
if (!getSchoolName().equals(school.getSchoolName())) returnfalse;
if (!getCreatedDt().equals(school.getCreatedDt())) returnfalse;
if (!getUpdatedDt().equals(school.getUpdatedDt())) returnfalse;
return getIsDel().equals(school.getIsDel());
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + getId().hashCode();
result = 31 * result + getSchoolName().hashCode();
result = 31 * result + getCreatedDt().hashCode();
result = 31 * result + getUpdatedDt().hashCode();
result = 31 * result + getIsDel().hashCode();
return result;
}
複製程式碼
@Override
public boolean equals(Object o) {
if (this == o) returntrue;
if (!(o instanceof Student)) returnfalse;
Student student = (Student) o;
if (!getId().equals(student.getId())) returnfalse;
if (!getStudentName().equals(student.getStudentName())) returnfalse;
if (!getSchoolId().equals(student.getSchoolId())) returnfalse;
if (!getCreatedDt().equals(student.getCreatedDt())) returnfalse;
if (!getUpdatedDt().equals(student.getUpdatedDt())) returnfalse;
return getIsDel().equals(student.getIsDel());
}
@Override
public int hashCode() {
int result = getId().hashCode();
result = 31 * result + getStudentName().hashCode();
result = 31 * result + getSchoolId().hashCode();
result = 31 * result + getCreatedDt().hashCode();
result = 31 * result + getUpdatedDt().hashCode();
result = 31 * result + getIsDel().hashCode();
return result;
}
複製程式碼
public class SonTest {
@Test
public void test() {
Son son1 = new Son();
son1.setSonName("son1");
son1.setFatherName("baseFather");
Son son2 = new Son();
son2.setSonName("son1");
son2.setFatherName("baseFather2");
System.out.println(son1.equals(son2));
}
}
複製程式碼
檢視反編譯後的Son類程式碼,恍然大悟。
public boolean equals(Object o) {
if (o == this) {
returntrue;
} elseif (!(o instanceof Son)) {
returnfalse;
} else {
Son other = (Son)o;
if (!other.canEqual(this)) {
returnfalse;
} else {
Object this$sonName = this.getSonName();
Object other$sonName = other.getSonName();
if (this$sonName == null) {
if (other$sonName != null) {
returnfalse;
}
} elseif (!this$sonName.equals(other$sonName)) {
returnfalse;
}
returntrue;
}
}
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $sonName = this.getSonName();
int result = result * 59 + ($sonName == null ? 43 : $sonName.hashCode());
return result;
}
複製程式碼
/**
* Call on the superclass's implementations of {@code equals} and {@code hashCode} before calculating
* for the fields in this class.
* <strong>default: false</strong>
*/
boolean callSuper() default false;
複製程式碼