Java Persistence API
의 약자로, Spring
진영에서 대표적으로 사용되는 ORM
스펙이다. 객체와 관계형 DB
간의 상호작용을 표준화 하는 역할을 한다.
ORM :
Object-Relational Mapping
의 약자로,back-end
환경에서 영속성을 보장하기 위해, 객체와관계형 DB
의 불일치를 해결하여, 둘의 상호작용을 지원하는 기술을 의미한다. 참고로 객체와의 불일치를 해결하고 상호작용을 도와주는 기술은ORM
만 있는 것이 아니다.MongoDB
와 같이문서 DB
와 상호작용을 지원하는 경우는ODM
이라 하며, 객체와XML
과의 상호작용을 도와주는 기술은OXM
이라고 한다.
ORM의 자세한 정의는 이전에 작성한 내용이 있으니 이를 참고하자.
[Spring] Persistence - 서버에서 데이터를 DB에 옮기기까지
JPA
의 경우는, 객체와 관계형 DB
간의 상호작용하기 위한 기술들을 명세한 인터페이스이며, JPA 구현체
는 JPA
의 명세를 바탕으로 실질적인 구현이 이루어진 코드를 의미한다. 즉 JPA
는 하나의 기술 표준
혹은 스펙
이라 분류할 수 있고, JPA 구현체
는 하나의 프레임워크, 라이브러리
로 분류할 수 있다.
대표적인 JPA 구현체
로는 Hibernate
와 EclipseLink
등이 있다.
JPA Entity
는 객체와 관계형 DB
의 상호작용을 위한 대표적인 수단으로, 실제로 DB
테이블에 대응하는 클래스를 일컫는다. 영속성 컨텍스트에 의해 관리가 이루어지며, 필요에 따라 데이터베이스 테이블에 맞게 변환하여 DB
에 저장되거나, 반대로 DB
쿼리 결과를 JPA Entity
인스턴스의 형태로 불러오기도 한다.
JPA Entity
의 영속성을 제어하며, 데이터베이스와의 통신을 담당하는 JPA
의 핵심 기능이다.
JPA Entity
는 Entity Manager
를 통해 영속성 컨텍스트에서 등록 및 관리가 이루어지며 되며, 트랜잭션 종료 시 JPA Entity
의 변경사항을 그대로 DB
에 반영하게 된다.
JPA Entity
의 생명주기를 관리하는 기술로서, Entity
의 변경사항을 추적하여 이에 따른 결과를 관계형 DB
에 반영시키는 상호작용 역할을 한다.
Dirty checking
영속성 컨텍스트는 Entity
등록 시 초기 스냅샷을 생성하여, 비교를 통해 향후 Entity
의 변경사항 및 상태를 추적하는 것이 가능하다. 최종적인 Entity
상태에 따라 관계형 DB
와의 상호작용이 달라지는 것이다.
예를들어 DB
데이터와 연관되지 않은 새로운 Entity
가 들어온 것이라면 데이티 생성을, DB
에 이미 존재하는 데이터를 가져온 것이라면 데이터 수정을,이미 존재하는 데이터를 영속성 컨텍스트에서 삭제하는 것이라면 데이터 삭제를 반영시키는 것이다.
영속성 컨텍스트는 Entity
등록 시 이를 캐싱하여, 동일한 Entity
를 찾는 경우, DB
와 통신 없이 영속성 컨텍스트에 캐싱된 Entity
를 제공하는 기능을 가지고 있다. 단, 영속성 컨텍스트는 매 트랜잭션마다 새롭게 생성되기 때문에, 1차 캐싱을 통한 성능 향상은 그리 크지 않은 편이다.
트랜잭션 마다 영속성 컨텍스트가 새롭게 생성되는 것은 다수의 트랜잭션 발생 시 데이터베이스의 일관성을 보장하기 위해서이다. 다수의 트랜잭션이 하나의 영속성 컨텍스트에서 관리가 이루어진다면 트랜잭션 끼리 서로 영향을 미쳐 데이터베이스가 변질될 수 있는 위험이 있다.
영속성 컨텍스트는 JPA Entity
의 연관관계 설정에 따라, 즉시로딩 혹은 지연로딩을 실행할 수 있다. 지연로딩은 실질적으로 연관관계의 Entity
가 호출되는 경우에만 조회가 이루어지기 때문에 불필요한 통신을 줄여 서버 성능을 높일 수 있다.
비영속 (new/transient) : 영속성 컨텍스트와 전혀 관계가 없는 상태를 의미한다. 단순히 JPA Entity
인스턴스를 생성만 한 상태이다.
영속(managed) : 영속성 컨텍스트에 JPA Entity
가 등록되어 관리되는 상태를 의미한다. EntityManger.persist()
를 통해 JPA Entity
를 엔티티 매니저 내부의 영속성 컨텍스트에 등록할 수 있다. 트랜잭션 커밋 시 데이터베이스에 동기화가 이루어질 수 있으며, 반대로 데이터베이스 쿼리 결과를 JPA Entity
인스턴스로 생성하는 것이 가능한 상태이다.
준영속 (detached) : 영속성 컨텍스트에 있던 JPA Entity
를 분리한 상태를 의미한다. 이는 더이상 영속성 컨텍스트에서 해당 Entity
를 관리하지 않음을 의미한다.
삭제 (removed) : 영속성 컨텍스트에서 해당 JPA Entity
를 삭제한 상태를 의미한다. 삭제한 Entity
는 비영속 상태가 된다.
준영속과 삭제는 모두 영속성 컨텍스트 내부의
Entity
를 지우는 역할을 하지만, 각 메서드 호출 시 데이터베이스의 반영 결과가 다르다. 준영속은 해당Entity
에 대해 데이터베이스에 반영되는 것이 없으며, 삭제는 해당Entity
와 연관된 데이터를 삭제시킨다.
JPA
의 CRUD
메서드는 메소드 호출 시 바로 쿼리를 실행하지 않는다. 영속성 컨텍스트를 통해 쓰기 지연 SQL 저장소
에서 대기하게 되며, 실제 트랜잭션의 변경사항을 반영할 때, 쓰기 지연 SQL 저장소
에 쌓인 작업이 한번에 이루어진다.
바로 쿼리를 실행하지 않는 이유는, 배치작업을 통해 다수의 쿼리를 한번에 보내는 것이 통신에 효율적이기 때문이다. 더불어, 트랜잭션의 원자성 처리가 간편해진다. 트랜잭션이 실패하거나, 롤백이 이루어지는 경우 현재
DB
에 반영이 되지 않은 상태이기 때문에DB
와 통신 없이 자체적으로 쉽게 취소가 가능하다.
commit()
과 flush()
모두 트랜잭션의 변경사항을 반영시키는 메서드이지만 분명한 차이도 존재한다. commit()
은 현재 트랜잭션의 변경사항을 반영시키고 트랜잭션을 종료시키며, flush()
는 현재 까지의 변경사항을 반영하되 트랜잭션을 종료시키지는 않는다. 즉 flush()
의 경우는 전송된 결과를 rollback()
을 통해 반영결과를 취소하는 것도 가능하다.
실제
commit()
호출은 내부에서flush()
호출을 통해DB
에 변경 결과를 반영시킨 후, 트랜잭션을 종료한다. 즉flush()
는 변경사항을 반영하는 기능을 담당하며,commit()
은 트랜잭션을 종료하는 기능을 담당한다고 볼 수 있다. 참고로JPQL
을 사용하는 쿼리 실행도 내부적으로flush()
를 호출된다.
참고
Spring OXM를 이용한 JAXB HttpClient 연동 Example(샘플)
Spring Boot 에서 Redis 사용하기
[JPA] Entity(엔티티)와 EntityManger(엔티티 매니저)
[JPA] 엔티티(entity) 개념
[DB] ORM이란 - Heee's Development Blog
쓰기 지연 저장소
[JPA] commit, flush, Entity Manager의 clear()와 close()에서 궁금한 부분들 탐구 + 데이터 삭제 및 수정 시 1차 캐시에서 발생하는 현상 + 준영속과 비영속의 차이점