작년에 저는 JPA Criteria와 Querydsl에 관한 두 篇文章을 작성했습니다(소개서 소개 및 메타모델 기사 참조). 작년 말부터 스프링 부트 3의 새로운 주요 릴리스가 있었습니다. 이 릴리스는 여러 중요한 변경사항과 문제를 기반으로 하는 스프링 프레임워크 6을 기반으로 합니다. 업그레이드할 때 고려해야 합니다.
이 기사의 목적은 sat-jpa 프로젝트(SAT 프로젝트)를 업그레이드할 때 이러한 변경 사항을 강조하는 것입니다. 여기서 사용되는 기술은 다음과 같습니다:
- Spring Boot 3.0.2,
- Hibernate 6.1.6.Final
- Spring Data JPA 3.0.1 및
- Querydsl 5.0.0.
Spring Framework 6.0.4
Spring Framework 6에는 많은 변경 사항이 있습니다(참조 스프링 프레임워크 6.x의 새로운 기능), 주요 변경 사항은 다음과 같습니다:
- Java 기준선을 Java 17로 전환(이 기사를 작성할 당시 마지막 Java LTS) – 즉, 사용해야 하는 최소 Java 버전입니다.
- Jakarta 기준선을 Jakarta EE 9+로 전환.
또한 SAT 프로젝트에서 사용되는 Spring MVC에 미미한 변경이 단지 하나 있습니다.
Spring MVC 6.0.4
모든 메서드의 시그니처가 ResponseEntityExceptionHandler
클래스에서 변경되었습니다. status
인수가 HttpStatus
에서 HttpStatusCode
타입으로 변경되었습니다 (이 변경사항은 CityExceptionHandler 클래스에서 확인할 수 있습니다).
스프링 MVC 5의 HttpStatus
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return buildResponse(BAD_REQUEST, exception);
}
스프링 MVC 6의 HttpStatusCode
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
HttpHeaders headers, HttpStatusCode status, WebRequest request) {
return buildResponse(BAD_REQUEST, exception);
}
스프링 부트 3.0.2
스프링 부트 3에는 많은 변경 사항이 있습니다 (참조: Spring Boot 3.0 Release Notes); 가장 중요한 것들은 다음과 같습니다:
- 스프링 프레임워크에 의해 정의된 Java 17.
-
위에서 언급한 바와 같이 스프링 프레임워크 6으로 업그레이드합니다.
-
하이버네이트 6으로 업그레이드하세요 (아래 참조).
- JavaEE에서 Jakarta EE 종속성으로의 마이그레이션 – 우리 경우에는 엔터프라이즈 자바에 의존하지 않으므로 중요하지 않지만, 서블릿 API, 검증, 지속성, JMS 등 많은 종속성에 영향을 줄 수 있습니다.
- Spring MVC 6에서
ResponseEntityExceptionHandler
클래스의 약간의 변경이 있습니다 (다음 부분 참조).
간단한 Jakarta EE 변경 사항부터 시작하여 그 후 지속성에 집중합시다.
Jakarta EE 종속성
주요 변경 사항은 Java EE에서 Jakarta EE 종속성으로의 마이그레이션입니다. Spring Framework 6은 Jakarta EE 9를 기준으로 설정했지만 (참조: Spring Framework 6.x의 새로운 기능), Spring Boot 3은 이미 많은 API (예: Servlet 또는 JPA 등)에 대해 Jakarta EE 10을 사용합니다 (참조: Spring Boot 3.0 릴리스 노트).
따라서 jakarta
패키지의 다른 클래스를 사용하는 모든 클래스는 javax
패키지의 동일한 클래스로 전환해야 합니다 (예: PostConstruct 또는 Entity 어노테이션 참조).
Javax 임포트
import javax.annotation.PostConstruct;
import javax.persistence.Entity;
Jakarta 임포트
import jakarta.annotation.PostConstruct;
import jakarta.persistence.Entity;
Hibernate 6.1.6
Spring Boot 3의 또 다른 주요 변경 사항은 Hibernate 5.6에서 Hibernate 6.1로의 업그레이드입니다. Hibernate 6.1에 대한 세부 사항은 여기 또는 릴리스 노트 내에서 확인할 수 있습니다.
솔직히 말하면, 결과 크기가 다르다는 이유로 실패한 테스트를 수정해야 하기 전까지는 이 변경에 주의를 기울이지 않았습니다 (코드 CountryRepositoryCustomTests
클래스에서 수정을 참조). 새로운 Hibernate 6의 구현은 이전보다 적은 엔티티를 반환합니다.
이 조사를 바탕으로 두 가지 변경 사항을 언급할 가치가 있습니다. 먼저 로깅부터 시작하겠습니다.
로깅
Hibernate 로거가 org.hibernate.type
에서 org.hibernate.orm.jdbc
로 변경되었습니다 (참조 이 참조 및 이 참조).
참고: 사용 가능한 모든 구성 항목은 org.hibernate.cfg.AvailableSettings
클래스에서 찾을 수 있습니다.
Hibernate 5
숨겨진 값과 추출된 값에 대한 단일 로거가 있었습니다.
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
Hibernate 6
Hibernate 6은 기본 패키지를 변경하고 두 개의 다른 로거로 분리하여 어떤 값을 로깅해야 하는지 구분하도록 변경했습니다.
logging.level.org.hibernate.orm.jdbc.bind=trace
logging.level.org.hibernate.orm.jdbc.extract=trace
의미론적 쿼리 모델
로깅이 수정됨에 따라 Hibernate가 DB에서 두 개의 레코드를 실제로 추출한다는 것이 확인되었습니다.
2023-01-25T08:40:18.819+01:00 INFO 6192 --- [ main] c.g.a.s.j.c.CountryRepositoryCustomTests : Started CountryRepositoryCustomTests in 4.678 seconds (process running for 5.745)
Hibernate: select c2_0.id,c2_0.name from city c1_0 join country c2_0 on c2_0.id=c1_0.country_id where c1_0.name like ? escape '!' and c1_0.state like ? escape '!'
2023-01-25T08:40:19.221+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.222+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([2] : [VARCHAR]) - [USA]
2023-01-25T08:40:19.240+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.241+01:00 TRACE 6192 --- [ main] org.hibernate.orm.jdbc.extract : extracted value ([2] : [VARCHAR]) - [USA]
그러나 테스트는 Hibernate로부터 단일 엔티티만 받음을 이러한 디버깅 스크린샷에서 확인할 수 있습니다.
변경된 동작은 Hibernate 6에 도입된 새로운 자동 중복 제거를 포함한 의미론적 쿼리 모델 (참조 의미론적 쿼리 모델 부분) 때문입니다 (코드>org.hibernate.sql.results.spi.ListResultsConsumer 클래스의 라인 178 참조). Hibernate 6은 이제 중복 제거된 결과를 반환합니다.
Hibernate JPA 생성기
하이버네이트 Jpamodelgen 마이크로모듈 의존성이 스프링 부트 의존성에 의해 관리되며, org.hibernate
에서 org.hibernate.orm
패키지로 이동되었습니다. 참고:
스프링 부트 2.7.5
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
스프링 부트 3.0.2
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
Liquibase
코어 지속성 의존성을 마무리하기 위해 Liquibase가 버전 4.9.1에서 4.17.2로 업그레이드되었습니다. JAX-B 의존성 사용을 제외하고는 큰 차이가 없습니다. 의존성은 Javax 대신 자카르타의 JAX-B를 사용해야 합니다(다음 참조 참조).
스프링 부트 2.7.5
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
스프링 부트 3.0.2
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<exclusions>
<exclusion> <!-- due to SB 3.0 switch to Jakarta -->
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
스프링 데이터 JPA 3.0.1
스프링 부트 3.0.2는 키 변경 사항과 함께 스프링 데이터 JPA 3.0.1을 사용하는 스프링 데이터 릴리스 트레인 2022.0.1에 의존합니다(다음 스프링 데이터 2022.0 – 튜링 릴리스 노트 참조).릴리스 노트:
- 자바 기준선을 자바 17로 전환,
- 자카르타 기준선을 자카르타 EE 10으로 전환 등
- 하이버네이트 6으로 업그레이드
참고: 이전에 사용된 버전(우리 경우)은 2.7.5 버전이었습니다.
Querydsl 5.0.0
Querydsl 버전은 변경되지 않았지만, Liquibase와 비슷한 방식으로 영향을 받았습니다. 의존성은 Javax 대신 Jakarta에서 사용해야 합니다. 따라서 Querydsl 의존성은 이전의 jpa
클래스라이터 대신 jakarta
클래스라이터를 사용해야 합니다(이 참조 참고).
스프링 부트 2.7.5
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jpa</classifier>
<scope>provided</scope>
</dependency>
스프링 부트 3.0.2
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
<version>${querydsl.version}</version>
<classifier>jakarta</classifier>
</dependency>
결론
이 글에서는 작성 당시 최신 스프링 부트 3.0.2에 대한 JPA와 Querydsl 업그레이드를 다루었습니다. 글은 스프링 프레임워크와 스프링 부트의 변경 사항으로 시작하였습니다. 다음으로 하이버네이트 및 관련 기술의 모든 변경 사항을 다루었습니다. 마지막으로 스프링 데이터 3.0.1과 Querydsl 5.0.0과 관련된 사소한 변경 사항에 대해 언급하였습니다.
위에서 설명한 전체 소스 코드는 제 GitHub 저장소에서 확인하실 수 있습니다.
참고: 이전 글로는 스프링 데이터 Elasticsearch 5.0 업그레이드 가이드가 있으며, 스프링 부트 3과 Elasticsearch의 유사한 업그레이드에 초점을 맞추고 있습니다.
Source:
https://dzone.com/articles/upgrade-guide-to-spring-boot-3-for-spring-data-jpa-3-and-querydsl-5