카테고리 없음
[모각코] 6주차 결과 (12:00 ~ 15:00 zoom 사용)
ddd12347
2022. 8. 9. 15:07
JPA
Java Persistence API의 약자로 자바의 ORM을 위한 표준 인터페이스이다.
Hibernate, EclipseLink, OpenJPA등과 같은 구현체가 있다.
ORM
- 자바의 객체와 관계형 데이터베이스를 매핑하는 것으로 어플리케이션의 객체를 테이블에 자동으로 영속화 해주는 기술
- 데이터베이스의 특정 테이블이 어플리케이션의 객체로 매핑되어 SQL문을 일일히 작성하지 않고 객체로 구현할 수 있게 해주는 프레임워크
사용이유
생산성
- JPA를 사용하면 반복적인 CRUD용 SQL을 작성하지 않아도 된다.
- 영속성 컨텍스트에 객체를 전달하면 JPA가 SQL문을 생성하여 처리함
유지보수
- 필드를 하나만 추가해도 관련된 SQL문과 JDBC 코드를 전부 수정해야 하지만 JPA를 사용하면 이를 대신해주므로 (DDL 포함) 개발자가 유지보수해야하는 코드가 줄어든다.
성능
- 어플리케이션과 데이터베이스 사이에서 다양한 성능 최적화의 기회를 제공함
데이터 접근 추상화와 벤더 독립성
- 어플리케이션과 데이터베이스 사이의 추상화된 데이터 접근 계층을 제공해서 어플리케이션이 특정 데이터베이스에 종속되지 않도록 한다.
패러다임의 불일치 해결
상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 프레임워크 불일치 문제를 해결한다.
상속
- JDBC API를 이용하여 코드를 작성하면 부모 객체, 자식 객체용 SQL을 따로 작성하고 조인하여 객체를 생성해야함
- 자식객체 생성시 부모 객체를 필수적으로 생성해야함
- JPA에서는 이를 대신해주므로 개발자가 쿼리를 작성할 필요가 없어짐
연관관계
- 객체는 참조를 통해 연관관계를 가지고, 테이블은 외래키를 통해 연관관계를 가진다.
- 객체에 외래키를 저장해도 참조를 통해 조회할 수 없다.
- 따라서 외래키 대신 객체를 멤버로 보관해야 연관관계의 객체를 조회할 수 있다.
- 객체와 테이블간의 차이 때문에 개발자가 변환과정을 작성해야한다.
- JPA를 사용하여 이를 대신할 수 있다.
객체 그래프 탐색
- 객체는 객체 그래프를 탐색할 수 있어야한다. (member에서 item 조회가 가능해야한다)
- 데이터베이스에서 member와 team의 데이터만 조회했다면, member객체에서 order을 조회할 수 없다.
- JPA에서는 연관된 객체를 사용하는 시점에 적절한 SELECT SQL문을 실행한다. 이 기능은 실제 객체를 사용할 때까지 조회를 미룬다. (lazy loading)
비교
- 데이터베이스는 primary key의 값으로 값을 비교한다.(동일성 비교) 객체는 인스턴스 주소값으로 비교한다(동등성 비교, equals() 메소드)
- 이런 차이를 해결하기 위해 같은 로우를 조회할 때마다 같은 인스턴스를 반환하도록 구현하는 것은 쉽지 않다.
- JPA는 같은 트랜잭션일 때 같은 객체가 조회되는 것을 보장한다.
영속성 컨텍스트
엔티티를 영구 저장하는 환경이라는 뜻으로 JPA를 이용하는데 가장 중요한 요소이다.
엔티티 생명주기
- 비영속 : 영속성 컨텍스트와 관계가 없는 상태
- 영속 : 영속성 컨텍스트에 저장된 상태
- 준영속 : 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제 : 삭제된 상태
EntityManagerFactory
- Entity를 관리하는 EntityManager를 생산하는 공장
- Thread Safe 하다
EntityManager
- EntityManager는 Entity를 저장하고, 수정하고, 삭제하고, 조회하는 (CRUD) 엔티티와 관련된 모든 일을 처리한다.
- Thread safe하지 않다. 여러 Thread에서 동시에 접근할 경우 동시성 이슈가 발생할 수 있다.
- 내부적으로 DB Connection을 사용하여 DB를 사용한다. (트랜잭션을 시작할 때 커넥션을 얻는다.)
- 특징
- 영속성 컨텍스트와 식별자 값
- 영속성 컨텍스트 안에서 관리되는 엔티티는 식별자 값을 반드시 가져야한다.
- key-value로 엔티티를 관리하기 때문이다.
- 영속성 컨텍스트와 데이터베이스 저장
- JPA는 트랜잭션을 커밋하는 순간 영속성 컨텍스트에 새로 저장된 엔티티를 DB에 반영한다. (Flush)
- 플러시는 영속성 컨텍스트의 변경 내용을 DB에 동기화하는 작업으로 이 때 등록, 수정, 삭제한 엔티티를 DB에 반영한다.
- 영속성 컨텍스트와 식별자 값
- 1차 캐시
- 영속성 컨텍스트 내부에 존재하는 캐시
- 엔티티를 영속성 컨텍스트에 저장하면 1차 캐시에 저장된다.
- Key : id 필드, value : 엔티티로 캐시에 저장된다.
- 조회시 1차 캐시에 값이 있는지 확인한 후 있으면 반환, 없다면 DB에 값을 요청하고 DB에서 받은 값을 1차 캐시에 저장한 후 반환함
- 1차 캐시는 글로벌하지 않다. (스레드 하나당 하나씩, 글로벌 캐시는 2차 캐시)
- 동일성 보장
- 영속 엔티티의 동일성을 보장한다. (같은 레퍼런스)
- 트랜잭션을 지원하는 쓰기 지연
- 쓰기 지연 저장소에 쿼리를 생성하여 넣어두고 commit()하는 시점에 DB에 쿼리를 보낸다. → flush()
- 변경 감지
- 엔티티 수정이 일어나면 영속성 컨텍스트 내부의 엔티티 값을 수정한다.
- flush() 또는 commit()이 일어날 때 엔티티와 엔티티의 스냅샷을 비교하여, 변경사항이 있다면 update 쿼리를 생성하여 DB에 보낸다.
- 플러시
- 영속성 컨텍스트의 변경 내용을 DB에 반영
- Transaction commit이 일어날 때 flush가 동작함
- 영속성 컨텍스트를 비우지 않는다.
- 영속성 컨텍스트의 변경된 내용을 DB에 업데이트함
- 동작 과정
- 변경 감지 → 수정된 내용을 쓰기 지연 저장소에 등록 → 쓰기 지연 저장소의 쿼리 전송