LazyInitializationException: 在Hibernate中从与原始会话不同的会话中加载延迟属性

huangapple go评论115阅读模式
英文:

LazyInitializationException: load lazy attribute from a session different from the original one in Hibernate

问题

  1. 我是初学者正在学习 Hibernate并尝试了解急加载和懒加载
  2. 我知道如果 Hibernate 会话已关闭然后我尝试检索懒加载数据那么 Hibernate 将抛出异常
  3. 现在我尝试在第一个会话中加载主实体Instructor),然后在一个***新的独立会话***中加载从属实体Course):
  4. **主类测试类**
  5. ```java
  6. public class EagerLazyDemo {
  7. public static void main(String[] args) {
  8. SessionFactory factory = new Configuration().configure("hibernate.cfg.xml")
  9. .addAnnotatedClass(Instructor.class)
  10. .addAnnotatedClass(InstructorDetail.class)
  11. .addAnnotatedClass(Course.class)
  12. .buildSessionFactory();
  13. Session session = factory.getCurrentSession();
  14. // 开始事务
  15. session.beginTransaction();
  16. // 从数据库获取讲师信息
  17. Instructor theInstructor = session.get(Instructor.class, 1);
  18. // 提交事务
  19. session.getTransaction().commit();
  20. session.close();
  21. //------
  22. // 新会话
  23. session = factory.getCurrentSession();
  24. session.beginTransaction();
  25. // 获取并显示讲师的课程
  26. List<Course> courses = theInstructor.getCourses();
  27. printCourses(courses);
  28. session.getTransaction().commit();
  29. session.close();
  30. }
  31. private static void printCourses(List<Course> courses) {
  32. for (Course c : courses) {
  33. System.out.println(c);
  34. }
  35. }
  36. }

但是 Hibernate 抛出了以下异常:

错误:

  1. Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mehdisarf.hibernate.demo.entity.Instructor.courses, could not initialize proxy - no Session
  2. at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
  3. at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
  4. at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
  5. at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
  6. at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387)
  7. at com.mehdisarf.hibernate.demo.EagerLazyDemo.printCourses(EagerLazyDemo.java:55)
  8. at com.mehdisarf.hibernate.demo.EagerLazyDemo.main(EagerLazyDemo.java:42)

它表示:

> 无法初始化代理 - 没有会话

尽管我已经为加载从属实体创建了一个会话

以下是我的实体类:

讲师类(主实体)

  1. @Entity
  2. @Table(name = "instructor")
  3. public class Instructor {
  4. // ... (省略其他代码)
  5. @OneToMany(fetch = FetchType.LAZY,
  6. mappedBy = "instructor",
  7. cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
  8. private List<Course> courses;
  9. // ... (省略其他代码)
  10. }

课程类(从属实体)

  1. @Entity
  2. @Table(name = "course")
  3. public class Course {
  4. // ... (省略其他代码)
  5. @ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
  6. @JoinColumn(name = "instructor_id")
  7. private Instructor instructor;
  8. // ... (省略其他代码)
  9. }
  1. <details>
  2. <summary>英文:</summary>
  3. I&#39;m beginner at hibernate and try to learn eager and lazy loading
  4. I know that if the hibernate session is closed and then I try to retrieve lazy data, then Hibernate will throw an exception.
  5. Now, I&#39;ve tried to load main entity(Instructor) in first session and then load dependent entity(Course) in a ***new separate session***:
  6. **Main Class(Test Class)**
  7. public class EagerLazyDemo {
  8. public static void main(String[] args) {
  9. SessionFactory factory = new Configuration().configure(&quot;hibernate.cfg.xml&quot;)
  10. .addAnnotatedClass(Instructor.class)
  11. .addAnnotatedClass(InstructorDetail.class)
  12. .addAnnotatedClass(Course.class)
  13. .buildSessionFactory();
  14. Session session = factory.getCurrentSession();
  15. // Begin A Transaction
  16. session.beginTransaction();
  17. // Get The Instructor From DB
  18. Instructor theInstructor = session.get(Instructor.class, 1);
  19. // Commit Transaction
  20. session.getTransaction().commit();
  21. session.close();
  22. //------
  23. //new session
  24. session = factory.getCurrentSession();
  25. session.beginTransaction();
  26. //Get And Display Courses For The Instructor
  27. List&lt;Course&gt; courses = theInstructor.getCourses();
  28. printCourses(courses);
  29. session.getTransaction().commit();
  30. session.close();
  31. }
  32. private static void printCourses(List&lt;Course&gt; courses) {
  33. for (Course c : courses) {
  34. System.out.println(c);
  35. }
  36. }
  37. }
  38. but hibernate throw this exception:
  39. **Error:**
  40. Exception in thread &quot;main&quot; org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mehdisarf.hibernate.demo.entity.Instructor.courses, could not initialize proxy - no Session
  41. at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
  42. at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
  43. at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
  44. at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
  45. at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:387)
  46. at com.mehdisarf.hibernate.demo.EagerLazyDemo.printCourses(EagerLazyDemo.java:55)
  47. at com.mehdisarf.hibernate.demo.EagerLazyDemo.main(EagerLazyDemo.java:42)
  48. **it says:**
  49. &gt; could not initialize proxy - no Session
  50. Although I have a session for loading dependent entity
  51. **These Are My Entity Classes:**
  52. **Instructor Class (main entity)**
  53. @Entity
  54. @Table(name = &quot;instructor&quot;)
  55. public class Instructor {
  56. @Id
  57. @GeneratedValue(strategy = GenerationType.IDENTITY)
  58. @Column(name = &quot;id&quot;)
  59. private int id;
  60. @Column(name = &quot;first_name&quot;)
  61. private String firstName;
  62. @Column(name = &quot;last_name&quot;)
  63. private String lastName;
  64. @Column(name = &quot;email&quot;)
  65. private String email;
  66. @OneToOne(cascade = CascadeType.ALL)
  67. @JoinColumn(name = &quot;instructor_detail_id&quot;)
  68. private InstructorDetail instructorDetail;
  69. @OneToMany(fetch = FetchType.LAZY,
  70. mappedBy = &quot;instructor&quot;,
  71. cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
  72. private List&lt;Course&gt; courses;
  73. public Instructor() {
  74. }
  75. public Instructor(String firstName, String lastName, String email) {
  76. this.firstName = firstName;
  77. this.lastName = lastName;
  78. this.email = email;
  79. }
  80. public void addCourse(Course theCourse) {
  81. if (courses == null) {
  82. courses = new ArrayList&lt;&gt;();
  83. }
  84. this.courses.add(theCourse);
  85. theCourse.setInstructor(this);
  86. }
  87. public int getId() {
  88. return id;
  89. }
  90. public void setId(int id) {
  91. this.id = id;
  92. }
  93. public String getFirstName() {
  94. return firstName;
  95. }
  96. public void setFirstName(String firstName) {
  97. this.firstName = firstName;
  98. }
  99. public String getLastName() {
  100. return lastName;
  101. }
  102. public void setLastName(String lastName) {
  103. this.lastName = lastName;
  104. }
  105. public String getEmail() {
  106. return email;
  107. }
  108. public void setEmail(String email) {
  109. this.email = email;
  110. }
  111. public InstructorDetail getInstructorDetail() {
  112. return instructorDetail;
  113. }
  114. public void setInstructorDetail(InstructorDetail instructorDetail) {
  115. this.instructorDetail = instructorDetail;
  116. }
  117. public List&lt;Course&gt; getCourses() {
  118. return courses;
  119. }
  120. public void setCourses(List&lt;Course&gt; courses) {
  121. this.courses = courses;
  122. }
  123. @Override
  124. public String toString() {
  125. return id + &quot;&quot; + firstName + &quot;&quot; + lastName + &quot;&quot; + email + &quot; (Detail:&quot; + instructorDetail+&quot;)&quot;;
  126. }
  127. }
  128. **Course Class (dependent entity)**
  129. @Entity
  130. @Table(name = &quot;course&quot;)
  131. public class Course {
  132. @Id
  133. @GeneratedValue(strategy = GenerationType.IDENTITY)
  134. @Column(name = &quot;id&quot;)
  135. private int id;
  136. @Column(name = &quot;title&quot;)
  137. private String title;
  138. @ManyToOne(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
  139. @JoinColumn(name = &quot;instructor_id&quot;)
  140. private Instructor instructor;
  141. public Course() {
  142. }
  143. public Course(String title) {
  144. this.title = title;
  145. }
  146. public int getId() {
  147. return id;
  148. }
  149. public void setId(int id) {
  150. this.id = id;
  151. }
  152. public String getTitle() {
  153. return title;
  154. }
  155. public void setTitle(String title) {
  156. this.title = title;
  157. }
  158. public Instructor getInstructor() {
  159. return instructor;
  160. }
  161. public void setInstructor(Instructor instructor) {
  162. this.instructor = instructor;
  163. }
  164. @Override
  165. public String toString() {
  166. return id + &quot;|&quot; + title + &quot;|&quot;;
  167. }
  168. }
  169. </details>
  170. # 答案1
  171. **得分**: 2
  172. 你的对象theInstructor仍然与之前的会话关联。为了检索你的对象,在打开新会话后,你需要进行另一个调用:
  173. theInstructor = session.get(Instructor.class, 1);
  174. <details>
  175. <summary>英文:</summary>
  176. Your object theInstructor is still linked to the former session. In order to retrieve your object you have to make another call after opening the new session :
  177. theInstructor = session.get(Instructor.class, 1);
  178. </details>
  179. # 答案2
  180. **得分**: 1
  181. "theInstructor"在进行"theInstructor.getCourses()"调用时,并未连接到任何会话,这导致了异常。
  182. 当对象通过get方法返回时,它处于持久状态。
  183. > 任何由get()或load()方法返回的实例都是持久的。[会话文档][1]
  184. 当会话关闭时,"theInstructor"对象进入脱离状态。
  185. > 脱离状态 - 脱离的实例是指已经持久化,但其会话已关闭的对象。[Hibernate对象状态文档][2]
  186. 调用`session = factory.getCurrentSession();`返回新的会话对象,但"theInstructor"对象并未连接到新会话。因此,尝试惰性加载课程时会失败。
  187. [1]: https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html#get(java.lang.Class,%20java.io.Serializable)
  188. [2]: https://docs.jboss.org/hibernate/core/3.5/reference/en/html/objectstate.html
  189. <details>
  190. <summary>英文:</summary>
  191. &quot;theInstructor&quot; is not attached to any session while &quot;theInstructor.getCourses()&quot; call is made, this results in exception.
  192. When object is returned by the get method it is in the Persistent state.
  193. &gt; Any instance returned by a get() or load() method is persistent
  194. [Session Documentation][1]
  195. When session is closed &quot;theInstructor&quot; object goes into the Detached state.
  196. &gt; Detached - a detached instance is an object that has been persistent, but its Session has been closed. [Hibernate object states documentation][2]
  197. Call made to `session = factory.getCurrentSession();` returns new session object, but `theInstructor` object is not attached to the new session. Hence an attempt to lazily load the courses fails.
  198. [1]: https://docs.jboss.org/hibernate/orm/3.5/api/org/hibernate/Session.html#get(java.lang.Class,%20java.io.Serializable)
  199. [2]: https://docs.jboss.org/hibernate/core/3.5/reference/en/html/objectstate.html
  200. </details>

huangapple
  • 本文由 发表于 2020年5月5日 05:20:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/61601826.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定