JPA란?
- JPA(Java Persistence API)는 기존의 반복적인 코드는 물론이고, 기본적인 SQL문도 JPA가 직접 만들어서 실행해준다.
- JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체중심의 설계로 전환가능하다.
- JPA를 사용하면, 개발 생산성을 크게 높일 수 있다.
- JPA는 자바에서 ORM (Object - Relational Mapping) 기술 표준으로 사용되는 인터페이스 모음이다. 즉, 실제적으로 구현된 것이 아니라, 구현된 클래스와 매핑을 해주기 위해 사용되는 프레임워크이다.
(JPA를 구현하는 대표적 오픈소스로는 Hibernate가 있다.)
ORM (Object-Relational Mapping 객체 관계 매핑)

- 객체는 객체대로 설계하고, RDB는 RDB대로 설계를 하도록 ORM 프레임워크가 중간에서 매핑한다.
- 애플리케이션 클래스와 RDB(Relational DB)의 테이블을 매핑(연결)한다는 의미
- 기술적으로는 어플리케이션 객체를 RDB테이블에 자동으로 영속화해주는 것이라고 보면 된다.
1. JPA의 장점
- SQL문이 아닌 Method를 통해서 DB를 조작할 수 있어, 개발자는 객체모델을 이용하여
비지니스 로직을 구성하는 데만 집중할 수 있다.
(내부적으로 쿼리를 생성하여 DB를 조작하지만, 개발자가 이를 신경쓰지 않아도 된다.)
- 쿼리와 같이 필요한 선언문, 할당 등의 부수적인 코드가 줄어들어 각종 객체에 대한 코드를 별도로 작성하여 코드의 가독성을 높인다.
- 객체지향적인 코드 작성이 가능하기 때문에, 오직 객체지향적 접근만 고려하면 된다.
- 매핑하는 정보가 class로 명시되었기 때문에, ERD를 보는 의존도를 낮출 수 있고, 유지보수 및 리팩토링에 유리하다.
2. JPA의 단점
- 프로젝트의 규모가 크고 복잡하여 (erd)설계가 잘못된 경우, 속도 저하 및 일관성을 무너뜨리는 문제점이 생길 수 있다.
- 복잡하고 용량이 큰 쿼리는 속도를 위해 별도의 튜닝이 필요하기 때문에, SQL문을 사용해야 할 수도 있다.
- 학습 난이도가 높다.
3. 데이터베이스 방언

- JPA는 특정 데이터베이스에 종속되지 않고, 각각의 데이터베이스가 제공하는 SQL문법과 함수는 조금씩 다르다.
- 따라서, 데이터베이스 방언은 SQL표준을 지키지 않는 특정 데이터베이스의 고유한 기능이다.
4. JPA의 기능
- 객체와 테이블을 생성하고 매핑
- @Entity : "JPA가 관리할 객체" 선언
- @Id : "데이터베이스의 PK와 매핑" 선언
5. JPA 설정하기
application.properties에서 hibernate.hbm2ddl.auto의 값을 설정하여 데이터베이스의 값을 초기화 설정할 수 있다.
- none : 아무것도 실행하지 않음
- create : sql문아 시작될 때, 기존테이블을 삭제후(drop), 다시 생성(create)한다.
- create-drop : create의 기능과 같으나, 종료될 때 drop을 실행한다.
- update : 변경된 스키마만 반영한다.
- validate : 엔티티와 테이블이 정상적으로 매핑(Sync)되었는지만 확인한다.
6. 엔티티 매니저
- 엔티티 매니저 팩토리는 하나만 생성해서, 애플리케이션 전체에서 공유한다.
- JPA의 모든 데이터 변경은 트랜잭션 안에서 실행된다.
JPQL
- JPA를 사용하면 엔티티 객체를 중심으로 개발할 수 있는데, 문제는 "검색 쿼리"가 어려운 부분이기 때문에, 검색(select)을 할 때도 테이블이 아닌 엔티티 객체를 대상으로 검색한다.
- 모든 DB데이터를 객체로 변환하는 건 불가능하고, 애플리케이션이 필요한 데이터만 DB에서 불러오려면 결국 검색 조건이 포함된 SQL이 필요하다.
- JPA는 SQL을 추상화한 JPQL이라는 객체 지향 쿼리 언어를 제공한다.
SQL과 유사한 문법, select, from, where, group by, having, join ...을 지원한다.
영속성 컨텍스트

엔티티 매니저 팩토리는
생성해서, 애플리케이션 전체에서 공유하고, 쿼리를 만들때 마다 엔티티 매니저를 생성한다.
따라서, "엔티티를 영구 저장하는" 영속성 컨텍스트는 JPA를 이해하는 데 가장 중요한 용어이다.
- 엔티티매니저에서 entity에
persist한다는 것은
- "entity에 들어가는 객체를 DB에 저장하는구나" 싶지만, 처음부터 DB에 저장하는 게 아니라 "영속성 컨텍스트"라는 곳에 저장한다.는 것이다.
- 따라서, 영속성 컨텍스트는 (눈에 보이지 않는) 논리적인 개념이고, "엔티티 매니저"를 통해 영속성 컨텍스트에 접근한다.
- 엔티티 매니저를 생성하면, 영속성 컨텍스트가 생성이 된다.
엔티티의 생명주기

- 비영속 상태 (new) : 영속성 컨텍스트와 전혀 관계가 없는 새로운 상태
- JPA와 전혀 상관없고, 오로지, 객체를 생성한 상태이다. (멤버변수에 값을 할당만 한다.)
- 영속 상태 (managed) : 영속성 컨텍스트에 관리되는 상태
- JPA에 속해 있는 상태이다. (엔티티매니저 객체에서 Member 객체
persist 저장 처리하였다.)
em.persist(member);
- 준영속 상태 (detached) : 엔티티가 영속성 컨텍스트에 저장되었다가 분리된 상태
- 삭제 상태 (removed) : 객체 삭제를 요청한 상태
영속성 컨텍스트의 이점
1차 캐시에 저장된다는 것, 동일성 (identity) 보장한다는 것, 트랜잭션을 지원하는 쓰기 지연
(transactional Write-Behind)이 가능하다는 것, 변경감지 (Dirty Checking)하고 지연로딩 (Lazy Loading)이 가능하다는 것이 사용했을 때의 이점이다.
1. 엔티티 조회할 때, "1차 캐시"에 저장된다는 것
- 영속성 컨텍스트는 엔티티를 조회(select)할 때, 식별자 값이 필요한데, 영속상태에서 그 값이 반드시 있어야 한다.(없으면 예외가 발생한다)
- JPA는 트랜잭션을 커밋하는 순간 영속 컨텍스트에 새로 저장된 엔티티를 DB에 반영(flush)을 하는데,
- 만약, 영속 컨텍스트가 없다면, 트랜잭션이 이뤄질때마다 DB에 CRUD를 해야하는 속도 이슈가 발생하게 되는데 영속 컨텍스트가 있으므로 1차 캐시에 저장되어 그러한 이슈를 줄여준다.
2. 쓰기지연
엔티티매니저를 통해 생성된 sql쿼리가 "영속상태"가 되면 변경된 엔티티는 1차 캐시에 저장이 되고, 변경된 sql쿼리 또한 쓰기 지연 SQL저장소에 담기는데, 이 또한 바로 DB에 저장되는 것보다는 영속 컨텍스트에 저장이 된 상태에서 커밋을 해서 한꺼번에 DB에 반영하는 것이 속도 이슈 측면에서 유리하다.
3. 엔티티 수정 변경감지
flush()가 호출되는 시점에 Entity와 스냅샷을 전부 비교후, 변경이 된 것을 감시(Dirty Checking)한 후에 update쿼리를 DB에 반영한다.

🎁 flush() 의 역할
1. 영속성 컨텍스트의 변경내용을 DB에 반영
2. 변경감지
3. 수정된 엔티티 쓰기 지연 SQL저장소에 등록
4. 쓰기 지연 SQL저장소의 쿼리를 데이터베이스에 등록, 수정, 삭제하는 쿼리등을 전송
🎁 영속성 컨텍스트를 플러쉬하는 방법
- 직접호출 :
em.flush();
- 플러쉬 자동 호출 :
트랜잭션 커밋, JPQL 쿼리 실행
🎁 플러쉬는
영속성 컨텍스트를 비우지 않고,
영속성 컨텍스트의 변경내용을 데이터베이스에 동기화하고,
트랜잭션이라는 작업단위가 중요한데, 커밋 직전에만 동기화하면 된다.
준영속 상태
영속상태에서 준영속상태로 변경하고 할 때,
영속상태 엔티티가 영속성 컨텍스트에서 분리한다.
(영속성 컨텍스트가 제공하는 기능을 사용하지 못함)
준영속상태로 만드는 방법
- 특정 엔티티만 준영속상태로 전환 :
em.detach(entity)
- 영속성 컨텍스트를 완전히 초기화 :
em.clear()
- 영속성 컨텍스트를 종료 :
em.close()