카테고리 없음

JPA test - 2

happyst 2024. 10. 30. 16:34

JPA의 성능 최적화 기능

1차 캐시와 동일성 (identity) 보장

  • 같은 트랜잭션 안에서는 같은 엔티티를 반환함
EmployeeFindTest.java
package jpajava;

import domain.Employee;

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

public class EmployeeFindTest {
  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();
    System.out.println("TRANSACTION STARTED");
    try {
      System.out.println("비영속 상태");
      System.out.println("DB에서 가져옴");
      Employee emp1 = em.find(Employee.class, "202402");
      System.out.println("employee.getEmpName() : " + emp1.getEmpName());
      System.out.println("commit 전");
      tx.commit();
      System.out.println("commit 후");
      System.out.println("1차 캐시에서 가져옴");
      Employee emp2 = em.find(Employee.class, "202402");
      System.out.println("employee.getEmpName() : " + emp2.getEmpName());

      // 1차 캐시와 동일성(identity) 보장
      System.out.println("emp1 == emp2 : " + (emp1 == emp2));

    } catch (Exception e) {
      tx.rollback();
      System.out.println("TRANSACTION ROLLBACK");
      System.out.println("[Error] " + e.getMessage());
    } finally {
      System.out.println("TRANSACTION ENDED");
    }
  }

}
실행 결과

 


트랜잭션을 지원하는 쓰기 지연 (Transactional Write Behind)

  • 트랜잭션을 commit 할 때까지 INSERT SQL을 전송하지 않고 지연시킴
  • commit하는 순간, 모아둔 INSERT SQL을 한번에 전송함 (Update, Delete도 마찬가지)
src/main/java/jpajava/EmployeeWriteBehind.java
package jpajava;

import domain.Employee;

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

public class EmployeeWriteBehind {
  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();
    System.out.println("TRANSACTION STARTED");
    try {
      Employee emp1 = new Employee("202403", "아이린", null, "2024-01-01", 600);
      Employee emp2 = new Employee("202404", "슬기", null, "2024-01-01", 600);
      Employee emp3 = new Employee("202405", "조이", null, "2024-01-01", 600);
      em.persist(emp1);
      em.persist(emp2);
      em.persist(emp3);

      System.out.println("commit 전");
      tx.commit();
      System.out.println("commit 후");
    } catch (Exception e) {
      tx.rollback();
      System.out.println("TRANSACTION ROLLBACK");
      System.out.println("[Error] " + e.getMessage());
    } finally {
      System.out.println("TRANSACTION ENDED");
    }
  }
}
실행 결과 - 쓰기 지연 적용 O

 


src/main/java/jpajava/DeptWriteBehind.java
package jpajava;

import domain.Department;
import domain.Employee;

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

public class DeptWriteBehind {
  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
    EntityManager em = emf.createEntityManager();
    EntityTransaction tx = em.getTransaction();

    tx.begin();
    System.out.println("TRANSACTION STARTED");
    try {
      Department dept1 = new Department();
      dept1.setDeptName("AA");
      Department dept2 = new Department();
      dept2.setDeptName("BB");
      Department dept3 = new Department();
      dept3.setDeptName("CC");

      em.persist(dept1);
      System.out.println("dept1 생성");
      em.persist(dept2);
      System.out.println("dept2 생성");
      em.persist(dept3);
      System.out.println("dept3 생성");

      System.out.println("commit 전");
      tx.commit();
      System.out.println("commit 후");
    } catch (Exception e) {
      tx.rollback();
      System.out.println("TRANSACTION ROLLBACK");
      System.out.println("[Error] " + e.getMessage());
    } finally {
      System.out.println("TRANSACTION ENDED");
    }
  }
}
실행 결과 - 쓰기 지연 적용 X

 

 

@GeneratedValue(strategy = GenerationType.IDENTITY)를 사용하면 쓰기 지연(write-behind)이 제대로 적용되지 않음

  • IDENTITY 전략이 데이터베이스의 AUTO INCREMENT 기능을 통해 기본 키를 즉시 할당받기 때문에, 엔티티를 persist하는 순간 즉시 INSERT 쿼리를 실행해야만 기본 키 값을 가져올 수 있기 때문!!
  • 쓰기 지연을 활용하려면 GenerationType.SEQUENCE나 GenerationType.TABLE 같은 다른 키 생성 전략을 사용해야 함