ABOUT ME

Today
Yesterday
Total
  • JPA test - 1
    카테고리 없음 2024. 10. 30. 12:29
    src/main/resources/META-INF/persistence.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.2"
                 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_2.xsd">
        <!--  EntityManagerFactory 생성 시 사용되는 persistence name -->
        <persistence-unit name="jpatest">
            <properties>
                <!-- 필수 속성 -->
                <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="javax.persistence.jdbc.user" value="root"/>
                <property name="javax.persistence.jdbc.password" value="1111"/>
                <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpatest?characterEncoding=UTF-8"/>
    
                <!-- 하이버네이트 사용 시 다른 DB에서 MySQL 문법을 사용 가능하도록 변경.-->
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL8Dialect"/>
                <!-- 콘솔에 SQL 출력 여부 -->
                <property name="hibernate.show_sql" value="true"/>
                <!-- 가독성 높여주는 formatting 여부 -->
                <property name="hibernate.format_sql" value="true"/>
                <!-- Comment 확인 여부 -->
                <property name="hibernate.use_sql_comments" value="true"/>
                <!-- 테이블 생성 옵션 create / create-drop / validate / update / none -->
                <property name="hibernate.hbm2ddl.auto" value="create"/>
            </properties>
        </persistence-unit>
    </persistence>
    • hibernate.hbm2ddl.auto 옵션
      • create
        • 애플리케이션 시작 시 기존 테이블을 삭제하고, 엔티티 매핑 정보에 따라 모든 테이블과 관계를 새로 생성함
        • 기존 데이터가 삭제되므로 개발 초기 단계에서 주로 사용
      • update
        • 엔티티 매핑 정보를 기반으로 기존 테이블을 수정함
        • 새로운 컬럼이 있으면 추가하고, 없으면 기존 상태를 유지함
        • 데이터는 삭제되지 않으며, 테이블에 없는 새 컬럼만 추가
    src/main/java/domain/Employee.java
    package domain;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Entity
    @Table(name = "employee")
    public class Employee {
      @Id
      @Column(name = "emp_id", length = 6)
      private String empId;
      private String empName;
      private String deptId;
      private String joinDate;
      private long salary;
    
      public Employee() {
      }
    
      public Employee(String empId, String empName, String deptId, String joinDate, long salary) {
        this.empId = empId;
        this.empName = empName;
        this.deptId = deptId;
        this.joinDate = joinDate;
        this.salary = salary;
      }
    
      public String getEmpId() {
        return empId;
      }
    
      public void setEmpId(String empId) {
        this.empId = empId;
      }
    
      public String getEmpName() {
        return empName;
      }
    
      public void setEmpName(String empName) {
        this.empName = empName;
      }
    
      public String getDeptId() {
        return deptId;
      }
    
      public void setDeptId(String deptId) {
        this.deptId = deptId;
      }
    
      public String getJoinDate() {
        return joinDate;
      }
    
      public void setJoinDate(String joinDate) {
        this.joinDate = joinDate;
      }
    
      public long getSalary() {
        return salary;
      }
    
      public void setSalary(long salary) {
        this.salary = salary;
      }
    }
    src/main/java/jpajava/EmployeeTest.java
    package jpajava;
    
    import domain.Employee;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class EmployeeTest {
      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 employee = new Employee("202401", "홍길동", null, "2024-01-01", 600);
          em.persist(employee);
          tx.commit();
        } catch (Exception e) {
          tx.rollback();
          System.out.println("TRANSACTION ROLLBACK");
          System.out.println("[Error] " + e.getMessage());
        } finally {
          System.out.println("TRANSACTION ENDED");
        }
      }
    
    }

     

    EmployeeTest.java 실행 결과

     


    EntityManager에서는 기본 생성자가 반드시 필요함

    • JPA가 엔티티 객체를 생성할 때 리플렉션을 사용하기 때문
    • EntityManager는 데이터베이스에서 데이터를 조회한 후 매핑된 엔티티 클래스를 통해 해당 데이터를 객체로 변환하는 과정을 거치는데, 이때 기본 생성자가 없으면 객체를 인스턴스화할 수 없음
    • [ 프록시 객체 생성 ] JPA 구현체(예: Hibernate)는 엔티티의 프록시 객체를 생성해 지연 로딩(Lazy Loading)을 지원함. 프록시 객체는 실제 객체 대신 사용될 수 있어야 하므로 기본 생성자가 필요함
    • [ 리플렉션 사용 ] JPA는 리플렉션을 사용해 엔티티를 생성함. 리플렉션으로 객체를 생성할 때는 기본 생성자가 필요하며, 이를 통해 매핑된 필드 값을 설정함
    • [ 내부 동작 ] JPA는 엔티티 로드 시점에 기본 생성자를 사용해 인스턴스를 생성한 후 필드에 값을 세팅함. 이 과정에서 매개변수가 있는 생성자는 사용할 수 없기 때문에 기본 생성자가 요구
    • 따라서 JPA 엔티티 클래스에는 public 또는 protected 접근자를 가진 기본 생성자가 반드시 있어야 함

     

    Employee.java 에 기본 생성자를 주석처리 하고 EmployeeFindTest.java를 실행하면 ?!

    기본 생성자가 없다는 에러가 나옴


    JPA 영속성 테스트 - 저장

     

    src/main/java/jpajava/EmployeeTest.java
    package jpajava;
    
    import domain.Employee;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class EmployeeTest {
      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("비영속 상태");
          Employee employee = new Employee("202402", "김연아", null, "2024-01-01", 600);
          em.persist(employee);
          System.out.println("영속 상태");
          em.find(Employee.class, "202402");
          System.out.println("1차 캐시에서 가져옴");
          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");
        }
      }
    
    }

     

    실행 결과

     


    JPA 영속성 테스트 - 조회

     

    src/main/java/jpajava/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());
    
        } catch (Exception e) {
          tx.rollback();
          System.out.println("TRANSACTION ROLLBACK");
          System.out.println("[Error] " + e.getMessage());
        } finally {
          System.out.println("TRANSACTION ENDED");
        }
      }
    
    }

     

    실행 결과

     


    JPA 영속성 테스트 - 삭제

    src/main/java/jpajava/EmployeeDeleteTest.java
    package jpajava;
    
    import domain.Employee;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class EmployeeDeleteTest {
      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 emp = em.find(Employee.class, "202402");
          System.out.println("employee.getEmpName() : " + emp.getEmpName());
          System.out.println("1차 캐시에서 삭제함");
          em.remove(emp);
          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");
        }
      }
    
    }

     

    실행 결과

     


    JPA 영속성 테스트 - 수정

    src/main/java/jpajava/EmployeeUpdateTest.java
    package jpajava;
    
    import domain.Employee;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class EmployeeUpdateTest {
      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("비영속 상태");
          Employee emp = new Employee("202402", "김연아", null, "2024-01-01", 600);
          em.persist(emp);
          System.out.println("영속 상태");
          emp = em.find(Employee.class, "202402");
          System.out.println("emp.getEmpName() : " + emp.getEmpName());
          System.out.println("1차 캐시에서 가져옴");
          emp.setSalary(200L);
          em.persist(emp);
          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");
        }
      }
    
    }

     

    실행 결과

     


     

    src/main/java/domain/Department.java
    package domain;
    
    import javax.persistence.*;
    
    @Entity
    @Table(name = "dept")
    public class Department {
    
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "dept_id")
      private int deptId;
    
      @Column(name = "dept_name", length = 10, nullable = false)
      private String deptName;
    
      public int getDeptId() {
        return deptId;
      }
    
      public void setDeptId(int deptId) {
        this.deptId = deptId;
      }
    
      public String getDeptName() {
        return deptName;
      }
    
      public void setDeptName(String deptName) {
        this.deptName = deptName;
      }
    }

     

    @GeneratedValue(strategy = GenerationType.IDENTITY) 전략

      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "dept_id")
      private int deptId;
    • GenerationType.IDENTITY: 주로 MySQL과 같은 데이터베이스에서 AUTO_INCREMENT를 통해 기본 키를 자동 생성하는 방식
    • 이 방식은 데이터베이스가 엔티티의 기본 키 값을 할당하기 때문에, JPA는 엔티티를 persist할 때 곧바로 INSERT SQL을 실행하여 데이터베이스에 저장하고 기본 키를 가져옴
    • 따라서 트랜잭션이 아직 commit되지 않았더라도, persist 호출 시점에 INSERT가 발생하여 기본 키 값이 생성됨
    • 1차 캐시에 쌓아 두었다가 한 번에 INSERT하는 방식이 아닌, persist 호출 시 바로 DB에 반영하는 방식

    src/main/java/jpajava/DepartmentTest.java
    package jpajava;
    
    import domain.Department;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class DepartmentTest {
      public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
    
        tx.begin();
        try {
          System.out.println("비영속 상태");
          Department dept = new Department();
          dept.setDeptName("IT");
    
          em.persist(dept);
          System.out.println("영속 상태");
    
          Department deptFound = em.find(Department.class, dept.getDeptId());
          System.out.println("deptFound.getDeptId() = " + deptFound.getDeptId() + ", deptFound.getDeptName() = " + deptFound.getDeptName());
          System.out.println("1차 캐시에서 가져옴");
    
          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 {
        }
    
      }
    }

     

    실행 결과


    src/main/java/jpajava/DepartmentFindTest.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 DepartmentFindTest {
      public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
    
        tx.begin();
        try {
          System.out.println("비영속 상태");
          System.out.println("DB에서 가져옴");
    
          Department deptFound = em.find(Department.class, 1);
          System.out.println("deptFound.getDeptId() = " + deptFound.getDeptId() + ", deptFound.getDeptName() = " + deptFound.getDeptName());
    
          System.out.println("commit 전");
          tx.commit();
          System.out.println("commit 후");
    
          System.out.println("1차 캐시에서 가져옴");
          Department deptFound2 = em.find(Department.class, 1);
          System.out.println("deptFound2.getDeptId() = " + deptFound2.getDeptId() + ", deptFound2.getDeptName() = " + deptFound2.getDeptName());
        } catch (Exception e) {
          tx.rollback();
          System.out.println("TRANSACTION ROLLBACK");
          System.out.println("[Error] " + e.getMessage());
        } finally {
        }
    
      }
    }

     

    실행 결과


    src/main/java/jpajava/DepartmentDeleteTest.java
    package jpajava;
    
    import domain.Department;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class DepartmentDeleteTest {
      public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
    
        tx.begin();
        try {
          System.out.println("비영속 상태");
          System.out.println("DB에서 가져옴");
    
          Department deptFound = em.find(Department.class, 1);
          System.out.println("deptFound.getDeptId() = " + deptFound.getDeptId() + ", deptFound.getDeptName() = " + deptFound.getDeptName());
    
          System.out.println("1차 캐시에서 삭제함");
          em.remove(deptFound);
          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 {
        }
    
      }
    }
    실행 결과


    src/main/java/jpajava/DepartmentUpdateTest.java
    package jpajava;
    
    import domain.Department;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.EntityTransaction;
    import javax.persistence.Persistence;
    
    public class DepartmentUpdateTest {
      public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpatest");
        EntityManager em = emf.createEntityManager();
        EntityTransaction tx = em.getTransaction();
    
        tx.begin();
        try {
          System.out.println("비영속 상태");
    
          Department dept = new Department();
          dept.setDeptName("HR");
          em.persist(dept);
          System.out.println("영속 상태");
    
          dept = em.find(Department.class, 2);
          System.out.println("dept.getDeptId() = " + dept.getDeptId() + ", dept.getDeptName() = " + dept.getDeptName());
    
          System.out.println("1차 캐시에서 가져옴");
          dept.setDeptName("Sales");
    
          em.persist(dept);
          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 {
        }
    
      }
    }
    실행 결과

Designed by Tistory.