JPA란 무엇인가?

0taetae·2025년 1월 7일
post-thumbnail

JPA는 ORM 기술의 표준 사양을 정의한 것이다.

이때, ORM(Object-Relational Mapping) 이란❓
자바 객체와 관계형 DB 간의 매핑 처리를 위한 API이다.

💡JPA 특징

  1. 어노테이션을 이용한 매핑을 설정한다.
    • XML 파일을 이용한 매핑 설정도 가능하다.
  2. Spring, int, LocalDate 등 기본적인 타입에 대한 매핑 지원한다.
  3. 커스텀 타입 변환기 지원한다.
    • 사용자 정의 타입을 DB 칼럼에 매핑할 수 있다.
  4. 밸류 타입 매핑을 지원한다.
    • 한 개 이상 칼럼을 한 개 타입으로 매핑할 수 있다.
  5. 클래스 간 연관관계를 지원한다.
    • 1-1, 1-N, N-1, N-M
  6. 상속에 대한 매핑 지원한다.
    • 객체 지향 프로그래밍의 상속 개념을 DB 매핑에 적용할 수 있다.

💡JPA를 사용하는 이유는?(JPA의 장점)

  1. SQL을 개발자가 직접 작성하지 않아도 된다.
  2. SQL과 JDBC API 코드를 JPA가 대신 처리하므로 유지보수해야 하는 코드 수가 감소한다.
  3. 패러다임의 불일치 문제를 해결해준다.
  4. JPA는 애플리케이션과 데이터베이스 사이에서 동작하는데, 이로 인해 성능 최적화에 효율적이다.
  5. 애플리케이션과 데이터베이스 사이에 추상화된 데이터 접근 계층을 제공해서 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 한다.

💡JPA 설정

  1. pom.xml
    • hibernate는 JPA의 구현체로 사용된다.
  2. persistence.xml
    • JPA가 관리한 영속성에 대한 정보를 담고 있다.
      • 매핑 클래스 정보
      • DB 연결 정보
      • 구현체에 특화된 설정에 대한 정보
    • name = "jpabegin" : 영속성 관리 단위, 일종의 식별자
    • < class > : 해당 클래스들을 이용하여 DB와 매핑을 처리하기 위한 태그이다. 매핑 대상 클래스를 추가할때마다 추가한다.
      ✔️ spring과 연동할 시에는 작성하지 않는다.

💡클래스와 테이블 매핑

@Entity  // DB 테이블과 매핑 대상
@Table(name = "user")  // user 테이블과 매핑 
public class User {
   @Id  // 식별자에 대응, 주로 PK와 매핑하는 칼럼, 필드명과 동일한 테이블 칼럼과 매핑
   private String email;
   private String name;
   @Column(name = "create_date")  // 필드명과 칼럼명이 다른 경우 @Column 사용 
   private LocalDateTime createDate;
  • @Entity : DB 테이블과 매핑 대상
  • @Table(name = "테이블명") : 해당 테이블과 매핑한다.
  • @Id : 식별자에 대응, 주로 PK와 매핑하는 칼럼, 필드명과 동일한 테이블 칼럼과 매핑
  • @Column(name = "칼럼명") : 필드명과 칼럼명이 다른 경우 사용

📙엔티티 매니저 팩토리와 엔티티 매니저

💡엔티티 매니저 팩토리

  • 영속성 단위를 기준으로 생성한다.
  • DB 연동을 위해 필요한 자원을 생성한다.
  • 애플리케이션 시작 시 한 번만 생성한다.
  • 종료 시 반드시 닫아야 함 -> 사용한 자원 반환
  • 여러 스레드가 동시에 접근해도 안전하므로, 서로 다른 스레드 간에 공유해도 된다.

💡엔티티 매니저

  • 여러 스레드가 동시에 접근하면 동시성 문제가 발생하므로 스레드 간에 공유하면 안된다.
  • 엔티티 매니저로 DB 연동한다.
  • 엔티티 매니저는 DB 연결이 필요한 시점까지 커넥션을 얻지 않는다.
transaction.begin();
User user = new User("user@user.com", "user", LocalDateTime.now());
entityManager.persist(user);
transaction.commit(); // 

💡쿼리 실행 시점

  • commit 시점에 select/insert/update 쿼리가 실행된다.

📙애플리케이션 개발

💡엔티티 매니저 설정

  • EntityManagerFactory 생성
    • 애플리케이션 전체에서 한 번만 생성하고 공유해서 사용해야 한다.
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabegin");
  • EntityManager 생성
    • EntityManager를 사용해서 entity를 DB에 등록/수정/삭제/조회할 수 있다.
    • DB 커넥션과의 관계로 인해, 스레드 간 공유나 재사용은 안된다.
      EntityManager em = emf.createEntityManager();

💡트랜잭션 관리

EntityTransaction transaction = entityManager.getTransaction();  // 트랜잭션 생성
try{
   transaction.begin();  // 트랜잭션 시작 
   User user = new User(...);
   entityManager.persist(user);  
   transaction.commit();  // 트랜잭션 커밋 
} catch (Exception ex) {
   ex.printStackTrace();
   transaction.rollback();  // 예외 발생 시 트랜잭션 롤백 
}

💡비즈니스 로직

  • 등록, 수정, 삭제, 조회 작업이 Entity Manager를 통해서 수행되는 것을 알 수 있다.
  1. 등록
    String id = "myid";
    Member member = new Member();
    member.setId(id);
  2. 수정
    member.setAge(20);
  3. 삭제
    em.remove(member);
  4. 조회
    Member member = em.find(entity 클래스 타입, PK 값)

📙예제로 알아보기

💡JPA를 사용하여 DB에 객체 저장하기

  • 트랜잭션 내에서 persist() 메소드를 사용하여 객체를 저장한다.
import jakarta.persistence.*;
import jpabasic.reserve.domain.User;

import java.time.LocalDateTime;

public class UserSaveMain {
   public static void main(String[] args) {
      EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabegin");
      EntityManager entityManager = emf.createEntityManager();
      EntityTransaction transaction = entityManager.getTransaction();  // 트랜잭션 생성
      try{
         transaction.begin();  // 트랜잭션 시작 
         User user = new User("user@user.com", "user", LocalDateTime.now());
         entityManager.persist(user);  // persist 호출시 entity로 매핑한 객체를 db에 저장
         transaction.commit();
      } catch (Exception ex) {
         ex.printStackTrace();
         transaction.rollback();
       } finally {
          entityManager.close();  // entityManager 닫기 -> 사용한 리소스 반환 
       }
       emf.close();  // entityManagerFactory를 닫기 -> 사용한 리소스 반환 
    }
 }

💡DB에서 데이터를 읽어와서 객체로 매핑해서 읽어오기

  • find() 메소드를 사용하여 데이터베이스에서 객체를 조회한다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabegin");
EntityManager entityManager = emf.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try{
   transaction.begin();
   User user = entityManager.find(User.class, "user@user.com");  // find(매핑 클래스 타입 지정, PK(app id로 매핑된 칼럼 값) 전달)
   if (user == null) {
      System.out.println("User 없음");
   } else{
      System.out.pringf("User 있음: email=%s, createDate=%s\n", user.getEmail(), user.getName(), user.getCreateDate());
   }
   transaction.commit();
} catch (Exception ex) {
   ex.printStackTrace();
   transaciton.rollback();
} finally {
   entityManager.close();
}
emf.close();

💡데이터 수정하기

  • 조회한 객체의 필드를 변경하면 트랜잭션 커밋 시 자동으로 데이터베이스에 반영된다.
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpabegin");
EntityManager entityManager = emf.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try{
   transaction.begin();
   User user = entityManager.find(User.class, "user@user.com");  // find 메서드를 사용하여 바꿀 대상을 조회 
   if (user == null) {
      System.out.println("User 없음");
   } else{
      String newName = "이름" + (System.currentTimeMillis() % 100);
      user.changeName(newName);  // 조회한 객체의 필드를 변경 
   }
   transaction.commit();
} catch (Exception ex) {
   ex.printStackTrace();
   transaciton.rollback();
} finally {
   entityManager.close();
}
emf.close();

✔️ 업데이트를 위한 별도의 EntityManager를 호출할 필요가 없고 트랜잭션 범위 내에서 조회한 객체의 형태만 변경하면 된다.

📙정리

  • JPA 개념

    • 간단한 설정으로 클래스와 테이블 간 매핑 처리한다.
    • EntityManager를 이용해서 DB 연동 처리한다.
    • 객체 변경만으로 DB 테이블을 업데이트한다.
    • 쿼리를 작성 하지 않는다.
  • 기본 구조

    • 앤티티 매니저 팩토리 초기화
    • DB 작업이 필요할때마다
      • 앤티티 매니저 생성
      • 앤티티 매니저로 DB 조작
      • 앤티티 트랜잭션으로 트랜잭션 관리
    • 스프링과 연동 시, 대부분 스프링이 대신 처리하므로 매핑 설정 중심으로 작업

0개의 댓글