
JPA란 무엇인가?
JPA(Java Persistence API)는 자바 진영의 ORM 기술 표준이다. JPA는 다음 그림처럼 애플리케이션과 JDBC 사이에서 동작한다.
ORM이란 무엇일까? ORM(Object-Relational Mapping)은 이름 그대로 객체와 관계형 데이터베이스를 매핑한다는 뜻이다. ORM 프레임워크는 객체와 테이블을 매핑해서 패러다임의 불일치 문제를 개발자 대신 해결해준다.
예를 들어 ORM 프레임워크를 사용하면 객체를 DB에 저장할 때 INSERT SQL을 직접 작성하는 것이 아니라 객체를 마치 자바 컬렉션에 저장하듯이 ORM 프레임워크에 저장하면 된다.
ORM 프레임워크는 단순히 SQL을 개발자 대신 생성해서 데이터베이스에 전달해주는 것뿐만 아니라 앞서 이야기한 다양한 패러다임의 불일치 문제들도 해결해준다. 그저 개발자는 Entity들을 어떻게 매핑해야 하는지 매핑 방법은 ORM 프레임워크에게 알려주면 된다.
자바 진영에도 다양한 ORM 프레임워크들이 있는데 그중에 하이버네이트 프레임워크가 가장 많이 사용된다. 하이버네이트는 거의 대부분의 패러다임 불일치 문제를 해결해주는 성숙한 ORM 프레임워크다.
JPA 표준 인터페이스와 구현체
그림을 보면 JPA는 자바 ORM 기술에 대한 API 표준 명세다. 쉽게 이야기해서 인터페이스를 모아둔 것이다.
따라서 JPA를 사용하려면 JPA를 구현한 ORM 프레임워크를 선택해야 한다.
JPA라는 표준 덕분에 특정 구현 기술에 대한 의존도를 줄일 수 있고 다른 구현 기술로 손쉽게 이동할 수 있는 장점이 있다.
JPA 표준은 일반적이고 공통적인 기능의 모음이다. 따라서 표준을 먼저 이해하고 필요에 따라 JPA 구현체가 제공하는 고유의 기능을 알아가면 된다.
왜 JPA를 사용해야 하는가?
▼생산성
지루하고 반복적인 코드와 CRUD용 SQL을 개발자가 직접 작성하지 않아도 된다. 더 나아가서 JPA에는 CREATE TABLE과 같은 DDL 문을 자동으로 생성해주는 기능도 있다.
▼유지보수
SQL에 의존적인 개발에서도 이야기했듯이 SQL을 직접 다루면 Entity에 필드를 하나만 추가해도 관련된 CRUD SQL과 결과를 매핑하기 위한 JDBC API 코드를 모두 변경해야 했다. 반면에 JPA를 사용하면 이런 과정을 JPA가 대신 처리해주므로 유지보수해야 하는 코드 수가 줄어든다
▼패러다임의 불일치 해결
JPA는 상속, 연관관계, 객체 그래프 탐색, 비교하기와 같은 패러다임의 불일치 문제를 해결해준다.
▼성능
같은 트랜잭션 안에서 같은 회원을 두 번 조회하는 코드가 있다면, JDBC API는 해당 회원을 두번 조회하지만 JPA를 사용하면 SELECT SQL을 한 번만 DB에 전달하고 두 번째는 조회한 회원 객체를 재사용한다.
▼데이터 접근 추상화와 벤더 독립성
관계형 데이터베이스는 같은 기능도 벤더마다 사용법이 다른 경우가 많다. JPA는 애플리케이션과 데이터베이스 사이에 추상화된 DB 접근 계층을 제공해서 애플리케이션이 특정 데이터베이스 기술에 종속되지 않도록 한다. 만약 데이터베이스를 변경하면 JPA에게 다른 DB를 사용한다고 알려주기만 하면된다. 예를 들어 JPA를 사용하면 로컬 개발 환경은 H2 DB를 사용하고 개발이나 상용환경은 오라클이나 MySQL 데이터베이스를 사용할 수 있다.
이제 JPA를 사용해서 테이블을 하나 생성하고 CRUD를 하는 애플리케이션을 만들어보자
IDE 설치와 프로젝트 불러오기
필자는 IDE로 IntelliJ를 사용하고 gradle project를 사용할 것이다.
https://www.h2database.com/html/download.html
Downloads
Downloads Version 2.2.224 (2023-09-17) Windows Installer (SHA1 checksum: 1e4cda116519e8f95cac8298b1a4d7cbd50073ec) Platform-Independent Zip (SHA1 checksum: 8de40da72b269ae1d7a899f25aa0bbcb242b6220) Version 2.1.214 (2022-06-13) Windows Installer (SHA1 check
www.h2database.com
해당 링크에 들어가 최신 버전의 Platform-Independent Zip 를 다운받고 h2/bin/h2.bat을 실행하자 간단하게 h2 dbms를 사용할 수 있다.
Hibernate를 구현체로 사용하기 위해 Spirng Data JPA, H2 DB 의존성 추가를 해주고 generate를 눌러 intelliJ에서 build.gradle을 open하면 된다.
객체 매핑 시작
회원 테이블과 회원클래스를 생성하자
CREATE TABLE MEMBER (
ID VARCHAR(255) NOT NULL,
NAME VARCHAR(255),
AGE INTEGER,
PRIMARY KEY (ID)
)
@Data
public class Member {
private String id;
private String username;
private Integer age;
}
lombok을 사용하여 getter, setter를 생성해주었다.
JPA를 사용하려면 가장 먼저 회원 클래스와 회원 테이블을 매핑해야 한다. 매핑 정보를 참고하여 실제 매핑을 시작해보자.
@Data
@Entity
@Table(name = "MEMBER")
public class Member {
@Id
@Column(name = "ID")
private String id;
@Column(name = "NAME")
private String username;
//매핑 정보가 없는 필드
private Integer age;
}
여기서 @Entity, @Table, @Column이 매핑 정보다 JPA는 매핑 어노테이션을 분석해서 어떤 객체가 어떤 테이블과 관계가 있는지 알아낸다
▼@Entity
이 클래스를 테이블과 매핑한다고 JPA에게 알려준다. 이렇게 @Entity가 사용된 클래스를 엔티티 클래스라고 한다.
▼ @Table
엔티티 클래스에 매핑할 정보를 알려준다 name 속성을 생략하면 클래스 이름을 테이블 이름으로 매핑한다
▼ @Id
엔티티 클래스의 필드를 테이블의 PK에 매핑한다. 이렇게 @Id가 사용된 필드를 식별자 필드라고 한다.
▼ @Column
필드를 컬럼에 매핑한다
▼매핑 정보가 없는 필드
age 필드에는 매핑 어노테이션이 없다. 이렇게 매핑 어노테피션을 생략하면 필드명을 사용해서 컬럼명으로 매핑한다.
여기서는 필드명이 age이므로 age 컬럼으로 매핑했다. 대소문자를 구분하는 DBMS의 경우에는 name 속성을 사용해 이름을 정확히 지정해줘야 한다.
매핑 정보 덕분에 JPA는 어떤 엔티티를 어떤 테이블에 저장해야 하는지 알 수 있다.
다음으로 JPA를 실행하기 위한 기본설정 파일인 persistence.xml을 알아보자
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
<persistence-unit name="jpastart">
<class>com.jpa.model.Member</class>
<properties>
<!-- 필수 속성! -->
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="jakarta.persistence.jdbc.user" value="sa"/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.use_sql_comments" value="true"/>
<property name="hibernate.id.new_generator_mappings" value="true"/>
</properties>
</persistence-unit>
</persistence>
JPA는 persistence.xml을 사용해서 필요한 설정 정보를 관리한다. 이 설정 파일이 resources/META-INF/persistence.xml 클래스 패스 경로에 있으면 별도의 설정 없이 JPA가 인식할 수 있다.
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" version="2.2">
설정 파일은 persistence로 시작한다 이곳에 XML 네임스페이스와 사용할 버전을 지정한다. 지정하지 않으면 최신 버전을 사용한다.
<persistence-unit name="jpastart">
JPA 설정은 영속성 유닛(persistence-unit)이라는 것부터 시작하는데 일반적으로 연결할 DB당 하나의 영속성 유닛을 등록한다. 그리고 영속성 유닛에는 고유한 이름을 부여해야 하는데 여기서는 jpastart라는 이름을 사용했다.
- JPA 표준 속성
- jakarta.persistence.jdbc.driver : JDBC driver
- jakarta.persistence.jdbc.user : DB 접속 아이디
- jakarta.persistence.jdbc.password : DB 접속 비밀번호
- jakarta.persistence.jdbc.url : DB 접속 URL
- Hibernate 속성
- hibernate.dialect : DB dialect(방언) 설정
이름이 jakarta.persistence로 시작하는 속성은 JPA 표준 속성으로 특정 구현체에 종속되지 않는다 반면에 hibernate로 시작하는 속성은 hiberante 전용 속성이므로 hibernate에서만 사용할 수 있다.
여기서 가장 중요한 속성은 DB 방언을 설정하는 hibernate.dialect이다.
데이터베이스 방언
JPA는 특정 DB에 종속적이지 않은 기술이다. 따라서 다른 DB로 손쉽게 교체할 수 있다. 그런데 각 DB가 제공하는 SQL 문법과 함수가 조금씩 다르다는 문제점이 있다.
SQL 표준을 지키지 않거나 특정 DB만의 고유한 기능을 JPA에서는 방언(Dialect)라고 한다. 애플리케이션 개발자가 특정 DB에 종속되는 기능을 많이 사용하면 나중에 DB를 교체하기가 어렵다.
대부분의 JPA 구현체들은 이런 문제를 해결하려고 다양한 DB dialect 클래스를 제공한다.
위의 그림처럼 개발자는 JPA가 재공하는 표준 문법에 맞추어 JPA를 사용하면 되고, 특정 DB에 의존적인 SQL은 DB 방언이 처리해준다. 따라서 DB가 변경되어도 애플리케이션 코드를 변경할 필요 없이 DB 방언만 교체하면 된다.
사용된 hibernate 전용 속성은 다음과 같다.
- hibernate.show_sql : hibernate가 실행한 SQL을 출력한다.
- hibernate.format_sql : hibernate가 실행한 SQL을 출력할 때 보기 쉽게 정렬한다.
- hibernate.use_sql_comments : 쿼리를 출력할 때 주석도 함께 출력한다.
- hibernate.id.new_generator_mappings: JPA 표준에 맞춘 새로운 키 생성 전략을 사용한다.
출처
김영한, "자바 ORM 표준 JPA 프로그래밍(2015)", 에이콘출판사
'Database' 카테고리의 다른 글
연관관계 매핑 기초 (0) | 2024.02.04 |
---|---|
엔티티 매핑 (1) | 2024.01.24 |
영속성 관리 (1) | 2024.01.21 |
JPA를 활용한 애플리케이션 개발해보기 (1) | 2024.01.21 |
JPA 소개 (0) | 2024.01.20 |

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!