JPA에 대한 개론

0ne·2024년 7월 2일

JPA

목록 보기
1/3

P. 문제점

객체 지향 프로그래밍 vs relational DB

패러다임 불일치

객체답게 모델링 할수록 매핑작업만 늘어날뿐.

상속
연관관계
데이터 타입
데이터 식별 방법

객체를 java Collection에 저장하듯이 DB에 저장할 수 없을까?

S. 이 고민에서 나온게 JPA

ORM : Object-Relational Mapping

  • 객체는 객체대로
  • RDB는 RDB대로
  • 프레임워크를 이용해 중간에서 mapping

장점

SQL중심 → 객체 중심의 개발 가능

  • 생산성
  • 유지보수

패러다임 불일치 해결

JPQL

한마디로 객체 지향 SQL

  • SQL을 추상화해서 여러 DB에 맞는 dialect사용하게끔해서 의존성 없앰
  • 테이블이 아닌 객체를 대상으로 검색하는 객체지향 query

JPA

  1. 항상 Entity Manager Factory를 만들어야 한다; 데이터베이스 하나씩 묶여서 돌아가는 것
  2. 작업을 해야하면 꼭 Entity Manager를 통해서 작업을 해야한다.
  3. JPA의 모든 작업은 transaction 안에서 일어나야 한다.
    • transaction 시작
    • 필요한 로직 실행
    • commit

핵심1. [ORM]

객체랑 RDB랑 어떻게 매핑을 해서 쓸 것인가?

핵심2. persistence context

"Entity를 영구 저장하는 환경."

내부 구현이 어떻게 되는가?

application과 database사이의 중간 매개체

Entity Manager를 통해 Persistence Context에 접근

하지만 EntityManger 도 자신의 인스턴스를 관리해줄 곳이 필요한데 그런 공간을 만들어 주는 곳이 EntityManagerFactory 이다. (Factory같은 경우는 한번 생성하는데 비용이 많이 들기 때문에 한번 생성 후 애플리케이션 전체에 공유)

EntityMangerFactory 생성 시 커넥션 풀도 만들어 준다

Entity의 4가지 상태

  1. new/transient : JPA와 전혀 관련 없는 상태
  2. managed : Persistence Context에 '관리'
  3. detached : Entity를 PersistencContext에서 '분리'
  4. removed : 객체를 삭제한 상태

특징과 이점

1. Entity 등록 : transaction단위로 등록하므로 쓰기 지연이 됨

	EntityManager em = emf.createEntityManager();
    EntityTransaction transaction = em.getTransaction();
    //EntityManager는 데이터 변경시 transaction을 시작해야 한다
    transaction.begin(); //transaction시작
    
    em.persist(memberA); //쓰기지연 SQ저장소에 INSERT 저장하고 1차 캐시에 memberA를 저장함.
    em.persist(memberB); //쓰기지연 SQ저장소에 INSERT 저장하고 1차 캐시에 memberA를 저장함.
    //여기까지 INSERT SQL을 DB에 보내지 않음
    
    transaction.commit(); //커밋하는 순간 flush()호출 : DB에 SQL저장소에 있던 쿼리를 보냄 

2. Entity 수정 : PersistencContext의 "쓰기 지연 → 변경 감지(dirty checking)"로 인해 DB 데이터의 수정을 Java의 컬렉션에 데이터를 수정하듯이 할 수 있다.

⟹ 수정 후 다시 em.persist(member)할 필요가 없다
쓰기 지연 SQL 저장소 : JPA는 transaction이 commit되는 시점에 변경을 반영함.

Member member1 = em.find(Member.class, 1L); // 조회
member1.setName("ha");

em.persist(member1) // ???

transaction.commit();

1차 캐시 내부 공간에서 만약 사용자가 em.persist를 하면 snapshot으로 해당 객체를 저장
member.setName('ha') 와 같은 코드로 setter를 호출해서 데이터를 바꿀 때 기존에 있던 스냅 샷과 바꾼 Member 객체 간 데이터를 비교해서 다르다면 Update 쿼리문을 자동으로 날려준다

3. Entity삭제

	Member memberA = em.find(member.class, "memberA");
    em.remove(memberA); //entity삭제

4. 동일성보장 : EntityManager에서 같은 객체를 불렀을 때 동일성을 보장

Member a = em.find(Member.class, "memberA"); 
member b = em.find(Member.class, "memberB");  
a == b ?? // true

*flush ≡ persistenceContext의 변경 내용을 DB에 반영하는 것

과정

flush 자동 호출 : i) transaction이 commit될 때 ii) JPQL 쿼리 실행할때 자동으로

or em.flush() (직접 호출하는 방법, 자동으로 ㄴㄴ)

ㄱ. dirty checking 변경 감지
ㄴ. 수정된 entity를 쓰기 지연 SQL 저장소에 등록
ㄷ. 쓰기 지연 SQL저장소의 쿼리를 DB에 전송

주의점

  • 1차 cache를 지우는 게 아님
  • persistence context를 지우는 것도 아님
  • transaction이라는 작업 단위. commit직전에만 동기화하면 됨
profile
@Hanyang univ(seoul). CSE

0개의 댓글