[아이티센 부트캠프] JPA 1

이언덕·2026년 4월 29일

아이티센 부트캠프

목록 보기
78/115
post-thumbnail

JPA 프로젝트 세팅

JPA를 배우기 전에 먼저 실습 프로젝트를 실행할 수 있는 상태로 만들어야 한다.
JPA는 자바 클래스만 작성한다고 바로 동작하지 않는다.
데이터베이스와 연결해야 하고, JPA 구현체도 필요하고, 어떤 엔티티 클래스를 관리할지도 설정해야 한다.


이번 글에서는 IntelliJ에서 Java 프로젝트를 만들고, Gradle에 필요한 의존성을 추가한 뒤, 제공된 실습 소스와 persistence.xml을 알맞은 위치에 넣는 단계까지 정리한다.
Maven Repository 사이트에 들어가서 의존성을 검색하는 과정은 이번 실습에서는 생략한다.
이미 정리된 의존성 코드를 build.gradle에 직접 넣는 방식으로 진행한다.


이번 단계의 핵심은 JPA 코드를 작성하는 것이 아니라, JPA가 실행될 수 있도록 프로젝트 구조와 설정 파일을 정확히 준비하는 것이다.



JPA 프로젝트 세팅이 필요한 이유

JPA는 자바 객체와 데이터베이스 테이블을 매핑해서 다루는 기술이다.
매핑은 서로 다른 두 구조를 연결해 주는 작업이다.
자바에서는 데이터를 객체로 다루고, 데이터베이스에서는 데이터를 테이블과 행으로 다룬다.
JPA는 이 둘 사이의 차이를 줄여서, 개발자가 객체를 저장하고 조회하듯이 데이터베이스 작업을 할 수 있게 도와준다.


여기서 ORM이라는 개념도 같이 알아두면 좋다.
ORM은 객체와 관계형 데이터베이스 테이블을 매핑하는 방식이다.
JPA는 자바에서 ORM을 사용하기 위한 표준 규칙이고, Hibernate는 그 표준을 실제로 동작하게 해 주는 구현체이다.
즉, JPA는 약속이고, Hibernate는 그 약속을 실제 코드로 실행해 주는 도구라고 이해하면 된다.


그래서 JPA는 일반 자바 코드처럼 클래스 하나만 만들고 실행하는 흐름과는 다르다.
자바 프로그램이 데이터베이스에 접속할 수 있어야 하고, JPA 표준을 실제로 실행해 줄 구현체도 있어야 한다.
또 어떤 자바 클래스를 테이블과 매핑할지도 설정해야 한다.


먼저 MySQL에 접속하려면 MySQL JDBC Driver가 필요하다.
JDBC Driver는 자바 프로그램과 데이터베이스 사이를 연결해 주는 통신 도구이다.
자바 코드가 직접 MySQL과 대화하는 것이 아니라, 이 드라이버를 통해 데이터베이스에 접속한다.


다음으로 Hibernate가 필요하다.
Hibernate는 JPA 표준을 실제로 실행하는 구현체이다.
개발자가 JPA 방식으로 객체 저장을 요청하면, Hibernate가 내부에서 필요한 SQL을 만들어 데이터베이스에 전달한다.


마지막으로 persistence.xml이 필요하다.
persistence.xml은 JPA 설정 파일이다.
이 파일에는 어떤 데이터베이스에 접속할지, 어떤 엔티티 클래스를 관리할지, 테이블을 자동으로 만들거나 수정할지 같은 설정이 들어간다.


즉, 이번 세팅은 크게 세 가지를 준비하는 과정이다.
Gradle로 필요한 라이브러리를 추가한다.
제공된 자바 실습 소스를 프로젝트에 넣는다.
persistence.xml을 정해진 위치에 넣어서 JPA가 설정 파일을 읽을 수 있게 만든다.


이 준비가 끝나야 다음 단계에서 EntityManagerFactory, EntityManager, Entity, 영속성 컨텍스트 같은 JPA 핵심 개념을 실제 코드로 확인할 수 있다.



프로젝트 생성 시작

IntelliJ를 실행한 뒤 새 프로젝트를 만든다.
상단 메뉴에서 File → New → Project를 선택한다.


이번 실습은 Spring Boot 프로젝트로 시작하지 않는다.
일반 Java 프로젝트로 만든다.
이유는 Spring Boot가 자동으로 처리해 주는 부분을 잠시 빼고, JPA 자체가 어떤 설정을 읽고 어떻게 실행되는지 먼저 보기 위해서이다.


Spring Boot를 사용하면 설정이 자동으로 잡히는 부분이 많다.
처음에는 편하지만, JPA가 내부에서 어떤 파일을 보고 어떤 순서로 준비되는지 놓치기 쉽다.
그래서 이번 단계에서는 일반 Java 프로젝트를 만들고, 필요한 설정을 직접 넣어 보면서 기본 흐름을 확인한다.

File → New → Project를 선택하면 새 프로젝트를 생성하는 화면으로 들어갈 수 있다.



프로젝트 생성 옵션 설정

새 프로젝트 화면에서는 왼쪽에서 Java를 선택한다.
프로젝트 이름은 jpaedu로 지정한다.
저장 위치는 실습 환경에 맞게 지정한다.


빌드 시스템은 Gradle을 선택한다.
Gradle은 프로젝트에 필요한 라이브러리를 내려받고, 프로젝트를 빌드하고, 테스트를 실행하는 일을 도와주는 도구이다.
이번 실습에서는 필요한 라이브러리를 build.gradle에 직접 추가할 것이므로 Gradle을 사용한다.


Gradle DSL은 Groovy를 선택한다.
DSL은 설정 파일을 어떤 문법으로 작성할지 정하는 방식이다.
여기서는 build.gradle 파일을 Groovy 문법으로 작성한다.


JDK는 실습 환경에 맞는 버전을 선택한다.
화면에서는 Oracle OpenJDK 21.0.7이 선택되어 있다.
JDK는 자바 코드를 컴파일하고 실행하기 위한 개발 도구이다.
자바 프로젝트를 만들려면 반드시 필요하다.


Add sample code는 체크하지 않는다.
샘플 코드가 자동으로 만들어지면 제공된 실습 소스와 섞여서 구조를 이해하기 어려워질 수 있다.
이번 실습에서는 제공된 jpaexam1, jpaexam2, util 폴더를 직접 넣을 것이므로 빈 프로젝트로 시작하는 편이 깔끔하다.

IntelliJ에서 새 JPA 실습 프로젝트를 만들 때는 프로젝트 이름과 위치를 정하고, 빌드 시스템으로 Gradle을 선택한다.


프로젝트를 생성하면 기본 폴더 구조가 만들어진다.
src/main/java에는 자바 소스 코드가 들어간다.
src/main/resources에는 실행할 때 필요한 설정 파일이 들어간다.


이 구분은 뒤에서 매우 중요하다.
jpaexam1, jpaexam2, util 같은 자바 패키지는 src/main/java 아래에 들어가야 한다.
반대로 persistence.xml은 자바 코드가 아니라 설정 파일이므로 src/main/resources 아래에 들어가야 한다.



build.gradle에 JPA 실습 의존성 추가

프로젝트가 생성되면 build.gradle 파일을 연다.
build.gradle은 Gradle 프로젝트의 설정 파일이다.
여기에는 프로젝트 그룹, 버전, 외부 라이브러리를 내려받을 저장소, 사용할 의존성 등이 들어간다.


먼저 repositories를 확인한다.
repositories는 외부 라이브러리를 어디에서 내려받을지 정하는 부분이다.
여기서는 mavenCentral()을 사용한다.
mavenCentral()은 자바 라이브러리들이 모여 있는 대표 저장소이다.
그래서 아래 dependencies에 작성한 라이브러리들을 Gradle이 이 저장소에서 찾아 내려받을 수 있다.

// build.gradle
repositories {
    mavenCentral() // 외부 라이브러리를 받을 저장소
}

정리하면 repositories는 라이브러리를 찾을 장소이고, dependencies는 실제로 프로젝트에서 사용할 라이브러리 목록이다.


그다음 dependencies 블록 안에 JPA 실습에 필요한 의존성을 추가한다.
의존성은 프로젝트에서 사용할 외부 라이브러리를 뜻한다.
내가 직접 만든 코드가 아니어도, 이미 만들어진 기능을 프로젝트에서 사용하려면 의존성으로 추가해야 한다.


예를 들어 JPA 어노테이션을 쓰려면 jakarta.persistence-api가 필요하고, JPA를 실제로 실행하려면 Hibernate가 필요하다.
또 MySQL에 연결하려면 MySQL JDBC Driver가 필요하다.


이번에는 Maven Repository 사이트에서 검색하는 과정은 생략한다.
이미 정리된 의존성 목록을 build.gradle에 직접 넣는다.


붙여 넣을 때 주의할 점이 있다.
중간에 file:/Users/leeunduck/education/springstudy/jpaedu/build.gradle 같은 파일 경로가 들어가면 안 된다.
이것은 의존성 문법이 아니라 파일 위치가 잘못 섞인 것이다.
Hibernate 의존성은 아래처럼 org.hibernate:hibernate-core:6.5.2.Final 형태로만 작성해야 한다.

// build.gradle
dependencies {
    implementation 'mysql:mysql-connector-java:8.0.17' // MySQL 연결 드라이버
    implementation 'org.hibernate:hibernate-core:6.5.2.Final' // JPA 구현체 Hibernate
    implementation 'jakarta.persistence:jakarta.persistence-api:3.2.0' // JPA 표준 API
    implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.2' // XML 처리 관련 API
    compileOnly 'org.projectlombok:lombok:1.18.32' // Lombok 컴파일 전용 설정
    annotationProcessor 'org.projectlombok:lombok:1.18.32' // Lombok 어노테이션 처리기
}

이번 실습에서는 제공된 설정에 맞춰 mysql:mysql-connector-java:8.0.17을 사용한다.
다른 자료에서는 com.mysql:mysql-connector-j처럼 다른 표기를 볼 수도 있지만, 여기서는 현재 실습 환경 기준으로 진행한다.


mysql:mysql-connector-java는 MySQL과 연결하기 위한 드라이버이다.
자바 프로그램이 MySQL에 접속하려면 이 라이브러리가 필요하다.


org.hibernate:hibernate-core는 Hibernate 핵심 라이브러리이다.
Hibernate는 JPA 표준을 실제로 동작하게 해 주는 구현체이다.
즉, 코드에서 JPA 방식으로 저장이나 조회를 요청하면, Hibernate가 내부에서 알맞은 SQL을 만들어 데이터베이스와 통신한다.


jakarta.persistence-api는 JPA 표준 문법을 사용하기 위한 라이브러리이다.
@Entity, @Id, EntityManager, EntityManagerFactory 같은 타입을 사용하려면 필요하다.


jakarta.xml.bind-api는 XML 데이터를 자바 객체와 연결해 처리할 때 필요한 API이다.
이번 실습에서는 persistence.xml처럼 XML 기반 설정을 사용하고, 실행 환경에 따라 관련 API가 따로 필요할 수 있으므로 함께 추가한다.


Lombok은 반복되는 코드를 줄여 주는 라이브러리이다.
예를 들어 필드마다 getter, setter, toString()을 직접 만들지 않고 @Getter, @Setter, @ToString 같은 어노테이션으로 처리할 수 있다.

build.gradle의 dependencies 블록에 MySQL, Hibernate, Jakarta Persistence, Jakarta XML Bind, Lombok 의존성을 추가한다.


build.gradle을 수정한 뒤에는 반드시 Gradle 동기화를 해야 한다.
동기화를 해야 IntelliJ가 새로 추가된 라이브러리를 프로젝트에서 사용할 수 있게 인식한다.


동기화하지 않으면 코드에는 의존성을 적었는데도 jakarta.persistence, Hibernate, Lombok 관련 클래스가 빨간색 오류처럼 보일 수 있다.
이때는 코드가 틀린 것이 아니라, Gradle 변경 사항이 아직 프로젝트에 반영되지 않은 상태일 수 있다.



Gradle 실행 설정 확인

다음으로 Gradle 실행 설정을 확인한다.
Settings에서 Build, Execution, Deployment → Build Tools → Gradle로 이동한다.


여기서 Build and run using과 Run tests using을 IntelliJ IDEA로 설정한다.
이 설정은 프로젝트를 빌드하고 실행할 때 어떤 도구를 기준으로 처리할지 정하는 부분이다.


학습 단계에서는 IntelliJ IDEA로 맞춰 두면 IntelliJ 안에서 실행 흐름을 확인하기 쉽다.
설정을 바꿨다면 Apply를 눌러 반영한다.

Build and run using과 Run tests using을 IntelliJ IDEA로 설정하면 IntelliJ 기준으로 빌드와 실행을 처리할 수 있다.


이 설정은 JPA 문법 자체를 배우는 내용은 아니다.
하지만 실행 환경이 꼬이면 뒤에서 예제를 실행할 때 오류 원인을 찾기 어려워진다.
그래서 본격적인 JPA 코드로 들어가기 전에 먼저 확인해 두는 것이 좋다.



Lombok annotation processing 설정

Lombok을 사용하려면 annotation processing 설정을 확인해야 한다.
annotation processing은 컴파일 과정에서 어노테이션을 해석하고 필요한 코드를 만들어 주는 기능이다.


예를 들어 클래스에 @Getter를 붙이면 개발자가 getName() 같은 메서드를 직접 작성하지 않아도 된다.
하지만 실제로는 컴파일 과정에서 Lombok이 그 메서드를 만들어 주는 것이다.
그래서 IntelliJ가 Lombok 어노테이션을 처리할 수 있도록 설정해야 한다.


Settings에서 Build, Execution, Deployment → Compiler → Annotation Processors로 이동한다.
그리고 Enable annotation processing을 체크한다.

Lombok의 @Getter, @Setter, @ToString 같은 어노테이션이 동작하려면 Enable annotation processing을 활성화해야 한다.


이 설정을 하지 않으면 Lombok 어노테이션을 붙였는데도 getter나 setter가 없는 것처럼 인식될 수 있다.
그러면 엔티티 코드나 실행 코드에서 메서드를 찾지 못하는 오류가 생길 수 있다.


초보자 입장에서는 이 부분이 특히 헷갈릴 수 있다.
코드에는 @Getter가 붙어 있으니 당연히 getter가 있다고 생각하는데, 설정이 꺼져 있으면 IntelliJ가 그것을 제대로 처리하지 못할 수 있다.
그래서 Lombok을 쓰는 프로젝트에서는 이 설정을 먼저 확인하는 습관이 필요하다.



제공된 학습 소스 복사

이제 제공된 학습 소스를 프로젝트에 넣는다.
jpaexam1, jpaexam2, util 폴더를 src/main/java 아래에 복사한다.


src/main/java는 자바 소스 코드가 들어가는 위치이다.
엔티티 클래스, 실행 클래스, 보조 유틸 클래스는 모두 자바 코드이므로 이 위치 아래에 있어야 한다.


jpaexam1과 jpaexam2는 이후 실습에서 사용할 예제 코드 묶음이다.
jpaexam1에는 기본 엔티티 실습에 필요한 클래스들이 들어 있고, jpaexam2에는 직원, 부서, 지역처럼 관계를 가진 엔티티 실습 코드가 들어 있다.
util은 실습에서 필요한 보조 기능을 담는 폴더이다.


지금 단계에서는 각 클래스의 내부 코드를 자세히 분석하지 않는다.
이번 단계의 목표는 JPA 실습 코드가 프로젝트 안에서 정상적으로 인식될 수 있도록 폴더 위치를 맞추는 것이다.

제공된 jpaexam1, jpaexam2, util 폴더는 자바 소스 코드이므로 src/main/java 아래에 복사한다.


자바 소스 코드는 src/main/java, 설정 파일은 src/main/resources에 넣는다는 구분이 중요하다.
이 구분을 잘못하면 자바 클래스가 소스 코드로 인식되지 않거나, 설정 파일을 JPA가 찾지 못할 수 있다.



META-INF와 persistence.xml 복사

다음으로 제공된 META-INF 폴더를 src/main/resources 아래에 복사한다.
최종 위치는 src/main/resources/META-INF/persistence.xml이 되어야 한다.


persistence.xml은 자바 클래스가 아니다.
JPA가 실행될 때 읽는 설정 파일이다.
그래서 src/main/java가 아니라 src/main/resources 아래에 들어가야 한다.


여기서 META-INF 폴더 이름도 중요하다.
JPA는 정해진 위치에서 persistence.xml 파일을 찾는다.
일반적으로 resources/META-INF/persistence.xml 위치에 있어야 한다.
폴더 이름이 다르거나 위치가 다르면 JPA가 설정 파일을 찾지 못할 수 있다.

persistence.xml은 JPA 설정 파일이므로 src/main/resources/META-INF 아래에 위치해야 한다.


이 위치가 맞아야 나중에 자바 코드에서 Persistence.createEntityManagerFactory("entitytest")를 실행했을 때 JPA가 entitytest라는 설정 묶음을 찾을 수 있다.


즉, persistence.xml은 단순히 프로젝트에 들어 있는 설정 파일이 아니다.
자바 코드에서 실행할 JPA 설정 이름과 실제 데이터베이스 연결 정보를 이어 주는 시작점이다.



persistence.xml 기본 구조 확인

persistence.xml 안에는 persistence-unit이 들어 있다.
persistence-unit은 하나의 JPA 설정 묶음이다.
쉽게 말하면 “이 이름으로 실행하면 이 데이터베이스에 연결하고, 이 엔티티 클래스들을 관리하라”는 설정 단위이다.


현재 persistence.xml에는 entitytest와 emptest라는 두 개의 persistence-unit이 들어 있다.
이처럼 이름이 다른 설정 묶음을 여러 개 만들어 둘 수 있다.
각 설정 묶음은 사용할 엔티티 목록이나 데이터베이스 설정을 따로 가질 수 있다.
이번 세팅 글에서는 먼저 entitytest를 기준으로 구조를 확인한다.


entitytest라는 이름은 나중에 자바 코드에서 그대로 사용된다.
예를 들어 자바 코드에서 Persistence.createEntityManagerFactory("entitytest")를 호출하면, JPA는 persistence.xml 안에서 이름이 entitytest인 설정 묶음을 찾아 읽는다.


전체 파일을 모두 보는 대신, 먼저 구조를 이해하기 위한 핵심 부분만 보면 아래와 같다.
아래 코드는 전체 파일을 그대로 옮긴 것이 아니라, 구조를 이해하기 위해 필요한 핵심 형태만 줄여서 본 것이다.
실제 파일에는 엔티티 클래스 목록이나 설정이 더 들어갈 수 있다.

<persistence-unit name="entitytest">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <class>jpaexam1.entity.EntityTest1</class>
    <class>jpaexam1.entity.EntityTest2</class>
    <class>jpaexam1.entity.EntityTest3</class>
    <class>jpaexam1.entity.EntityTest4</class>
    <class>jpaexam1.entity.EntityTest5</class>
    <class>jpaexam2.model.entity.Emp</class>
    <class>jpaexam2.model.entity.Dept</class>
    <class>jpaexam2.model.entity.Locations</class>
    <properties>
        <property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
        <property name="jakarta.persistence.jdbc.user" value="jdbctest" />
        <property name="jakarta.persistence.jdbc.password" value="jdbctest" />
        <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>
</persistence-unit>

provider는 실제 JPA 구현체를 지정하는 부분이다.
여기서는 org.hibernate.jpa.HibernatePersistenceProvider가 들어 있다.
즉, JPA 표준을 실제로 실행하는 도구로 Hibernate를 사용한다는 뜻이다.


class는 JPA가 관리할 엔티티 클래스를 등록하는 부분이다.
엔티티는 데이터베이스 테이블과 연결되는 자바 클래스이다.
JPA는 이 목록에 등록된 클래스를 보고 어떤 클래스가 데이터베이스 테이블과 매핑되는지 확인한다.


properties는 데이터베이스 연결 정보와 Hibernate 동작 설정을 담는 부분이다.
여기에는 사용할 드라이버, 데이터베이스 계정, 비밀번호, 접속 주소, 테이블 자동 처리 방식 같은 설정이 들어간다.


초보자는 persistence.xml을 보면 복잡한 설정 파일처럼 느껴질 수 있다.
하지만 처음에는 세 부분만 나눠 보면 된다.
provider는 누가 실행할지 정하는 부분이다.
class는 어떤 엔티티를 관리할지 정하는 부분이다.
properties는 어떤 데이터베이스에 어떻게 연결할지 정하는 부분이다.



데이터베이스 연결 설정 확인

persistence.xml에서 데이터베이스 연결 설정은 매우 중요하다.
이 값이 틀리면 자바 코드가 맞아도 데이터베이스에 접속하지 못한다.


이 설정이 동작하려면 먼저 MySQL 서버가 실행 중이어야 한다.
또 edudb 데이터베이스가 있어야 하고, jdbctest 계정과 비밀번호도 준비되어 있어야 한다.
즉, persistence.xml은 새로운 데이터베이스 계정을 자동으로 만들어 주는 파일이 아니다.
이미 준비된 데이터베이스에 어떻게 접속할지를 적어 두는 설정 파일이다.


대표 설정은 아래와 같다.

<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
<property name="jakarta.persistence.jdbc.user" value="jdbctest" />
<property name="jakarta.persistence.jdbc.password" value="jdbctest" />
<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/edudb?characterEncoding=UTF-8&amp;serverTimezone=UTC" />

jakarta.persistence.jdbc.driver는 사용할 JDBC Driver를 지정한다.
여기서는 MySQL 드라이버인 com.mysql.cj.jdbc.Driver를 사용한다.


jakarta.persistence.jdbc.user는 데이터베이스 접속 계정이다.
현재 값은 jdbctest이다.


jakarta.persistence.jdbc.password는 해당 계정의 비밀번호이다.
현재 값은 jdbctest이다.


jakarta.persistence.jdbc.url은 접속할 데이터베이스 주소이다.
localhost:3306은 현재 컴퓨터에서 실행 중인 MySQL 서버의 3306 포트로 접속한다는 뜻이다.
edudb는 접속할 데이터베이스 이름이다.


즉, 이 설정을 말로 풀면 이렇다.
현재 컴퓨터의 MySQL 서버에 접속한다.
edudb 데이터베이스를 사용한다.
접속 계정과 비밀번호는 jdbctest를 사용한다.


특히 emptest 설정의 jdbc.url을 확인할 때는 jdbc:mysql:// 앞에 공백이 들어가 있지 않은지 봐야 한다.
실제 연결 문자열은 아래처럼 바로 jdbc로 시작해야 한다.

<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/edudb?characterEncoding=UTF-8&amp;serverTimezone=UTC" />

value=" jdbc:mysql://...처럼 앞에 공백이 들어가면 JPA가 데이터베이스 주소를 올바른 JDBC URL로 인식하지 못할 수 있다.
복사한 뒤에는 value="jdbc:mysql://localhost:3306/edudb...처럼 jdbc 앞에 공백이 없는지 확인한다.


build.gradle이 라이브러리를 준비하는 단계라면, persistence.xml의 jdbc 설정은 실제 데이터베이스 접속 정보를 준비하는 단계이다.
둘 중 하나라도 빠지면 JPA 실습이 정상적으로 진행되지 않는다.



Hibernate 설정 확인

persistence.xml에는 Hibernate 관련 설정도 들어 있다.
이 설정들은 JPA가 실행될 때 어떤 SQL을 보여 줄지, 엔티티와 테이블 구조를 어떻게 맞출지에 영향을 준다.


대표 설정은 아래와 같다.

<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<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.hbm2ddl.auto" value="update" />

hibernate.dialect는 사용할 데이터베이스 문법을 Hibernate에게 알려 주는 설정이다.
데이터베이스마다 SQL 문법이 조금씩 다르다.
그래서 Hibernate는 어떤 데이터베이스 기준으로 SQL을 만들어야 하는지 알아야 한다.
이번 실습에서는 MySQL을 사용하므로 MySQLDialect가 설정되어 있다.


hibernate.show_sql은 실행되는 SQL을 콘솔에 출력할지 정한다.
값이 true이면 JPA가 내부적으로 어떤 SQL을 실행하는지 볼 수 있다.


이 설정은 학습할 때 매우 중요하다.
코드에서는 객체를 저장하거나 조회하는 것처럼 보이지만, 실제 데이터베이스에는 insert, select, update, delete 같은 SQL이 실행된다.
show_sql을 켜 두면 객체 중심 코드가 실제 SQL로 어떻게 바뀌는지 확인할 수 있다.


hibernate.format_sql은 출력되는 SQL을 보기 좋게 줄바꿈해서 보여 주는 설정이다.
SQL이 한 줄로 길게 출력되면 읽기 어렵기 때문에 학습 단계에서는 true로 두는 편이 좋다.


hibernate.use_sql_comments는 출력되는 SQL에 주석을 붙여 어떤 쿼리인지 더 쉽게 파악하게 해 준다.
즉, 콘솔에 출력되는 SQL을 읽기 쉽게 만드는 보조 설정이다.


가장 중요한 설정은 hibernate.hbm2ddl.auto이다.
이 설정은 엔티티 클래스 정보를 기준으로 테이블 구조를 어떻게 처리할지 정한다.
현재 값은 update이다.

hibernate.hbm2ddl.auto 값이 update이면 JPA 실행 시 엔티티 정보를 기준으로 기존 테이블 구조에 필요한 변경분을 반영한다.


update는 기존 테이블을 모두 지우고 다시 만드는 방식이 아니다.
엔티티 정보를 기준으로 필요한 변경분을 반영하는 방식이다.
예를 들어 새로운 엔티티가 등록되어 있으면 테이블을 만들 수 있고, 컬럼이 추가되면 변경분을 반영할 수 있다.


다만 update가 모든 변경을 완벽하게 안전하게 처리해 주는 만능 설정은 아니다.
특히 컬럼 삭제나 컬럼 타입 변경처럼 위험한 변경은 update가 기대한 대로 처리하지 못할 수 있다.
학습 단계에서는 편리하지만, 실제 운영 환경에서 테이블 구조 변경을 자동으로 맡기면 위험할 수 있다.
운영 데이터가 있는 상황에서는 테이블 변경을 더 조심스럽게 관리해야 한다.


따라서 학습 단계에서는 update로 엔티티와 테이블이 어떻게 맞춰지는지 확인하고, 실제 운영 환경에서는 테이블 변경을 자동 설정에 맡기기보다 직접 관리하는 방식으로 접근해야 한다.


이 단계에서는 update는 엔티티와 테이블 구조를 맞추기 위해 변경분을 반영하는 학습용 설정이라고 이해하면 된다.



persistence.xml 위치와 설정 이름이 중요한 이유

persistence.xml은 단순히 프로젝트 안에 있기만 하면 되는 파일이 아니다.
정확한 위치에 있어야 하고, 그 안의 persistence-unit 이름도 자바 코드에서 사용하는 이름과 맞아야 한다.


예를 들어 자바 코드에서 아래처럼 작성한다고 생각해 보자.

// HelloJPA1.java
EntityManagerFactory factory = Persistence.createEntityManagerFactory("entitytest"); // entitytest 설정 묶음 읽기

이 코드는 persistence.xml에서 이름이 entitytest인 persistence-unit을 찾는다.
그리고 그 설정 묶음 안에 있는 데이터베이스 연결 정보, 엔티티 클래스 목록, Hibernate 설정을 읽어서 EntityManagerFactory를 만든다.


EntityManagerFactory는 EntityManager를 만들기 위한 공장 역할을 한다.
EntityManager는 엔티티 객체를 저장하고 조회하고 수정하고 삭제하는 실제 작업의 중심 객체이다.


즉, 흐름은 아래처럼 이어진다.
먼저 persistence.xml 위치를 맞춘다.
그 안의 persistence-unit 이름을 확인한다.
자바 코드에서 같은 이름으로 EntityManagerFactory를 만든다.
그다음 EntityManager를 통해 엔티티를 다룬다.


이 흐름을 알면 왜 src/main/resources/META-INF/persistence.xml 위치가 중요한지 더 분명해진다.
JPA는 설정 파일을 읽고 나서야 어떤 데이터베이스와 어떤 엔티티를 사용할지 알 수 있다.



세팅이 제대로 되었는지 실행으로 확인하기

persistence.xml의 위치와 설정을 맞췄다면, 실제로 JPA가 이 파일을 읽을 수 있는지 확인해야 한다.
이때 가장 간단하게 확인할 수 있는 방법은 EntityManagerFactory를 만들어 보는 것이다.


EntityManagerFactory는 EntityManager를 만들기 위한 공장 역할을 한다.
아직 데이터를 저장하거나 조회하지 않더라도, EntityManagerFactory가 정상적으로 만들어진다는 것은 JPA가 설정 파일을 읽고, 데이터베이스 연결 정보와 엔티티 클래스 목록을 해석했다는 뜻이다.


이번 테스트에서는 HelloJPA1.java를 실행한다.
이 코드는 Persistence.createEntityManagerFactory("entitytest")를 호출한다.
여기서 "entitytest"는 임의의 문자열이 아니라, persistence.xml 안에 있는 persistence-unit name="entitytest"와 반드시 일치해야 한다.

// HelloJPA1.java
package jpaexam1.app;

import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

public class HelloJPA1 {
    public static void main(String[] args) {
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("entitytest"); // entitytest 설정 묶음 읽기
        System.out.println("EntityManagerFactory 객체 : " + factory.getClass().getName()); // 생성된 구현 객체 확인
        factory.close(); // 사용한 자원 정리
    }
}

이 코드에서 가장 중요한 부분은 Persistence.createEntityManagerFactory("entitytest")이다.
JPA는 이 이름을 기준으로 src/main/resources/META-INF/persistence.xml 파일을 찾고, 그 안에서 이름이 entitytest인 설정 묶음을 읽는다.


마지막의 factory.close()는 만들어 둔 EntityManagerFactory가 사용한 자원을 정리하는 코드이다.
이번 예제처럼 확인만 하고 끝나는 경우에도, 사용한 자원은 닫아 주는 흐름을 같이 익히는 것이 좋다.


즉, 실행 흐름은 아래와 같다.
HelloJPA1을 실행한다.
JPA가 persistence.xml을 찾는다.
entitytest라는 persistence-unit을 읽는다.
등록된 엔티티 클래스와 데이터베이스 연결 정보를 확인한다.
Hibernate가 필요한 테이블 생성 또는 변경 SQL을 실행한다.
마지막으로 EntityManagerFactory 객체가 만들어진다.

HelloJPA1의 "entitytest"와 persistence.xml의 persistence-unit name="entitytest"가 연결된다.
이 이름이 맞아야 JPA가 어떤 설정 묶음을 사용할지 찾을 수 있다.


MySQL에서 테이블을 확인할 때는 먼저 edudb 데이터베이스를 선택한 상태여야 한다.
예를 들어 use edudb;를 실행한 뒤 show tables;를 실행하면 현재 edudb 안의 테이블 목록을 볼 수 있다.
이 상태에서 HelloJPA1을 실행하면 persistence.xml에 등록된 엔티티 정보를 기준으로 Hibernate가 필요한 테이블 생성 또는 변경 작업을 수행한다.


이때 중요한 설정이 hibernate.hbm2ddl.auto이다.
현재 값은 update이다.
update는 기존 테이블을 모두 삭제하고 다시 만드는 방식이 아니라, 엔티티 정보를 기준으로 필요한 변경분을 반영하는 방식이다.

hibernate.dialect는 MySQL 문법에 맞게 SQL을 만들도록 지정하고, hibernate.hbm2ddl.auto의 update는 엔티티와 테이블 구조의 변경분을 반영하도록 설정한다.


이 테스트에서 성공 여부는 두 가지로 확인할 수 있다.
첫째, 콘솔에 EntityManagerFactory 객체 : org.hibernate.internal.SessionFactoryImpl이 출력된다.
둘째, MySQL에서 show tables;를 다시 실행했을 때 엔티티 정보를 기준으로 만들어진 테이블이 보인다.


실행 결과를 보면 Hibernate 로그가 출력된다.
이 로그에는 어떤 persistence-unit을 처리하는지, 어떤 Hibernate 버전을 사용하는지, 어떤 JDBC Driver를 읽었는지, 어떤 JDBC URL로 접속했는지가 나온다.


마지막에 EntityManagerFactory 객체 : org.hibernate.internal.SessionFactoryImpl이 출력된다.
이 말은 JPA 표준 타입인 EntityManagerFactory를 만들었지만, 실제 내부 구현체는 Hibernate의 SessionFactoryImpl이라는 뜻이다.
즉, 앞에서 설명한 것처럼 JPA는 표준이고, 실제 동작은 Hibernate가 처리한다는 흐름이 실행 결과로 확인된다.


실행 로그에서 entitytest 설정 묶음을 처리하고, MySQL에 연결한 뒤, EntityManagerFactory 구현 객체가 만들어진 것을 확인할 수 있다.


hibernate.show_sql이 true로 설정되어 있기 때문에 실행 중 만들어지는 SQL도 콘솔에 출력된다.
여기서는 엔티티 클래스 정보를 기준으로 create table, alter table, add constraint 같은 명령이 출력된다.


create table은 테이블을 새로 만드는 명령이다.
alter table은 기존 테이블 구조를 변경하는 명령이다.
add constraint는 외래키나 유니크 제약조건 같은 규칙을 테이블에 추가하는 명령이다.

Hibernate가 엔티티 클래스 정보를 읽고, 필요한 테이블을 만들거나 기존 테이블 구조를 수정하는 SQL을 실행한다.

엔티티 사이에 관계가 설정되어 있으면 Hibernate가 외래키 제약조건을 추가하는 alter table 명령도 실행할 수 있다.


실행 후 다시 show tables;를 확인하면 entitytest2, entitytest3, entitytest4, entitytest5, entitytesttbl, locker, membertbl, mymytest, team 같은 테이블이 보인다.
이 테이블들은 persistence.xml에 등록된 엔티티 클래스 정보를 기준으로 만들어지거나 변경된 결과이다.


여기서 꼭 구분해야 할 점이 있다.
update는 애플리케이션을 실행할 때마다 무조건 모든 테이블을 새로 만드는 설정이 아니다.
이미 필요한 테이블이 있으면 그대로 두고, 부족한 부분이나 변경이 필요한 부분만 반영하려고 한다.
그래서 학습할 때는 편리하지만, 실제 운영 환경에서 모든 테이블 변경을 update에 맡기는 것은 위험할 수 있다.

hibernate.hbm2ddl.auto는 엔티티 정보를 기준으로 테이블을 어떻게 처리할지 정한다.
현재 실습에서는 update를 사용해서 필요한 변경분을 반영한다.


hibernate.hbm2ddl.auto에 설정할 수 있는 대표 값은 아래처럼 정리할 수 있다.
create는 기존 테이블을 삭제한 뒤 다시 생성한다.
create-drop은 create처럼 생성하되, 종료 시점에 테이블을 삭제한다.
update는 변경분을 반영한다.
validate는 엔티티와 테이블이 정상적으로 맞는지만 확인한다.
none은 테이블 생성이나 변경 작업을 하지 않는다.


이번 실습에서는 update를 사용했기 때문에 JPA 실행 시 엔티티 정보를 기준으로 필요한 테이블 생성과 변경이 일어나는지 확인할 수 있다.
즉, HelloJPA1 테스트는 단순히 파일 하나를 실행해 보는 것이 아니라, build.gradle 의존성, persistence.xml 위치, persistence-unit 이름, 데이터베이스 연결, 엔티티 매핑이 모두 이어지는지 확인하는 세팅 검증 단계이다.


만약 이 단계에서 오류가 난다면 먼저 persistence.xml 위치, persistence-unit 이름, jdbc.url 앞 공백, edudb 데이터베이스 존재 여부, jdbctest 계정 정보를 차례대로 확인하면 된다.



여기까지 세팅이 끝났을 때의 상태

여기까지 완료하면 JPA 실습을 시작할 기본 준비가 끝난다.


여기까지 끝났다면 아래 상태가 되어 있어야 한다.
build.gradle에는 JPA 실습에 필요한 의존성이 들어 있다.
src/main/java 아래에는 jpaexam1, jpaexam2, util 폴더가 있다.
src/main/resources/META-INF 아래에는 persistence.xml이 있다.
persistence.xml 안에는 entitytest, emptest 설정 묶음과 데이터베이스 연결 정보가 들어 있다.
Gradle 동기화와 Lombok 설정도 완료되어 있다.
HelloJPA1 실행을 통해 JPA가 entitytest 설정 묶음을 읽고 EntityManagerFactory를 만들 수 있는 것도 확인했다.


이제 다음 단계부터는 실제 JPA 실행 흐름으로 넘어갈 수 있다.
다음에 볼 핵심은 EntityManagerFactory와 EntityManager이다.
이 두 객체를 이해하면 JPA가 설정 파일을 읽고, 엔티티를 관리하고, 데이터베이스와 연결되는 큰 흐름이 잡힌다.


이번 세팅 글의 핵심을 한 줄로 정리하면 이것이다.
JPA 프로젝트 세팅은 Gradle 의존성, 실습 소스 위치, persistence.xml 위치와 설정을 맞춰서 JPA가 데이터베이스 연결 정보와 엔티티 클래스를 인식할 수 있게 만들고, 실행 테스트로 그 연결이 실제로 동작하는지 확인하는 과정이다.

0개의 댓글