JPA를 배우기 전에 먼저 실습 프로젝트를 실행할 수 있는 상태로 만들어야 한다.
JPA는 자바 클래스만 작성한다고 바로 동작하지 않는다.
데이터베이스와 연결해야 하고,JPA구현체도 필요하고, 어떤 엔티티 클래스를 관리할지도 설정해야 한다.
이번 글에서는IntelliJ에서Java프로젝트를 만들고,Gradle에 필요한 의존성을 추가한 뒤, 제공된 실습 소스와persistence.xml을 알맞은 위치에 넣는 단계까지 정리한다.
Maven Repository사이트에 들어가서 의존성을 검색하는 과정은 이번 실습에서는 생략한다.
이미 정리된 의존성 코드를build.gradle에 직접 넣는 방식으로 진행한다.
이번 단계의 핵심은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파일을 연다.
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실행 설정을 확인한다.
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설정을 확인해야 한다.
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폴더를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-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&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&serverTimezone=UTC" />
value=" jdbc:mysql://...처럼 앞에 공백이 들어가면JPA가 데이터베이스 주소를 올바른JDBC URL로 인식하지 못할 수 있다.
복사한 뒤에는value="jdbc:mysql://localhost:3306/edudb...처럼jdbc앞에 공백이 없는지 확인한다.
build.gradle이 라이브러리를 준비하는 단계라면,persistence.xml의jdbc설정은 실제 데이터베이스 접속 정보를 준비하는 단계이다.
둘 중 하나라도 빠지면JPA실습이 정상적으로 진행되지 않는다.
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-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가 데이터베이스 연결 정보와 엔티티 클래스를 인식할 수 있게 만들고, 실행 테스트로 그 연결이 실제로 동작하는지 확인하는 과정이다.