24.08.19

윤지현·2024년 8월 19일

TIL

목록 보기
44/75

오늘의 루틴

  • Spring 강의 최소 4개는 듣기 (O)
  • 주말에 공부한 내용 다시 보기 (O)

JPA란 무엇일까?


🔻 DB를 직접 다룰 때의 문제점

  • SQL => 의존적
  • 데이터가 추가되면 SQL을 수정해야 함
  • 3 Layer Architecture, dto에도 추가해야 함

🔻 ORM이란?

  • 객체와 데이터베이스를 매핑해주는 기술
  • 데이터가 추가되면 직접 수정해야 하는 번거로운 작업들을 '자동'으로 처리

🔻 JPA이란?

  • ORM 기술 중에서 표준적인 기술
    - JPA를 사용하면 DB 연결 과정을 직접 개발하지 않아도 자동으로 처리
    - 객체를 통해 간접적으로 DB 데이터 접근 => 쉽게 DB 자동으로 처리

Entity 이해하기


🔻 Entity란?

  • JPA에서 관리되는 클래스 즉, 객체
  • DB의 테이블과 매핑되어 JPA에 의해 관리

🔻 Entity 클래스 만들기

@Entity // JPA가 관리할 수 있는 Entity 클래스 지정
@Table(name = "memo") // 매핑할 테이블의 이름을 지정
public class Memo {
    @Id
    private Long id;

    // nullable: null 허용 여부
    // unique: 중복 허용 여부 (false 일때 중복 허용)
    @Column(name = "username", nullable = false, unique = true)
    private String username;

    // length: 컬럼 길이 지정
    @Column(name = "contents", nullable = false, length = 500)
    private String contents;
}

영속성 컨텍스트란 무엇일까?


🔻 영속성 컨텍스트란?

  • Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간입니다.
  • JPA는 영속성 컨텍스트에 Entity 객체들을 저장하여 관리하면서 DB와 소통 -> 효율적으로 처리!

🔻 EntityManager

  • 영속성 컨텍스트에 접근하여 Entity 객체들을 조작하기 위해 필요
  • Entity를 저장하고 조회하고 수정하고 삭제
  • EntityManagerFactory 통해 생성

🔻 EntityManagerFactory

  • 일반적으로 DB 하나에 하나만 생성되어 애플리케이션이 동작하는 동안 사용
  • 이를 만들기 위해서는 DB에 대한 정보를 전달해야함
  • EntityFactory를 통해 생성
EntityManagerFactory emf = Persistence.createEntityManagerFactory("memo");
EntityManager em = emf.createEntityManager();


🔻 EntityManager

  • 영속성 컨텍스트에 접근하여 Entity 객체들을 조작하기 위해 필요
  • Entity를 저장하고 조회하고 수정하고 삭제
  • EntityManagerFactory 통해 생성

🔻 JPA의 트랜잭션

  • 변경이 발생한 객체들의 정보를 쓰기 지연 저장소에 전부 가지고 있다가 마지막에 SQL을 한번에 DB에 요청해 변경을 반영
@Test
@DisplayName("EntityTransaction 성공 테스트")
void test1() {
    EntityTransaction et = em.getTransaction(); // EntityManager 에서 EntityTransaction 을 가져옵니다.

    et.begin(); // 트랜잭션을 시작합니다.

    try { // DB 작업을 수행합니다.

        Memo memo = new Memo(); // 저장할 Entity 객체를 생성합니다.
        memo.setId(1L); // 식별자 값을 넣어줍니다.
        memo.setUsername("Robbie");
        memo.setContents("영속성 컨텍스트와 트랜잭션 이해하기");

        em.persist(memo); // EntityManager 사용하여 memo 객체를 영속성 컨텍스트에 저장합니다.

        et.commit(); // 오류가 발생하지 않고 정상적으로 수행되었다면 commit 을 호출합니다.
        // commit 이 호출되면서 DB 에 수행한 DB 작업들이 반영됩니다.
    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback(); // DB 작업 중 오류 발생 시 rollback 을 호출합니다.
    } finally {
        em.close(); // 사용한 EntityManager 를 종료합니다.
    }

    emf.close(); // 사용한 EntityManagerFactory 를 종료합니다.
}

영속성 컨텍스트의 기능

  • 영속성 컨테스트 : Entity 객체를 효율적으로 쉽게 관리하기 위해 만들어진 공간

🔻 1차 캐시

  • 영속성 컨텍스트는 내부적으로 캐시 저장소를 가짐
  • Map 자료구조 형태로

1. Entity 저장

em.persist(memo) : 메서드가 호출되면 memo Entity 객체를 캐시 저장소에 저장

2. Entity 조회

- 캐시 저장소에 조회하는 ID가 존재할 때

em.find(Memo.class, 1); 호출 시 캐시 저장소에 식별자 값이 1이면서 Memo Entity 타입인 값이 있는지 조회

- 캐시 저장소에 조회하는 Id가 존재하지 않은 경우

DB에 SELECT 조회 후 해당 값을 캐시 저장소에 저장하고 반환

3. Entity 삭제

em.remove(memo); 호출 시 삭제할 Entity를 DELETED 상태로 만든 후 트랜잭션 commit 후 Delete SQL이 DB에 요청


🔻 쓰기 지연 저장소(ActionQueue)

  • JPA가 트랜잭션 처럼 SQL을 모아서 한번에 DB에 반영
  • 쓰기 지연 저장소를 만들어 SQL을 모아두고 있다가 트랜잭션 commit 후 한번에 DB에 반영
  • EntityManagerFactory 통해 생성
@Test
@DisplayName("쓰기 지연 저장소 확인")
void test6() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        Memo memo = new Memo();
        memo.setId(2L);
        memo.setUsername("Robbert");
        memo.setContents("쓰기 지연 저장소");
        em.persist(memo);

        Memo memo2 = new Memo();
        memo2.setId(3L);
        memo2.setUsername("Bob");
        memo2.setContents("과연 저장을 잘 하고 있을까?");
        em.persist(memo2);

        System.out.println("트랜잭션 commit 전");
        et.commit();
        System.out.println("트랜잭션 commit 후");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}
  • flush()
    • 쓰기 지연 저장소의 SQL들을 바로 DB에 요청하는 역할을 수행
@Test
@DisplayName("flush() 메서드 확인")
void test7() {
    EntityTransaction et = em.getTransaction();

    et.begin();

    try {
        Memo memo = new Memo();
        memo.setId(4L);
        memo.setUsername("Flush");
        memo.setContents("Flush() 메서드 호출");
        em.persist(memo);

        System.out.println("flush() 전");
        em.flush(); // flush() 직접 호출
        System.out.println("flush() 후\n");
        

        System.out.println("트랜잭션 commit 전");
        et.commit();
        System.out.println("트랜잭션 commit 후");

    } catch (Exception ex) {
        ex.printStackTrace();
        et.rollback();
    } finally {
        em.close();
    }

    emf.close();
}


profile
첫 시작

0개의 댓글