Spring Framework/JPA

[JPA] 1. 개요 및 개발환경 구축

hyomee2 2024. 9. 13. 02:44

JPA 개요

1. JPA란?

Java 진영의 ORM(Object Relational Mapping) 기술 표준으로 ORM 기술을 사용하기 위한 표준 인터페이스의 모임이다.

JDBC에서 JDBC가 인터페이스고 그 구현체가 Driver였던 것처럼 JPA는 인터페이스, Hibernate는 그 구현체라 생각하면 된다.

ORM은 자바 객체와 DB 테이블을 매핑하고 자바 객체 간의 관계를 토대로 SQL을 생성 및 실행할 수 있다.

2. JPA의 특징

- 영속성 컨텍스트가 엔티티(DB와 매핑되는 자바 객체)를 생명주기를 통해 관리한다.

- DBMS별로 Dialect를 제공한다.

  (JPA 내부에서 사용하는 SQL 문법인 JPQL을 구동시키면 사용하는 DB별 SQL 구문을 JPA 쪽에서 알아서 만들어준다.)

 

- native SQL을 통해 직접 SQL을 해당 DB에 맞게 작성할 수도 있다.

3. JPA의 장점

- Java객체와 RDBMS(관계형 DB)는 데이터를 저장하거나 다루는 데 있어 패러다임이 서로 다른데(객체지향과 관계지향),

JPA는 이 둘 간의 서로 다른 패러다임 불일치를 해소해주어 SQL 중심이 아닌 객체지향 패러다임 중심의 개발이 가능하다.

(패러다임의 차이는 JPA가 해소해줄테니 객체 지향적 관점에 맞춰 코드를 짜면 된다.)

- 개발자가 직접 SQL을 작성하지 않아도 SQL문을 작성해주므로 생산성이 향상된다.

- SQL을 수정할 필요가 없으므로 설정 및 필드 변경 시 SQL이 자동 수정되어 유지보수가 향상된다.

 (JPA는 SQL에 대한 의존성을 없애는 것이 목적이다.

 SQL이 변경되어도 Java 코드를 바꿔야 하는 상황을 막고 싶고, Java 코드 만으로 온전할 수 있도록 만드는 것이 목적이다.)

- 캐시를 활용한 성능 최적화로 인해 트랜젝션을 처리하는 시간이 굉장히 많이 단축된다.

4. JPA의 단점

- 너무 복잡한 SQL을 작성하기엔 적합하지 않다.

- JPA를 제대로 이해하지 못하고 작성 시 성능 저하가 발생할 수 있다.

5. MyBatis와 JPA

- JPA는 ORM 기술, MyBatis는 SQL Mapper의 한 종류다.

- MyBatis는 SQL Mapper로 SQL Mapping을 사용하는 영속성(DB 저장) 프레임워크이다.

  개발자가 직접 SQL 코드를 작성해야하고, 객체 매핑을 위한 설정을 모두 직접 처리해야 한다.

  또한 수정이 이루어질 시 SQL 뿐만 아니라 매핑될 객체까지 같이 수정해야한다.

- 어플리케이션이 단순하면 JPA 성능이 크게 올라가지만, 복잡한 경우에는 JPA보다 MyBatis가 좋은 선택일 수도 있다.

6. JPA의 원리

(1) JPA의 기본 동작 방식

Java 어플리케이션과 JDBC 사이에서 동작하며 내부적으로 JDBC API를 활용한다.

JPA는 엔티티를 저장하는 환경인 영속성 컨텍스트(Persistence Context)를 통해 엔티티를 보관하고 관리한다.

여기서 엔티티는 @Entity, @Table, @Id, @Column과 같은 어노테이션을 통해

SQL이 아닌 DB 테이블과 매핑되게 작성된 클래스이다.

(2) 엔티티의 영속성 컨텍스트에서의 생명주기

엔티티 매니저가 엔티티를 저장하는 공간으로, 엔티티를 보관하고 관리한다.

엔티티 매니저가 생성될 때 하나의 영속성 컨텍스트가 만들어진다.

엔티티의 생명주기는 아래와 같다.

상태 설명
비영속(new/transient) 엔티티가 영속성 컨텍스트와 전혀 관계가 없는 상태
영속(managed) 엔티티가 영속성 컨텍스트에 저장된 상태
준영속(detached) 영속성 컨텍스트에 저장되었다가 분리된 상태
삭제(removed) 엔티티가 삭제된 상태
병합(merge) 엔티티가 준영속 상태인 엔티티가 다시 영속상태로 변경된 상태

(3) 영속성 컨텍스트가 엔티티를 관리하는 원리

1) 1차 캐시

영속성 컨텍스트 내부에 Map으로 관리되는 캐시(key는 @Id이며 매핑한 식별자이고 value는 엔티티 인스턴스이다.)이며

이 곳에 있는 엔티티는 캐시에서 바로 불러와서 조회 성능이 올라간다.

 

2) 동일성 보장

반복해서 호출 시 1차 캐시에서 같은 엔티티 인스턴스를 가져올 수 있다.

 

3) 트랜젝션을 지원하는 쓰기 지연 (transactional write-behind)

엔티티 등록(INSERT)을 예로 들면,

엔티티 매니저는 트랜젝션을 커밋하기 직전까지 데이터베이스에 저장(flush) 대신

쓰기 지연 SQL 저장소에 INSERT SQL을 차곡차곡 쌓게 되며 커밋 시에 쿼리를 데이터베이스로 보내는데,

이를 트랜젝션을 지원하는 쓰기 지연이라고 한다.

* flush(영속성 컨텍스트의 변경 내용을 데이터베이스에 반영) 절차

1. 영속성 컨텍스트에 보관할 때 최초 엔티티 상태를 복사해서 스냅샷으로 저장해두고

모든 엔티티를 스냅샷과 비교하여 수정된 엔티티를 찾은 뒤 수정 쿼리를 만들어 쓰기 지연 SQL 저장소에 보낸다.

2. 쓰기 지연 SQL 저장소의 쿼리를 데이터베이스에 저장한다.

* flush를 하는 경우

- em.flush()를 직접 호출한다.

- 트랜젝션 커밋 시 자동 호출한다.

- JPQL 쿼리 실행 시 자동 호출한다.

 

4) 변경 감지(dirty checking)

SQL에 의존적이지 않도록 엔티티의 데이터 변경을 감지하고 데이터베이스에 자동 반영하는 기능이다.

영속성 컨텍스트에 보관할 때 최초 엔티티 상태를 복사해서 저장한 스냅샷과 이를 비교하여 감지한다.

영속 상태의 엔티티에만 적용되고, 준영속이나 비영속은 해당되지 않는다.

* 변경 감지 절차(commit 실행 시)

1. 엔티티와 스냅샷을 비교해서 변경된 엔티티를 찾는다.

2. 변경된 엔티티와 관련된 수정 쿼리를 생성해서 쓰기 지연 SQL 저장소에 보낸다.

3. 쓰기 지연 저장소의 SQL을 데이터베이스로 보낸다.

4. 데이터베이스에서 트랜젝션을 커밋한다.


개발 환경 설정

Java project를 생성한다.

1. bulid.gradle 설정

JPA 사용을 위한 Hibernate ORM Hibernate Core MariaDB 사용을 위한 MariaDB Java Client 의존성을 추가한다.

dependencies {
    // jdbc는 항상 드라이버가 필요하다. DBMS에 맞춰서 가져오자.
    // https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-client
    implementation 'org.mariadb.jdbc:mariadb-java-client:3.4.1'

    // jdbc 인터페이스를 구현하는 구현체로 hibernate를 사용
    // https://mvnrepository.com/artifact/org.hibernate.orm/hibernate-core
    implementation 'org.hibernate.orm:hibernate-core:6.6.0.Final'

    // 생략
}

2. persistence.xml 생성

persistence.xml은 JPA의 설정 파일으로, 이 파일에는 엔티티 매니저 팩토리를 설정하기 위한 내용이 들어간다.

<!-- resources/META-INF/persistence.xml-->

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">

    <!-- 엔티티 매니저 팩토리를 식별하기 위한 이름 설정 -->
    <persistence-unit name="jpatest">

        <class>org.example.section02.crud.Menu</class>>
        <class>org.example.section03.entity.Menu</class>>

        <properties>
            <!-- 데이터 베이스 연결 정보 -->
            <property name="jakarta.persistence.jdbc.driver" value="org.mariadb.jdbc.Driver"/>
            <property name="jakarta.persistence.jdbc.url" value="jdbc:mariadb://localhost:3307/menudb"/>
            <property name="jakarta.persistence.jdbc.user" value="swcamp"/>
            <property name="jakarta.persistence.jdbc.password" value="swcamp"/>
            <!-- hibernate 설정 (실행 되는 sql 구문을 format 형태로 보여준다) -->
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.format_sql" value="true"/>
        </properties>

    </persistence-unit>

</persistence>

'Spring Framework > JPA' 카테고리의 다른 글

[JPA] 6. Association Mapping  (6) 2024.09.17
[JPA] 5. Mapping  (0) 2024.09.16
[JPA] 4. EntityLifeCycle  (6) 2024.09.13
[JPA] 3. CRUD 실습  (0) 2024.09.13
[JPA] 2. Persistence Context - EntityManager 생성하기  (1) 2024.09.13