JPA(Java Persistence API) 란
자바 애플리케이션에서 관계형 데이터베이스를 관리하고 상호작용하기 위한 자바 표준 API이다. JPA는 자바 객체와 데이터베이스 간의 매핑을 자동화하여, 개발자가 SQL 쿼리를 직접 작성하지 않고도 데이터베이스 작업을 수행할 수 있게 한다.
💡 왜 JPA가 필요한지 영속성, JDBC에 대해서 먼저 알아보자
영속성 (Persistence)
프로그래밍에서 영속성은 객체의 상태를 데이터베이스와 같은 영구 저장소에 저장하고, 필요할 때 이를 다시 불러오는 것을 의미한다.
--> 어플리케이션의 상태와 상관 없도록 물리적인 저장소를 이용해 데이터를 저장하는 행위
보편적으로 관계형 데이터베이스(RDBMS)에 데이터를 저장하기 위해서는 SQL을 이용해 데이터를 영속화 해야 한다.
JDBC(Java Database Connectivity)
자바 어플리케이션에서 데이터베이스에 접근 하는 방법은 기본적으로 JDBC 인터페이스를 통한 방법이다. JDBC 인터페이스는 자바어플리케이션과 데이터베이스의 소통을 위한 기능들을 정의하고 있다. 각 데이터베이스 제조사들(ex. oracle, MySQL)은 JDBC 인터페이스를 구현하는 클래스들을 제공하며 이를 드라이버라고 한다. JDBC는 자바 애플리케이션과 데이터베이스 간의 통신을 추상화하여, 특정 데이터베이스에 종속되지 않도록 한다. 따라서 어떤 데이터베이스를 사용하는지에 따라서 JDBC Driver만 바꾸면 된다. 그러나, 순수 JDBC 기반의 영속적 데이터 관리는 개발 과정에서 다소 많은 시간과 비용을 발행하게 한다.
JDBC 인터페이스와 DBMS의 관계
순수 JDBC를 적용하여 데이터를 관리할 경우 자바 코드와 SQL 코드를 동일한 파일에서 관리하게 된다.
(쿼리가 문자열의 형태로 자바 코드 안에 있다.)
이런식으루..
public List<Course> getCoursesByName(String courseName) { // 강의명으로 강의 조회
List<Course> courses = new ArrayList<>();
Connection connection = DatabaseConnection.getConnection();
try {
String query = "SELECT * FROM DB2024_Course WHERE CourseName LIKE ?";
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.setString(1, "%" + courseName + "%");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
courses.add(mapCourse(resultSet));
}
} catch (Exception e) {
e.printStackTrace();
}
return courses;
}
따라서, 비즈니스 로직과 데이터 접근 로직을 분리하자는 것이 필요!
자원(resource) 접근 레이어
비즈니스 컴포넌트는 비즈니스 로직 레이어에, 자원 접근 모듈은 자원 접근 레이어에 놓여 있다. 데이터가 자원 접근 레이어를 통해 저장될 때, 데이터가 실제로 저장되는 경로는 자원 접근 레이어에서 어떤 모듈이 처리하는가에 따라 달라진다. 소프트웨어 아키텍처에서 비즈니스 로직과 데이터 접근 로직을 분리하는 중요한 원칙이다.
JPA의 필요성!
객체의 세상과 테이블의 세상 (객체와 테이블 간의 불일치)
객체 중심의 객체지향 어플리케이션과 테이블 중심의 관계형 데이터베이스는 서로의 목표가 다르다.
이를 패러다임이 일치하지 않는다고 표현하며 이는 개발 과정에서 많은 비용을 발생하게 한다.
영속적으로 데이터를 저장하기 위해 객체의 세상과 테이블의 세상을 서로 맞추는 과정이 필요하다.
Persistence Framework
자바 어플리케이션에서 관계형 데이터베이스의 사용을 돕는 프레임워크를 Persistence Framework라 한다.
Persistent Framework는 SQL Mapping과 OR Mapping으로 구분한다.
SQL Mapping은 자바 코드와 SQL을 분리하며 개발자가 작성한 SQL 수행 결과를 객체로 매핑한다.
OR Mapping은 객체와 관계형 데이터베이스 사이에서 매핑을 담당하며 SQL을 생성하여 패러다임의 불일치를 해결한다.
Persistence Framework는 로직에서 DB연결 설정을 분리하여, 개발자가 비즈로직에 집중할 수 있도록 도와준다.
SQL Mapping 프레임워크는 자바 객체와 쿼리 결과를 매핑한다.
OR Mapping 프레임워크는 자바 객체와 데이터베이스 릴레이션(테이블)을 매핑한다.
JPA의 정의와 역할
JPA는 자바 프로그램에서 관계형 데이터베이스에 접근하는 방식을 명세화한 인터페이스이다.
JPA는 자바 진영의 ORM(Object-Relational Mapping) 기술 표준이다.
자바 애플리케이션과 JDBC 사이에서 동작하며, 일반적으로 구현체는 Hibernate 라이브러리를 사용한다.
JPA를 적용할 경우 도메인 객체는 기술에 의존적이지 않으며 재사용을 높일 수있다.
객체를 영속화 하기 위해서는 객체에 annotation을 추가하거나 별도의 메타 데이터 구성이 필요하다.
JPA 내부 동작 방식
JPA를 통해 객체를 영속화 하기 위해서는 EntityManager 객체가 필요하며, EntityManager의 인스턴스 객체는 Entity ManagerFactory 객체를 통해 얻는다. EntityManager는 영속성 컨텍스트(PersistenceContext)를 통해 영속 객체를 관리한다.
사용자는 EntityManager 인스턴스 객체의 다양한 메소드를 이용해 영속 객체를 관리한다.
영속성 컨텍스트 (Persistence Context)
영속성 컨텍스트란 JPA에서 엔티티의 상태를 관리하는 환경을 의미한다. 영속성 컨텍스트는 데이터베이스와의 동기화를 통해 엔티티 객체의 생명주기를 관리하며, 엔티티를 데이터베이스와의 연결 상태에서 유지한다.
JPA의 EntityManager는 영속성 컨텍스트를 통해 엔티티의 상태를 관리한다. 영속성 컨텍스트는 애플리케이션과 영구 저장소(데이터베이스) 사이에 위치한다. Entity Manager를 통해 등록된 영속객체 혹은 저장소로부터 가져온 영속객체의 정보는 1차 캐시에서 관리한다.
영속성 컨텍스트 동작방식
EntityManager 단위로 관리된다. EntityManager.persist()를 통한 영속객체 등록은 우선 해당 객체가 1차 캐시에 저장되고 일반적으로 트랜잭션이 커밋되는 시점에 Insert 쿼리가 데이터베이스에 반영된다. EntityManager.find()를 통한 데이터 검색은 우선 1차 캐시를 통해 해당 객체를 검색하고 없을 경우 select 쿼리를 통해 데이터베이스에서 검색을 수행한다.
주요 기능
- 엔티티의 상태관리: 영속성 컨텍스트는 엔티티 객체의 생명주기를 관리한다. 엔티티의 상태는 비영속, 영속, 준영속, 삭제의 네 가지로 구분된다.
- 1차 캐시: 영속성 컨텍스트는 1차 캐시 역할을 한다. 동일한 트랜잭션 내에서 동일한 엔티티를 여러 번 조회할 때, 데이터베이스를 다시 조회하지 않고 1차 캐시에서 데이터를 가져온다.
- 변경 감지: 영속성 컨텍스트는 엔티티의 변경 사항을 감지하고, 트랜잭션이 커밋될 때 자동으로 데이터베이스에 반영한다.
- 쓰기 지연: 영속성 컨텍스트는 엔티티 매니저의 쓰기 작업을 모아서 한 번에 데이터베이스에 반영한다. 이를 통해 성능을 최적화할 수 있다.
- 엔티티 간의 관계 관리: 영속성 컨텍스트는 엔티티 간의 연관 관계를 관리한다. 이를 통해 객체 그래프를 일관성 있게 유지할 수 있다.
엔티티의 생명주기 상태
1. 비영속 상태 (Transient)
- 영속성 컨텍스트에 의해 관리되지 않는 상태이다.
- 데이터베이스와 연관되지 않으며, JPA가 추적하지 않는다.
- ex) 'new' 키워드로 생성된 엔티티 객체
2. 영속 상태 (Persistent)
- 영속성 컨텍스트에 의해 관리되는 상태이다.
- 데이터베이스와 동기화되어 영구적으로 저장된다.
- ex) EntityManager.persist() 메서드를 호출한 엔티티
3. 준영속 상태 (Detached)
- 영속성 컨텍스트가 닫히거나 엔티티가 분리되면, 엔티티는 준영속 상태가 된다.
- 더 이상 영속성 컨텍스트에 의해 관리되지 않지만 데이터베이스의 기록은 그대로 남아 있다.
- ex) EntityManager.detach() 메서드를 호출한 엔티티, 또는 EntityManger.colse() 이후의 엔티티
4. 삭제 상태 (Removed)
- 엔티티가 삭제되어 영속성 컨텍스트와 데이터베이스에서 제거될 상태이다.
- ex) EntityManger.remove() 메서드를 호출한 엔티티
'개발 노트' 카테고리의 다른 글
[Locust] 모델 서빙 최적화 실험: FastAPI와 Flask 부하 테스트 (1) | 2024.11.16 |
---|