Code ví dụ Hibernate FetchType = LAZY (Lazy loading)

Code ví dụ Hibernate FetchType = LAZY (Lazy loading).

(Xem thêm: Hướng dẫn tự học Hibernate)

(Xem lại: Hibernate FetchType là gì? So sánh sự khác nhau giữa FetchType Lazy và Eager.)

(Xem thêm: Code ví dụ Hibernate FetchType = EAGER (Eager loading))

Các công nghệ sử dụng:

Tạo database MySQL

CREATE SCHEMA `hibernate-fetch` ;

CREATE TABLE `hibernate-fetch`.`company` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(45) NULL,
  `address` VARCHAR(255) NULL,
  PRIMARY KEY (`id`));

  
CREATE TABLE `hibernate-fetch`.`employee` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `company_id` INT NULL,
  `name` VARCHAR(45) NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `emp-company`
    FOREIGN KEY (`company_id`)
    REFERENCES `hibernate-fetch`.`company` (`id`));

Cấu trúc Project

Code ví dụ Hibernate FetchType = LAZY (Lazy loading)

 

Các thư viện sử dụng

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>stackjava.com</groupId>
  <artifactId>HibernateFetchLazy</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
    <hibernate.version>5.3.6.Final</hibernate.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-entitymanager</artifactId>
      <version>${hibernate.version}</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.46</version>
    </dependency>
  </dependencies>


</project>

File cấu hình hibernate, kết nối tới MySQL

<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">
  <persistence-unit name="persistence">
    <description>Demo HibernateFetchLazy</description>
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
      <property name="javax.persistence.jdbc.url"
        value="jdbc:mysql://localhost:3306/hibernate-fetch" />
      <property name="javax.persistence.jdbc.user" value="root" />
      <property name="javax.persistence.jdbc.password" value="admin1234" />
      <property name="hibernate.show_sql" value="true" />
    </properties>
  </persistence-unit>
</persistence>

Trong ví dụ này mình sử dụng entityManager nên sẽ khai báo file persistence.xml nếu các bạn sử dụng hibernateSession thì có thể khai báo file hibernate.cfg.xml

Các File entity

@Entity
@Table(name = "company")
public class Company {

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "name")
  private String name;

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "company", cascade = CascadeType.ALL)
  private List<Employee> listEmployee = new ArrayList<>();

  // getter - setter - constructor

  @Override
  public String toString() {
    return "Company [id=" + id + ", name=" + name + "]";
  }

}
@Entity
@Table(name = "employee")
public class Employee {

  @Id
  @Column(name = "id")
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Integer id;

  @Column(name = "name")
  private String name;

  @ManyToOne
  @JoinColumn(name = "company_id", nullable = false)
  private Company company;

  // getter - setter - constructor

  @Override
  public String toString() {
    return "Employee [id=" + id + ", name=" + name + ", company=" + company + "]";
  }

}

File DAO

package stackjava.com.hibernatedemo.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceUnitUtil;

import stackjava.com.hibernatedemo.entities.Company;
import stackjava.com.hibernatedemo.entities.Employee;

public class CompanyDAO {
  EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistence");

  public Company findById(int id) {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    Company company = entityManager.find(Company.class, id);
    entityManager.close();
    return company;
  }

  public Company save(Company company) {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.persist(company);
    entityManager.getTransaction().commit();
    entityManager.close();
    return company;
  }

  public Company findByIdWithEmployee(int id) {
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    Company company = entityManager.find(Company.class, id);
    List<Employee> listEmployee = company.getListEmployee();
    listEmployee.size();
    entityManager.close();
    return company;
  }

  public List<Employee> getListEmployeeByCompany(Company company) {
    PersistenceUnitUtil impl = entityManagerFactory.getPersistenceUnitUtil();
    if (!impl.isLoaded(company.getListEmployee())){
      System.out.println("listEmployee is Lazy");
      EntityManager entityManager = entityManagerFactory.createEntityManager();
      List<Employee> listEmployee = entityManager
          .createQuery("SELECT e FROM Employee e WHERE company = :company", Employee.class).setParameter("company", company).getResultList();
      entityManager.close();
      return listEmployee;
    } else {
      return company.getListEmployee();
    }
  }

  public void close() {
    entityManagerFactory.close();
  }

}

 

Demo

Demo1

Đầu tiên insert đối tượng company và các đối tượng employee cho company đó:

package stackjava.com.hibernatedemo;

import stackjava.com.hibernatedemo.dao.CompanyDAO;
import stackjava.com.hibernatedemo.entities.Company;
import stackjava.com.hibernatedemo.entities.Employee;

public class DemoInsert {

  public static void main(String[] args) {
    CompanyDAO companyDAO = new CompanyDAO();
    Company company = new Company("Google");
    Employee emp1 = new Employee("Bat Man");
    Employee emp2 = new Employee("Super Man");
    Employee emp3 = new Employee("Iron Man");
    emp1.setCompany(company);
    emp2.setCompany(company);
    emp3.setCompany(company);
    company.getListEmployee().add(emp1);
    company.getListEmployee().add(emp2);
    company.getListEmployee().add(emp3);
    companyDAO.save(company);
    System.out.println("Saved!");
    System.out.println(company);
    System.out.println(emp1);
    System.out.println(emp2);
    System.out.println(emp3);
    companyDAO.close();
  }

}

Kết quả:

Code ví dụ Hibernate FetchType = EAGER (Eager loading)

Sau khi được save vào database, các đối tượng employee và company sẽ tự động được tạo id.

Demo2

Bây giờ select đối tượng company vừa tạo ở trên.

package stackjava.com.hibernatedemo;

import java.util.List;

import stackjava.com.hibernatedemo.dao.CompanyDAO;
import stackjava.com.hibernatedemo.entities.Company;
import stackjava.com.hibernatedemo.entities.Employee;

public class DemoSelect {

  public static void main(String[] args) {
    CompanyDAO companyDAO = new CompanyDAO();
    int companyId = 1;
//		Company company = companyDAO.findByIdWithEmployee(companyId);
    Company company = companyDAO.findById(companyId);
    if (company != null) {
      List<Employee> listEmployee = company.getListEmployee();
//			List<Employee> listEmployee = companyDAO.getListEmployeeByCompany(company);
      for (Employee emp : listEmployee) {
        System.out.println(emp);
      }

    } else {
      System.out.println("Not found company with id = " + companyId);
    }
    companyDAO.close();
  }

}

Kết quả:

Các bạn thấy không hề có câu sql select employee, và xảy ra lỗi LazyInitializationException do các đối tượng Employee bên trong Company chưa được select ra.

Sửa lỗi LazyInitializationException

Lỗi LazyInitializationException phát sinh do listEmployee chưa được query, do đó để khắc phục lỗi này ta cần query listEmployee trước đó và gán nó vào đối tượng Company.

Cách thứ 1: khi query company ta sẽ query luôn listEmployee (query listEmployee và gán vào company)
Ở đây mình gọi luôn method company.getListEmployee(), vì nó vẫn nằm trong transaction nên vẫn lấy được listEmployee bình thường.

public List<Employee> getListEmployeeByCompany(Company company) {
  if (company.getListEmployee() instanceof PersistentBag || company.getListEmployee() == null){
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    List<Employee> listEmployee = entityManager
        .createQuery("SELECT e FROM Employee e WHERE company = :company", Employee.class).setParameter("company", company).getResultList();
    entityManager.close();
    return listEmployee;
  } else {
    return company.getListEmployee();
  }
}

Thử lại bằng cách thay method findById bằng method findByIdWithEmployee

Kết quả: Ngoài câu sql select company sẽ có thêm 1 câu sql select listEmployee

Sửa lỗi LazyInitializationException

Cách thứ 2: Khi gọi method company.getListEmployee()ta sẽ check xem listEmployee đã được load chưa, nếu chưa được load thì ta query lại, nếu load rồi thì thôi.

public List<Employee> getListEmployeeByCompany(Company company) {
  PersistenceUnitUtil impl = entityManagerFactory.getPersistenceUnitUtil();
  if (!impl.isLoaded(company.getListEmployee())){
    System.out.println("listEmployee is Lazy");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    List<Employee> listEmployee = entityManager
        .createQuery("SELECT e FROM Employee e WHERE company = :company", Employee.class).setParameter("company", company).getResultList();
    entityManager.close();
    return listEmployee;
  } else {
    return company.getListEmployee();
  }
}

Thử lại bằng cách thay method getListEmployee() bằng method companyDAO.getListEmployeeByCompany()

Kết quả:

Sửa lỗi LazyInitializationException trong hibernate

 

_______________________

Okay, Done!

Download code ví dụ trên tại đây.

References:

https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/FetchType.html

stackjava.com