Tell me, please, how to properly use the delayed load strategy in Hibernate. Suppose there is a class Student :
@Entity @Table(name = "students") public class Student { @Id @Column(name = "student_id") @GeneratedValue(strategy = GenerationType.IDENTITY) public Long id; public String name; public Student(){} public Student(String name){ this.name = name; } } and the Room class, which has a reference to the Student class with a one-to-one relationship and using the delayed load strategy fetch = FetchType.LAZY :
@Entity @Table(name = "rooms") public class Room { @Id public Long id; @Column(name = "number") public int number; @OneToOne( fetch = FetchType.LAZY, optional = false ) @PrimaryKeyJoinColumn public Student student; public Room(){} public Room(int number, Student student) { this.id = student.id; this.number = number; this.student = student; } } To get the Room entity, I use the RoomService function of the RoomService class:
public class RoomService { public RoomService(){} public Room get(long id) throws DBException { Transaction transaction = DBService.getTransaction(); try { Room room = DaoFactory.getRoomDao().get(id); transaction.commit(); return room; } catch (HibernateException | NoResultException | NullPointerException e) { DBService.transactionRollback(transaction); throw new DBException(e); } } To obtain a transaction, use the following function from the DBService class:
public static Transaction getTransaction(){ Session session = DBService.getSessionFactory().getCurrentSession(); Transaction transaction = session.getTransaction(); if (!transaction.isActive()) { transaction = session.beginTransaction(); } return transaction; } } Actually, finally the calling code itself:
StudentService studentService = new StudentService(); RoomService roomService = new RoomService(); try { Student student = studentService.create(new Student("Вася")); Room room = roomService.create(new Room(5, student)); Room room2 = roomService.get(room.id); } Actually, the problem is in room2 , since the student field, although not null , but all the fields in room2.student.id and room2.student.name are null . When debugging, you can see that when you call the get function, an org.hibernate.LazyInitializationException occurs org.hibernate.LazyInitializationException you try to get room2.student , that is, the data from the database is not loaded immediately. Due to the fact that the transaction is completed, this data can no longer be obtained.
What needs to be done so that the data can be loaded later? It is clear that you can replace fetch = FetchType.LAZY with fetch = FetchType.EAGER , but then the data will always be loaded, which is not always acceptable. How should an application be properly designed so that you can use a deferred loading strategy?
UPDRoomDao class RoomDao very short:
public class RoomDao extends AbstractDao<Room> { RoomDao() { super(Room.class); } } And this is the get class get function:
@Override public T get(long id) { return DBService.getSessionFactory() .getCurrentSession() .get(parameterizedClass, id, LockMode.PESSIMISTIC_READ); }
persistenceUtil.isLoaded(room.student()). This expression returnsfalse, i.e. the storage context of thestudententity of theroomentity is closed. Moreover, even if we add the lineHibernate.initialize(room.student());to thegetfunction of theRoomServiceclassHibernate.initialize(room.student());after the lineRoom room = DaoFactory.getRoomDao().get(id);, then the initialization of the proxy objectroom.studentwill not occur. All fields of this object arenull. - golubtsoffoptional = falsein theRoomclass, everything works in a magical way. And all because the relation (mapping) of theone-to-oneconnection with the common primary key with theoptional = trueparameter does not support deferred data loading, i.e. works the same as withfetch = FetchType.EAGER. Why does not work withoptional = falseis not clear. - golubtsoffHibernate.initialize(room.student());all the fields inroom.studentarenull, but if you go to the fieldroom.student.addressinmain, the address is read normally. In the absence ofHibernate.initialize(room.student());anorg.hibernate.LazyInitializationExceptionexception wasorg.hibernate.LazyInitializationException. - golubtsoff