去年,我撰寫了兩篇關於JPA Criteria和Querydsl的文章(參見簡介與元模型文章)。自去年底以來,Spring Boot推出了3.0的重大更新版本。此版本基於Spring Framework 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帶來了眾多變革(詳見Spring Framework 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類別中的變更)。
Spring MVC 5中的HttpStatus
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return buildResponse(BAD_REQUEST, exception);
}
Spring MVC 6中的HttpStatusCode
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
HttpHeaders headers, HttpStatusCode status, WebRequest request) {
return buildResponse(BAD_REQUEST, exception);
}
Spring Boot 3.0.2
Spring Boot 3有許多變更(參見Spring Boot 3.0 Release Notes);其中最重要的包括:
- Java 17(由Spring Framework定義)。
-
升級至Spring Framework 6(如上所述)。
-
升級至Hibernate 6(見下文)。
- 從JavaEE遷移到Jakarta EE的依賴——這對我們來說並不重要,因為我們在這裡不依賴企業級Java,但它可能會影響許多依賴項(例如,servlet 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
在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確實從資料庫中提取了兩條記錄:
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生成器
Hibernate Jpamodelgen 的 Maven 依賴,由 Spring Boot Dependencies 管理,已從 org.hibernate
包移至 org.hibernate.orm
包。參見:
Spring Boot 2.7.5
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
Spring Boot 3.0.2
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>
Liquibase
為完成核心持久化依賴,Liquibase 已從版本 4.9.1 升級至 4.17.2。除 JAX-B 依賴的使用外,無顯著差異。該依賴應使用 Jakarta 的 JAX-B 而非 Javax(參見以下 參考資料)。
Spring Boot 2.7.5
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
Spring Boot 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>
Spring Data JPA 3.0.1
Spring Boot 3.0.2 依賴於 Spring Data Release Train 2022.0.1(參見 Spring Data 2022.0 – Turing 發佈說明),其中使用了 Spring Data JPA 3.0.1,主要變更如下(參見 發佈說明):
- 將 Java 基線切換至 Java 17,
- 將 Jakarta 基線切換至 Jakarta EE 10 和
- 升級至 Hibernate 6
注意:我們之前使用的版本是 2.7.5 版本。
Querydsl 5.0.0
Querydsl 版本未變更,但受到與 Liquibase 類似的影響。依賴項必須從 Jakarta 而非 Javax 使用。因此,Querydsl 依賴項必須使用 jakarta
分類器,而非舊的 jpa
分類器(參見此參考)。
Spring Boot 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>
Spring Boot 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>
結論
本文涵蓋了升級至最新 Spring Boot 3.0.2 的 JPA 和 Querydsl(撰寫本文時)。文章從 Spring Framework 和 Spring Boot 的變更開始。接著,涵蓋了 Hibernate 及其相關技術的所有變更。最後,我們提到了與 Spring Data 3.0.1 和 Querydsl 5.0.0 相關的小變更。
上述完整範例程式碼可在我的GitHub倉庫中找到。
注意:還有一篇前文,Spring Data Elasticsearch 5.0 升級指南,專注於 Spring Boot 3 的 Elasticsearch 類似升級。
Source:
https://dzone.com/articles/upgrade-guide-to-spring-boot-3-for-spring-data-jpa-3-and-querydsl-5