JPA intro

Growing_HJ·2024년 7월 12일

일기장

목록 보기
47/51

1. JPA

1.1 발전 흐름

JDBC (Java DataBase Connectivity)
Java Code + SQL 존재. => 유지 보수 및 확장성 문제가 있음 (SQL 이 혼자 일 다해서..)

SQL Mapper
Java Code 와 SQL 을 완전 분리.
sql 서비스별로 관리가 가능해지므로, 응집도가 높아지면서 재사용성이 높아졌음.
=> SQL 코드 품질 향상, SQL 성능 향상으로 이어짐.

MyBatis SQL 관리 파일

  • 서비를 위한 SQL (응집도 향상 목적)

1.2 ORM (객체 관계 매퍼)

  • SQL Mapper 로 SQL 을 분리해서 관리할 수 있으나, 그래도 SQL 을 사용하면서 관리해야 하는 불편함이 있음.

A. ORM의 장점

- SQL을 직접 작성하지 않고, 사용하는 개발 언어로 데이터베이스에 접근할 수 있음,
- 객체지향적으로 코드를 작성할 수 있기 때문에 비즈니스 로직에 집중할 수 있음.
- 데이터베이스 시스템이 추상화되어 있기 때문에 H2와 
다른 데이터베이스로 변경되더라도 추가로 필요한 작업이 들지 않음.
=> 데이터베이스에 대한 종속성이 감소 (ORM을 사용하는 이유)

B. ORM의 단점

- 프로젝트의 복잡성이 커질수록 사용 난이도가 올라감.
- 복잡하고 무거운 쿼리는 ORM으로 해결이 불가능 할 수도 있음
- SQL 에 직접적인 튜닝이 어려움. 

중요한 개념

A. Entity - @Entity 사용

  • 데이터베이스의 테이블과 매핑되는 객체 (자바 class)

A.1 Entity Manager (엔터티 매니저, EM)

  • 엔터티의 생명주기와 밀접한 관련성.
    => 프로젝트의 복잡성이 있는 경우 더욱 중요해짐.
    엔터티 매니저는 Entity Manager Factory(엔터티 매니저 팩토리, 스레드 기반 동작) 에서 생성됨.
    => 요청별로 엔터티 매니저가 생성됨.

A.2 엔터티 관리 상태

1. 분리 상태
2. 관리(영속) 상태 
3. 비영속 상태
4. 삭제된 상태 

A.3 영속성 컨텍스트

  • 엔터티 매니저는 엔터티를 영속성 컨텍스트에서 저장해서 관리함.
    따라서, 영속성 컨텍스트는 엔터리를 관리하는 가상의 공간임.
  • 영속성 컨텍스트에는 1차 캐쉬, 쓰기 지역, 변경감지, 지연 로딩의 특징이 있음.

1. 1차 캐쉬

  • 엔터티를 조회를 하는 경우, 1차 캐쉬에서 데이터를 조회한 후, 값이 존재할 경우 반환하고, 없으면 DB에서 조회한 후에 1차 캐쉬에 저장 후 반환한다.

2. 쓰기 지연

  • 쓰기 지연은 트랜잭션을 커밋하기 전까지는 데이터베이스에 실제로 질의문을 보내지 않고, 쿼리를 모아두었다가 트랜잭션을 커밋하면 모아두었던 쿼리를 한꺼번에 실행하는 것을 의미함.
    따라서, 적당한 묶음으로 쿼리를 요청할 수 있기 때문에 Data Base의 부하를 줄일 수 있음.

3. 변경 감지

  • 트랜잭션을 커밋하면 1차 캐쉬에 저장되어 있는 엔터티의 값과 현재 엔터티의 값을 비교한 후, 변경된 값이 있다면 변경 사항을 감지해 변경된 값을 DataBase에 자동 반영함.
    따라서, 쓰기 지연처럼 적당한 묶음으로 쿼리를 요청할 수 있고, DataBase에 대한 부하를 낮출 수 있게 됨.

4. 지연 로딩 (테이블간의 관계성이 있는 경우)

  • 지연 로딩(lazy loading)은 쿼리로 요청한 데이터를 애플리케이션에 바로 로딩하는 것이 아니라, 필요할 때 쿼리를 보내서 데이터를 조회하는 것을 의미함.
    + 반대의 경우 : 즉시 로딩
    - 즉시 로딩은 조회할 때 쿼리를 보내 연관된 모든 데이터를 가져오는 것을 의미함.

공통점

  • 모든 데이터베이스의 접근을 최소화해서 성능을 높일 수 있도록 하는 점.
    캐쉬를 하거나, 자주 쓰지 않게 하거나, 변화를 자동 감지해서 미리 준비하거나 하는 등의 방법을 이용
    결론
  • JPA 를 사용하려면, 반드시 상기의 특징을 이해하고 사용할 수 있도록 해야 함.

A.4 Entity Manager Factory

  • 엔터티 매니저 팩토리는 엔터티 매니저를 만들어 주는 기능을 담당.
  • 여러 스레드가 동시에 접근을 해도 안전하게 사용할 수 있도록 설계가 되어 있음.
  • 엔터티 매니저 팩토리는 서로 다른 스레드간에 공유를 해도 되지만, 엔터티 매니저는 여러 스레드가 동시에 접근하면 동시성 문제가 발생하게 되므로, 스레드간의 공유는 절대 금지임!

A.5 영속성 컨텍스트

- 엔터티를 영구 저장하는 환경

  • 엔터티 매니저로 엔터티를 저장하거나 조회를 하면 엔터티 매니저는 영속성 컨텍스트에서 엔터티를 보관하고 관리함.
    - Entity LifeCycle
    - 분리 상태
    - 관리(영속상태)
    - 비영속 상태
    - 삭제 상태

영속성 컨텍스트의 메모리 특징

1. 영속성 컨텍스트와 식별자

  • 영속성 컨텍스트는 엔터티를 식별자 값으로 구분함.
    따라서 영속 상태는 식별자 값이 반드시 필요하게 됨.
    식별자 값이 없으면 예외가 발생하게 됨.
  • 영속성 컨텍스트의 1차 캐쉬는 Map의 형태임
    1차 캐쉬의 형태 - @id, entity
member 를 관리하는 경우의 영속 컨텍스트의 1차 캐쉬의 모양.
             	
             	@id			entity			snapshot
   				'member1'	member1 entity	member1 entity 원본  <=> DB 
   				'member2'	member2 entity	member2 entity 원본  <=> DB
   				
   				snapshot 항목은 entity 의 update 상태 유무를 판단하기 위한 것임.
   				( 변경 감지 용 )

2. 조회

  • 우선 1차 캐쉬에서 식별자 값으로 엔터티를 찾음.
    찾는 엔터티가 1차 캐쉬에 없으면, 엔터티 매니저는 데이터베이스를 조회하여 엔터티를 생성함.
    그리고 1차 캐쉬에 저장한 후, 영속성 상태의 엔터티를 반환하게 됨.
    영속 엔터티의 동일성
Member a = em.find('member1');
             	Member b = em.find('member1');
             	
             	System.out.println( a == b ); 
             	

=> 동일성 비교시, 결과는 항상 true! 따라서 영속성 컨텍스트는 항상 동일성을 보장함.

getById() : 검색한다는 의미보다는 가져온다는 의미가 있음.
해당되는 엔터티가 없으면 예외가 발생함.
findById() : 검색한다는 의미가 있음.
실제 DB에 요청해서 엔터티를 가져옴.
영속성 컨텍스트의 1차 캐쉬에 먼저 확인 후, 엔터티가 없으면
실제 DB에 데이터가 있는지 확인함.

         		결과적으로 entity가 있거나, 없으면, null 이 발생함.

3. 등록

  • 엔터티 매니저는 트랜잭션을 커미샇기 직전까지 데이터베이스에 엔터티를 저장하지 않고, 내부 쿼리 저장소인 지연 SQL 저장소에 insert sq 을 계속 쌓아서 지정함.
    트랜잭션이 커밋을 할때 쓰기 지연 SQL 저장소에 저장된 쿼리들을 한꺼번에 데이터베이스에 전송을 함. => 쓰기 지연!

4. 수정

  • 커밋하기 전까지의 모든 SQL은 쓰기지연 SQL 저장소에 저장된 상태.
    트랜잭션을 커밋하면 엔터티 매니저 내부에서 먼저 flush() 호출됨.
    엔터티와 snapshot 을 비교하여 변경된 엔터티를 찾음.
    변경된 엔터티가 있으면 update sql을 생성하여 쓰기 지연 SQL 저장소에 저장함.

JPA의 기본 전략

모든 필드를 대상으로 Update를 수행.
이유) 애플리케이션 로딩 시점에 update sql 을 미리 생성해 두고 재사용이 가능할 수 있음.
데이터베이스에 동일한 SQL을 전송하면 데이터베이스는 이전에 한 번 파싱된 SQL을 재사용할 수 있게 됨.

5. 삭제

삭제의 경우도 바로 삭제가 되는 것이 아니라, 쓰기 지연 SQL 저장소에 SQL이 저장된 후, 트랜잭션이 커밋해서 엔터티 매니저의 flush() 가 호출되면 실제 데이터베이스에 delete sql을 전달하게 됨.

+ flush()

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영하는 기능.
변경감지가 동작해서 영속성 컨텍스트에 있는 모든 엔터티를 스냅샷과 비교해서 수정이 발생된 엔터티를 찾음. 수정된 엔터티는 update query 를 만들어서 쓰기 지연 SQL 저장소에 저장.
쓰기 지연 SQL 저장소의 쿼리가 데이터베이스에 전송(insert, update, delete)

영속성 컨텍스트틀 flush 하는 방법
>1. entity manager의 flush() 호출
2. 트랜잭션 커밋시 flush() 가 자동 호출
3. JPQL 쿼리 실행 시 자동으로 flush() 가 호출

0개의 댓글