JPA 2.2 에서 JPA 3 으로 버전업이 되면서 내부의 패키지 명칭이 javax.*
에서
jakarta.*
로 바뀌었고, 명칭 또한 Java Persistence API
에서
Jakarta Persistence API
로 바뀌게 되었습니다.
이런 변화로 인해서 기존 JPA 2.2 을 베이스로 Java 프로젝트를
생성하던 방식과 JPA 3.0 버전의 생성 방식에 차이가 생겼습니다.
패지키 명칭이 바뀐 이유가 궁금하다면 이 링크를 참조하세요.
이 글은 현재 많은 블로그들에 기재되어 있는 기존 JPA 2.2 방식의 프로젝트 생성법이 아닌,
JPA 3 방식의 프로젝트를 생성하는 방법을 알아내는 것이 이 글의 목표입니다.
이 글에서는 많은 라이브러리를 maven 으로 추가하는데,
이때 사용되는 라이브러리들의 버전들은 글을 작성할 당시의 가장 최신
Spring Boot 인Spring Boot 3.1.2
에서 사용되는dependency version
을 참고했습니다. 또한 사용하는 JDK 버전도 Spring Boot 3 에서 요구하는 최소 버전인17
을 사용했습니다.
혹시라도 아래 과정이 다 귀찮은 분들이 있다면 그냥 제 Git Repository 에 있는
프로젝트를 clone 받아서 하셔도 좋습니다.https://github.com/CodingToastBread/jpa3-hibernate6-querydsl5
이 프로젝트에서는
h2 2.2.224
버전 및 jdk 21 을 사용한다는 점만 주의하시면 됩니다!
참고링크: 프로젝트 세팅 완성본 - 깃 리포지토리
혹여 세팅이 완료된 프로젝트 구조를 먼저 빠르게 보고 싶다면 제 깃 리포지토리에
오셔서 clone 을 받아 보셔도 됩니다.
참고: 필자의 개발환경
IDE:IntelliJ Ultimate
OS :Window 10 (Home Edition)
DB : H2 Database (v1.4.200) (설치하는 방법)
JDK : 17 (Spring Boot 3 의 최소 JDK 버전을 고려함)
New Project
를 생성해줍니다.프로젝트 생성 직후 pom.xml
은 아래와 같이 생겼습니다.
이제 이 파일을 수정하여 dependency
를 추가해보겠습니다. 아래처럼
pom.xml
의 <properties>
태그 바로 아래에 <dependencies>
태그를 넣어줍니다.
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 추가된 태그 -->
<dependencies>
<!-- Spring Boot 3.1.2 의 Version Dependecy 참고 -->
<!-- 필수 라이브러리 -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.2.6.Final</version>
</dependency>
<!-- Spring Boot 3.1.2 의 Version Dependecy 참고 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-hikaricp</artifactId>
<version>6.2.6.Final</version>
</dependency>
<!-- Spring Boot 3.1.2 의 Version Dependecy 참고 -->
<!-- slf4j-api 2.0.7 버전과 호환 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.4.8</version>
</dependency>
<!-- 자신이 설치한 h2 데이터베이스의 버전과 통일 -->
<!-- 필수 라이브러리. (DB Client 는 당연히 필수임) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
<!-- 롬복은 그냥 최신 버전으로 함 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
</dependencies>
각 의존성에 대한 설명:
hibernate-core
: JPA 3.1 API
+ Hibernate Core
가 내장된 라이브러리hibernate-hikaricp
: hibernate orm
에 HickariCp
를 적용h2
: H2
DB 사용을 위한 것. version 은 반드시 자신이 설치한 h2 와 일치시킬 것!logback-classic
: 로그를 이쁘게 출력하기 위함lombok
: 개발편의성을 위해 추가위 의존성 중에서
hibernate-core
와db-client
(여기서는h2
)만
필수입니다. 그외 것들은 필수적인 것은 아닙니다.
이후에 화면 상단 우측에 작게 생긴 Load Maven Changes
버틍르
클릭 해줍니다. (아래 그림참고)
resource 디렉토리 내부에...
1. META-INF
디렉토리를 생성하고,
2. 그 안에 persistence.xml
파일을 생성합니다.
그리고 내용을 아래처럼 채워줍니다.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence version="3.0" xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence
https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd">
<persistence-unit name="my-unit">
<!-- https://jakarta.ee/specifications/persistence/3.0/jakarta-persistence-spec-3.0#a12384 참고 -->
<properties>
<property name="jakarta.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="jakarta.persistence.jdbc.url" value="jdbc:h2:tcp://localhost/~/test" />
<property name="jakarta.persistence.jdbc.user" value="sa" />
<property name="jakarta.persistence.jdbc.password" value="sa" />
<!-- ( 이것도 세팅하고 싶으면 하셔도 됩니다. 필수는 아닙니다. )
<property name="jakarta.persistence.lock.timeout" value="100"/>
<property name="jakarta.persistence.query.timeout" value="100"/>
-->
<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.hbm2ddl.auto" value="update" />
<property name="hibernate.physical_naming_strategy" value="org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy"/>
<property name="hibernate.jdbc.batch_size" value="10"/>
</properties>
</persistence-unit>
</persistence>
jdbc.url
, jdbc.password
, jdbc.url
은 자신의 환경에 맞게 세팅해주세요.hibernate.physical_naming_strategy
세팅은 추천사항입니다.camelCase
작성되어 있어도, DB Object 들과 매칭시킬 때는snake_case
로 변환시켜서 서로 매칭시키기 위한 설정입니다.(Java) userNm
⮂ (DB) user_nm
Spring Boot
에서의 기본 전략이기도 합니다.로그가 이쁘게 찍히도록 logback.xml 을 작성하겠습니다.
먼저 resource 디렉토리 하단에 logback.xml
파일을 생성합니다.
그리고 아래처럼 내용을 작성해줍니다.
(추후에 로그가 별로 안 이쁘다고 생각되면 자기 입맛에 맞게 수정하시기 바랍니다)
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta(%-4relative) --- [ %thread{10} ]
%cyan(%logger{20}) : %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.hibernate.SQL" level="info"/>
<!-- hibernate 5 버전에서는 org.hibernate.type.descriptor.sql 였는데 -->
<!-- hibernate 6 버전부터는 org.hibernate.orm.jdbc.bind 로 변경되었습니다. -->
<logger name="org.hibernate.orm.jdbc.bind" level="TRACE"/>
<root level="info">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
테스트를 위한 main 메소드를 갖는 Class 를 생성합니다.
package coding.toast;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.Persistence;
public class MainClass {
public static void main(String[] args) {
// persistence.xml 에 작성된
// <persistence-unit name="my-unit"> 의 name 을
// Persistence.createEntityManagerFactory 메소드의 인자로 전달합니다.
try (EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-unit");
EntityManager em = emf.createEntityManager()) {
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
// 여기에 자기가 테스트해 보고 싶은 코드를 작성합니다.
tx.commit();
} catch (Exception e) {
tx.rollback();
throw new RuntimeException(e);
}
}
}
}
QueryDSL 5.0.0
을 적용해보겠습니다.
이 버전을 사용한 이유는 앞에서도 잠깐 말했지만, spring boot 에서 지정한 버전과 동일하게 하고 싶어서 그런겁니다. (참고링크).
참고로 이 방법은 querydsl 공식 문서의 방식으로하면 계속 에러가 나서
제가 검색해보고 찾아낸 방법이며, 가장 심플한 방법이기도 합니다.
이전에 수정했던 pom.xml 에 이어서 의존성을 추가하겠습니다.
pom.xml 파일에 가서 <dependencies>
태그 안에 아래와 같이
2가지 의존성을 추가해줍니다.
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>5.0.0</version>
<classifier>jakarta</classifier>
</dependency>
이러면 pom.xml 세팅은 끝입니다.
참고: 기존에 JPA2.2 를 쓰시던 분들을 위한 보충 설명
"어라? Annotation Processor 는 등록 안하나?" ... 라고 생각하실 수 있습니다.
위의 의존성 2개만 있다면 안하는 게 맞습니다. 하면 에러나요.
이게 가능한 이유는
querydsl-api:jakarta:5.0.0
의존성을 사용하는 경우에는
해당 라이브러리 안에 이미AnnotationProcessor
와 관련된 내용이 포함되어 있기
때문입니다. (참고 링크)
이로 인해서 결과적으로
target/generated-sources/annotations
폴더 안에
annotation processing
의 처리 결과물, 즉 Q 클래스들이 생성됩니다.
이후에는 저희는 소스상에서 그 Q 클래스를 사용하면 됩니다.
의존성을 추가한 후에는 꼭 아래처럼 순서대로 한번씩 클릭해주시기 바랍니다.
특히 4번을 클릭 안하면 Q 클래스를 import 하지 못하는 경우가 종종 있습니다.
그러니 꼭! 클릭해주시기 바랍니다. 한번하고 이후에는 안해도 됩니다.
이러고 나서 maven compile (1)
을 한번 해줍니다.
그리고 Reload All Maven Project (2)
버튼도 눌러줍니다.
이후에 target 폴더에 정상적으로 Q 클래스가 생성된 것을 확인할 수 있습니다.
소스 상에서 Q
라고만 입력해도 자동완성 목록에서
QueryDSL 의 Q클래스
들이 표출되는 것을 확인할 수 있습니다.
혹시라도 뭔가 잘 안되면,
invalidate cache
를 한번 해주고,
maven reload
목차부터 다시 시도해주시기 바랍니다.
저도 어쩌다 한번씩 안되네요 😅
설정, 세팅에 의해서 고생 중이신 분들에게 도움이 됐길 바라며
이만 글을 마치겠습니다. 긴 글 읽어주셔서 감사합니다.
아래 xml 에서
<artifactId>spring-boot-dependencies</artifactId>
아래에
기재된<version>
값을 자신이 원하는 spring boot 버전에 맞춰주기만 하면 됩니다.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.2.4</version>
</parent>
<groupId>coding.toast</groupId>
<artifactId>jpa3-retry</artifactId>
<version>1.0.0</version>
<properties>
<java.version>21</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-hikaricp</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--querydsl bom 이 spring-boot-dependencies 에 의해서 이미 추가된 상태 -->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>5.0.0</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
<version>5.0.0</version>
<classifier>jakarta</classifier>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<compilerArgs>
<arg>-proc:full</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-XX:+EnableDynamicAgentLoading</argLine>
</configuration>
</plugin>
</plugins>
</build>
</project>