JPA(Java Persistence API)의 개념

이혜지·2020년 9월 24일
14

Spring

목록 보기
11/15
post-thumbnail

JPA(Java Persistence API)

  • 자바 ORM 기술에 대한 표준 명세로, JAVA에서 제공하는 API이다. 스프링에서 제공하는것이 아니다.
  • 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스다.
  • 여기서 중요한건 JPA는 말 그대로 인터페이스이다.
    JPA는 특정 기능을 하는 라이브러리가 아니다. 스프잉의 PSA에 의해서(POJO를 사용하면서 특정 기술을 사용하기 위해서)표준 인터페이스를 정해두었는데, 그중 ORM을 사용하기 위해 만든 인터페이스가 바로 JPA이다.
  • 기존 EJB에서 제공되던 엔티티 빈을 대체하는 기술이다.
  • ORM이기 때문에 자바 클래스와 DB테이블을 매핑한다.(SQL을 매핑하지않는다)
  • ORM을 사용하기 위한 인터페이스를 모아둔 것이며, JPA를 사용하기 위해서는 JPA를 구현한 Hibernate, EclipseLink, DataNucleus같은 ORM 프레임워크를 사용해야 합니다.

ORM이란?

ORM이란 객체와 DB의 테이블이 매핑을 이루는 것을 말합니다.
즉, 객체가 테이블이 되도록 매핑 시켜주는 것을 말합니다..
ORM을 이용하면 SQL Query가 아닌 직관적인 코드(메서드)로서 데이터를 조작할 수 있습니다.

예들들어, User 테이블의 데이터를 출력하기 위해서 MySQL에서는
SELECT * FROM user;라는 query를 실행해야하지만, ORM을 사용하면 User 테이블과 매핑된 객체를 user라 할 때, user.findAll() 라는 메서드 호출로 데이터를 조회 가능합니다.

query를 직접 작성하지 않고 메서드 호출만으로 query가 수행되다 보니, ORM을 사용하면 생산성이 매우 높아집니다.
그러나 query가 복잡해지면 ORM으로 표현하는데 한계가 있고, 성능이 raw query에 비해 느리다는 단점이 있기때문에, JPQL, QueryDSL 등을 사용하거나 한 프로젝트 내에서 Mybatis와 JPA를 같이 사용하기도 합니다.

Spring - Data - JPA 란 ?


JPA는 ORM을 위한 자바 EE 표준이며 Spring-Data-JPA는 JPA를 쉽게 사용하기 위해 스프링에서 제공하고 있는 프레임워크이다.

추상화 정도는 Spring-Data-JPA -> Hibernate -> JPA이다.
Hibernate를 쓰는 것과 Spring Data JPA를 쓰는 것 사이에는 큰 차이가 없지만

  • 구현체 교체의 용이성
  • 저장소 교체의 용이성
    이라는 이유에서 Spring Data JPA를 사용하는것이 더 좋다.

Spring Data JPA, Spring Data MongoDB, Spring Data Redis등 Spring Data의 하위 프로젝트들은 findAll(), save()등을 동일한 인터페이스로 가지고 있기 때문에 저장소를 교체해도 기본적인 기능이 변하지않는다.

JPA 동작 과정

JPA는 애플리케이션과 JDBC 사이에서 동작한다.
개발자가 JPA를 사용하면, JPA 내부에서 JDBC API를 사용하여 SQL을 호출하여 DB와 통신한다.
즉, 개발자가 직접 JDBC API를 쓰는 것이 아니다.

insert


MemberDAO에서 객체를 저장하고 싶을 때 개발자는 JPA에 Member 객체를 넘긴다.

JPA는
1.Member 엔티티를 분석한다.
2. insert sql을 생성한다.
3. JDBC API를 사용하여 SQL을 DB에 날린다.

find


개발자는 member의 pk값을 JPA에 넘긴다.

JPA는
1. 데이터를 객체지향적으로 관리할 수 있기 때문에 개발자는 비즈니스 로직에 집중할 수 있고 객체지향 개발이 가능하다.
2. JDBC API를 사용하여 SQL을 DB에 날리낟.
3. DB로부터 결과를 받아온다.
4. 결과(ResultSet)를 객체에 모두 매핑한다.
쿼리를 JPA가 만들어 주기 때문에 Object와 RDB 간의 패러다임 불일치를 해결할 수 있다.

🤷‍♀️JPA를 왜 사용해야 할까?

  1. sql 중심적인 개발에서 객체 중심적인 개발이 가능하다.
    sql 코드의 반복, 객체지향과 관계지향 데이터베이스의 페러다임 불일치

Object -> [SQL 변환] -> RDB에 저장
[개발자 == SQL 매퍼] 라고 할만큼 SQL 작업을 너무 많이 하고 있다.

  1. 생산성이 증가
    간단한 메소드로 CRUD가 가능하다

  2. 유지보수가 쉽다
    기존: 필드 변경 시 모든 SQL을 수정해야 한다.
    JPA: 필드만 추가하면 된다. SQL은 JPA가 처리하기 때문에 손댈 것이 없다.

  3. Object와 RDB 간의 패러다임 불일치 해결

JPA Hibernate(하이버네이트)

하이버네이트는 JPA 구현체의 한 종류이다.
JPA는 DB와 자바 객체를 매핑하기 위한 인터페이스(API)를 제공하고 JPA 구현체(하이버네이트)는 이 인터페이스를 구현한 것이다.

하이버네이트 외에도 EclipseLink, DataNucleus, OpenJPA, TopLink Essentials등이 있다.

  • Hibernate가 SQL을 직접 사용하지 않는다고 해서 JDBC API를 사용하지 않는다는 것은 아니다.

  • Hibernate가 지원하는 메서드 내부에서는 JDBC API가 동작하고 있으며, 단지 개발자가 직접 SQL을 작성하지 않을 뿐이다.

  • HQL(Hibernate Query Language)이라 불리는 매우 강력한 쿼리 언어를 포함하고 있다.

  • HQL은 SQL하고 매우 비슷하며 추가적인 컨벤션을 정의할 수도 있다.

  • HQL은 완전히 객체 지향적이며 이로써 상속, 다형성, 관계 등의 객체지향의 강점을 누릴 수 있다.

  • HQL은 쿼리 결과로 객체를 반환하며 프로그래머에 의해 생성되고 직접적으로 접근할 수 있다.

  • HQL은 SQL에서는 지원하지 않는 페이지네이션이나 동적 프로파일링과 같은 향상된 기능을 제공한다.

  • HQL은 여러 테이블을 작업할 때 명시적인 join을 요구하지 않는다.

    영속성(Persistence)

    데이터를 생성한 프로그램이 종료되어도 사라지지 않는 데이터의 특성을 말한다.

    영속성을 갖지 않으면 데이터는 메모리에서만 존재하게 되고 프로그램이 종료되면 해당 데이터는 모두 사라지게 된다.

    그래서 우리는 데이터를 파일이나 DB에 영구 저장함으로써 데이터에 영속성을 부여한다.

    Persistence Layer

    프로그램의 아키텍처에서 데이터에 영속성을 부여해주는 계층을 말한다.
    JDBC를 이용해 직접 구현이 가능하나 보통은 Persistance Framework를 사용한다.

  • 프레젠테이션 계층 (Presentation layer) - UI 계층 (UI layer) 이라고도 함

  • 애플리케이션 계층 (Application layer) - 서비스 계층 (Service layer) 이라고도 함

  • 비즈니스 논리 계층 (Business logic layer) - 도메인 계층 (Domain layer) 이라고도 함

  • 데이터 접근 계층 (Data access layer) - 영속 계층 (Persistence layer) 이라고도 함

Persistance Framework

JDBC프로그래밍의 복잡함이나 번거로움 없이 간단한 작업만으로 DB와 연동되는 시스템을 빠르게 개발할 수 있고 안정적인 구동을 보장한다.

Persistance Framework는 SQL Mapper와 ORM으로 나눌 수 있다.

JPA에서의 영속성


JPA의 핵심 내용은 엔티티가 영속성 컨텍스트에 포함되어 있냐 아니냐로 갈린다.
JPA의 엔티티 매니저가 활성화된 상태로 트랜잭션(@Transactional) 안에서 DB에서 데이터를 가져오면 이 데이터는 영속성 컨텍스트가 유지된 상태이다. 이 상태에서 해당 데이터 값을 변경하면 트랜잭션이 끝나는 시적에 해당 테이블에 변경 내용을 반영하게 된다. 따라서 우리는 앤티티 객체의 필드 값만 변경해주면 별도로 update()쿼리를 날릴 필요가 없게 된다! 이 개념을 더티 체킹이라고 한다.

Spring Data Jpa를 사용하면 기본으로 엔티티 매니저가 활성화되어있는 상태이다.

영속 컨텍스트: 엔티티를 담고 있는 집합. JPA는 영속 컨텍스트에 속한 엔티티를 DB에 반영한다. 엔티티를 검색, 삭제, 추가 하게 되면 영속 컨텍스트의 내용이 DB에 반영된다.
영속 컨텍스트는 직접 접근이 불가능하고 Entity Manager를 통해서만 접근이 가능하다.

엔티티: @Entity 어노테이션을 붙인 클래스

1. Entity Class
엔티티 클래스는 자바 클래스에 @Entity 어노테이션을 붙여, 테이블과 매핑한다고 JPA에게 알려주는 클래스다.
그리고 엔티티 클래스에서 만들어진 객체를 엔티티라고 한다.

2. 영속성 컨텍스트(Persistence Context)

영속성 컨텍스트는 엔티티 클래스에서 만들어지는 엔티티를 영구 저장하고 관리하는 환경이다.

영속성 컨텍스트와 관련한 엔티티의 4가지 상태

① 비영속(new/transient) - 엔티티 객체가 만들어져서 아직 저장되지 않은 상태로, 영속성
컨텍스트와 전혀 관계가 없는 상태

② 영속(managed) - 엔티티가 영속성 컨텍스트에 저장되어, 영속성 컨텍스트가 관리할 수 있
는 상태

③ 준영속(detached) - 엔티티가 영속성 컨텍스트에 저장되어 있다가 분리된 상태로, 영속성
컨텍스트가 더 이상 관리하지 않는 상태

④ 삭제(removed) - 엔티티를 영속성 컨텍스트와 데이터베이스에서 삭제

영속성 컨텍스트의 특징

① 영속성 컨텍스트는 엔티티를 식별자 값(@Id로 테이블의 기본키와 매핑한 필드 값)으로 구분
한다. 그렇기 때문에 영속 상태는 식별자 값이 반드시 있어야 한다.

② 영속성 컨텍스트에 엔티티를 저장하면 바로 데이터베이스에 저장되는 것이 아니라, 1차 캐시
에 엔티티를 생성하고, 쓰기 지연 SQL 저장소에 쿼리문을 생성해서 저장한다.
이렇게 쌓인 쿼리문은 flush( )가 실행될 때 데이터베이스에 반영된다.

3. 엔티티 생성

  1. 자바 어플리케이션에서 어떤 엔티티가 만들어져서 JPA에게 데이터베이스 저장을 부탁하면,

  2. 만들어진 엔티티는 1차적으로 영속성 컨텍스트에 저장된다. 1차 캐시 정도라고 생각하면 된다. 그리고, 저장한 엔티티를 데이터베이스에 저장하기 위한 쿼리문을 생성시켜 쓰기 지연 SQL 저장소에 저장한다.계속해서 엔티티를 넘기면 엔티티들과 쿼리문들은 차곡차곡 영속성 컨텍스트에 저장된다.

  3. 그러다가 자바 어플리케이션에서 커밋 명령이 내려지면 영속 컨텍스트에는 자동으로 flush()가 호출되고,

  4. 영속성 컨텍스트의 변경내용을 데이터베이스와 동기(flush)화 한다(SQL 저장소의 쿼리를 실행시킨다).

  5. 마지막으로 데이터베이스에게 commit 쿼리문을 명령한다.

4. 엔티티 조회
1. 자바 어플리케이션에서 JPA에게 데이터베이스 조회를 부탁하면,
1차적으로 영속성 컨텍스트에서 엔티티를 찾는다.

  1. 있으면 자바 어플리케이션에 엔티티를 넘긴다.

  2. 영속성 컨텍스트에 없는 엔티티 조회를 부탁하면

  3. 쿼리문을 사용해 데이터베이스에서 찾아와

  4. 영속성 컨텍스트에 엔티티로 저장하고

  5. 자바 어플리케이션에 그 엔티티를 넘긴다.

5. 엔티티 변경
JPA는 엔티티를 영속성 컨텍스트에 보관할 때, 최초의 상태를 복사해서 저장해 두는데,
이것을 스냅샷이라 한다.

  1. 자바 어플리케이션에서 커밋 명령이 들어오면, 영속 컨텍스트에는 자동으로 flush( )가 호출되고,

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

  3. 변경된 엔티티가 있으면 데이터베이스에 변경사항을 저장하기 위해 쿼리를 생성하고,

  4. 영속성 컨텍스트의 변경내용을 데이터베이스와 동기(flush)화 한다(SQL 저장소의 쿼리를 실행시킨다).

  5. 마지막으로 데이터베이스에게 commit 쿼리문을 명령한다.

이렇게 엔티티의 변경사항을 데이터베이스에 자동으로 반영하는 기능을 변경감지(Dirty Checking)이라 한다.

6. 엔티티 삭제

앞의 과정과 마찬가지로, 자바 어플리케이션에서 엔티티 삭제 명령이 들어오면,

엔티티를 찾고 쓰기 지연 SQL 저장소에 delete 쿼리를 생성한다.

그리고 자바 어플리케이션에서 커밋 명령이 들어오면, 자동으로 flush( )가 호출되고,

영속성 컨텍스트의 변경내용을 데이터베이스와 동기(flush)화 한다(SQL 저장소의 쿼리를 실행시킨다).

마지막으로 데이터베이스에게 commit 쿼리문을 명령한다.

JPA 메소드

(1) flush( )

영속성 컨텍스트의 변경 내용을 데이터베이스에 반영한다.

실행되었을 때 일어나는 일

① 변경 감지가 동작해서 영속성 컨텍스트에 있는 모든 엔티티를 스냅샵과 비교해서 수정된 엔티티를 찾고,수정된 엔티티를 데이터베이스에 반영하기 위해 수정 쿼리를 생성하여 지연 SQL 저장소에 등록

② 쓰기 지연 SQL 저장소의 쿼리를 데이터 베이스에 전송(등록, 수정, 삭제 쿼리) 보통 직접 사용하지 않고, 자바 어플리케이션에서 커밋 명령이 들어왔을 때, 자동으로 실행된다.

(2) detach( )

특정 엔티티를 준영속 상태로 만든다.

준영속 상태가 된 엔티티는 더이상 영속 컨텍스트의 관리를 받지 않으며,
영속 컨텍스트가 지원하는 어떤 기능도 동작하지 않게 된다.
영속 상태가 영속성 컨텍스트로에게 관리(managed)되는 상태라고 하면,
준영속 상태는 영속성 컨텍스트로부터 분리(detached)된 상태이다.

(3) clear( )

영속성 컨텍스트를 초기화 한다.
영속성 컨텍스트의 모든 엔티티를 준영속 상태로 만든다.

(4) close( )

영속성 컨텍스트를 종료한다.

영속성 컨텍스트가 관리하던 영속 상태의 엔티티가 모둔 준영속 상태가 된다.

영속 상태의 엔티티는 주로 영속성 컨텍스트가 종료되면서 준영속 상태가 된다.

개발자가 직접 준영속 상태로 만드는 일은 거의 없다.

(5) merge( )

준영속 상태의 엔티티의 특징

① 거의 비영속 상태에 가깝다. 영속성 컨텍스트가 관리하지 않으므로 영속성 컨텍스트가 제공하는 어떠한 기능도 동작하지 않는다.

② 식별자 값을 가지고 있다. 비영속 상태의 엔티티는 식별자(엔티티를 구분하기 위한 유일한 값, ID)를 가지지 않고 있을 수도 있지만,
*준영속 상태는 이미 한 번 영속 상태였기 때문에, 식별자 값을 가지고 있다.

merge( )는 준영속 상태의 엔티티를 이용해서 새로운 영속 상태의 엔티티를 반환한다.

실행되었을 때 일어나는 일

① 파라미터로 넘어온 준영속 엔티티의 식별자 값으로 1차 캐시에서 엔티티를 조회
(1차 캐시에 엔티티가 없으면 데이터베이스에서 엔티티를 조회하고 1차 캐시에 저장)

② 조회한 영속 엔티티에 준영속 엔티티의 값을 채워 넣는다.

③ 생성된 새로운 영속 엔티티를 반환한다.

새롭게 생성된 영속 상태의 엔티티를 가지고 이제 영속성 컨텍스트가 지원하는 기능을 사용할 수 있다.
준영속 상태의 엔티티를 영속 상태로 변경하는 것이 아니라, 새로운 영속 상태의 엔티티를 만들어서, 준영속 상태의 엔티티 값을 영속 상태의 엔티티에 채워 넣어서 반환하는 점에 주의해야 한다.
그리고, 준영속 뿐만 아니라, 비영속 상태의 엔티티도 병합하여 새로운 영속 상태의 엔티티를 만들어 반환한다.

자세한 내용은 위의 엔티티 변경 참조.

(6) find( )

식별자 값을 가지고 엔티티를 찾아서 반환한다.

자세한 내용은 위의 엔티티 조회 참조

(7) persist( )

자바 어플리케이션에서 생성된 엔티티를 영속성 컨텍스트와 데이터베이스에 저장한다.

자세한 내용은 위의 엔티티 생성 참조

(8) remove( )

식별자 값을 가지고 엔티티를 찾아서 삭제한다.

자세한 내용은 위의 엔티티 삭제 참조

profile
공유 문화를 지향하는 개발자입니다.

0개의 댓글