Home > Blockchain >  Hibernate - Why is lazy loading not working here?
Hibernate - Why is lazy loading not working here?

Time:07-03

I am learning Hibernate from an online course, and right now, I am learning Eager vs Lazy loading.

For the example I have three entities and a test program like so:

@Entity
@Table(name = "instructor")
public class Instructor {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    
    @Column(name = "first_name")
    private String firstName;
    
    @Column(name = "last_name")
    private String lastName;
    
    @Column(name = "email")
    private String email;
    
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "instructor_detail_id")
    private InstructorDetail instructorDetail;
    
    @OneToMany(fetch = FetchType.LAZY,
            mappedBy = "instructor",
            cascade = {
                    CascadeType.DETACH,
                    CascadeType.MERGE,
                    CascadeType.PERSIST,
                    CascadeType.REFRESH
            })
    private List<Course> courses;
    
    // constructors
    
    public void add(Course tempCourse) {
        if (courses == null) {
            courses = new ArrayList<>();
        }
        
        if (tempCourse != null) {
            courses.add(tempCourse);
            tempCourse.setInstructor(this);
        }
    }
    
    // getters and setters
    
    @Override
    public String toString() {
        return "Instructor{"  
                "id="   id  
                ", firstName='"   firstName   '\''  
                ", lastName='"   lastName   '\''  
                ", email='"   email   '\''  
                ", instructorDetail="   instructorDetail  
                '}';
    }
    
}
@Entity
@Table(name = "instructor_detail")

public class InstructorDetail {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    
    @Column(name = "youtube_channel")
    private String youtubeChannel;
    
    @Column(name = "hobby")
    private String hobby;
    
    @OneToOne(mappedBy = "instructorDetail",
            cascade = {
                    CascadeType.DETACH,
                    CascadeType.MERGE,
                    CascadeType.PERSIST,
                    CascadeType.REFRESH
            })
    private Instructor instructor;
    
    // constructors
    
    // getters and setters
    
    @Override
    public String toString() {
        return "InstructorDetail{"  
                "id="   id  
                ", youtubeChannel='"   youtubeChannel   '\''  
                ", hobby='"   hobby   '\''  
                '}';
    }
    
}
@Entity
@Table(name = "course")
public class Course {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    
    @Column(name = "title")
    private String title;
    
    @ManyToOne(fetch = FetchType.LAZY,
            cascade = {
                    CascadeType.DETACH,
                    CascadeType.MERGE,
                    CascadeType.PERSIST,
                    CascadeType.REFRESH})
    @JoinColumn(name = "instructor_id")
    private Instructor instructor;
    
    // constructors
    
    // getters and setters
    
    @Override
    public String toString() {
        return "Course{"  
                "id="   id  
                ", title='"   title   '\''  
                '}';
    }
    
}

Main Program:

package pt.hmsk.hibernate.demo;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import pt.hmsk.hibernate.demo.entity.Course;
import pt.hmsk.hibernate.demo.entity.Instructor;
import pt.hmsk.hibernate.demo.entity.InstructorDetail;

public class EagerLazyDemo {
    
    public static void main(String[] args) {
        try (SessionFactory factory = new Configuration()
                .configure("hibernate.cfg.xml")
                .addAnnotatedClass(Instructor.class)
                .addAnnotatedClass(InstructorDetail.class)
                .addAnnotatedClass(Course.class)
                .buildSessionFactory();
             Session session = factory.getCurrentSession()) {
            
            // start a transaction
            session.beginTransaction();
    
            // get instructor from db
            int theId = 1;
            Instructor tempInstructor = session.get(Instructor.class, theId);
    
            System.out.println("luv2code: Instructor: "   tempInstructor);
            
            // get courses for the instructor
            System.out.println("luv2code: Courses: "   tempInstructor.getCourses());
            
            // commit transaction
            session.getTransaction().commit();
            
            System.out.println("luv2code: Done!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
}

Then, I put a breakpoint in the main program at the line:

System.out.println("luv2code: Instructor: "   tempInstructor);

Supposedly here, no call to the courses field was done yet so, it shouldn't be in the tempInstructor obejct, but debugging the program shows that the course was loaded into the Instructor obejct anyways: debugger

Why is this happening??

CodePudding user response:

You are lazy loading the courses, but because you are referencing them via the line

System.out.println("luv2code: Courses: "   tempInstructor.getCourses());

they are loaded in.

Turn on logging of the queries by adding to your hibernate.cfg.xml

<property name="hibernate.show_sql">true</property>

And don't get the courses from the Instructor, then you will see, that they were in fact lazy-loaded.

CodePudding user response:

Oh, another way to verify it, is to do the call to the courses after you've committed the transaction. The transaction is the scope, where lazy loading can happen.

  • Related