將應(yīng)用程序進(jìn)行Spring6遷移的最佳使用方式
介紹
在本文中,我們將了解如何將現(xiàn)有應(yīng)用程序遷移到Spring 6以及如何充分利用此升級。
本文中的提示基于我在Hypersistence Optimizer和高性能 Java Persistence 項(xiàng)目中添加對 Spring 6 的支持所做的工作。
Java17
首先,Spring 6 將最低 Java 版本提升到 17 個,這太棒了,因?yàn)槟悻F(xiàn)在可以使用文本塊和記錄。
文本塊
多虧了文本塊,您的注釋將更具可讀性:@Query
@Query(""" select p from Post p left join fetch p.comments where p.id between :minId and :maxId """) List<Post> findAllWithComments( @Param("minId") long minId, @Param("maxId") long maxId );
有關(guān) Java 文本塊的更多詳細(xì)信息,請查看本文。
記錄
Java Records 非常適合 DTO 投影。例如,你可以像這樣定義 aclass:PostRecord
public record PostCommentRecord( Long id, String title, String review ) {}
然后,您可以使用 Spring Data JPA 查詢方法獲取對象:PostCommentRecord
@Query(""" select new PostCommentRecord( p.id as id, p.title as title, c.review as review ) from PostComment c join c.post p where p.title like :postTitle order by c.id """) List<PostCommentRecord> findCommentRecordByTitle( @Param("postTitle") String postTitle );
我們之所以可以在 JPQL 構(gòu)造函數(shù)表達(dá)式中使用 theJava 的簡單名稱,是因?yàn)槲覐?a rel="external nofollow" target="_blank">Hibernate Type 項(xiàng)目中注冊了以下內(nèi)容:PostCommentRecordClassClassImportIntegrator
properties.put( "hibernate.integrator_provider", (IntegratorProvider) () -> Collections.singletonList( new ClassImportIntegrator( List.of( PostCommentRecord.class ) ) ) );
有關(guān) Java 記錄的更多詳細(xì)信息,請查看本文。
這還不是全部!Java 17 改進(jìn)了 forand 的錯誤消息,并添加了模式匹配 forand。NullPointerExceptionswitchinstanceOf
JPA 3.1
默認(rèn)情況下,Spring 6 使用 Hibernate 6.1,而 Hibernate 6.1 又使用 Jakarta Persistence 3.1。
現(xiàn)在,3.0版本標(biāo)志著從Java持久性到Jakarta Patersistence的遷移,因此,出于這個原因,您必須將軟件包導(dǎo)入替換為命名空間。javax.persistencejakarta.persistence
這是遷移到 JPA 3 必須進(jìn)行的最重要的更改。與此同時,發(fā)布了3.1版本,但這個版本只包括Hibernate已經(jīng)支持的一些小改進(jìn)。
UUID 實(shí)體屬性
例如,JPA 3 現(xiàn)在支持基本類型:UUID
@Column( name = "external_id", columnDefinition = "UUID NOT NULL" ) private UUID externalId;
您甚至可以將它們用作實(shí)體標(biāo)識符:
@Id @GeneratedValue(strategy = GenerationType.UUID) private UUID id;
但這只是一個糟糕的主意,因?yàn)槭褂?anfor 主鍵會導(dǎo)致很多問題:UUID
- 索引頁將很少填充,因?yàn)槊總€新的 UUID 都將在 B+樹聚集索引中隨機(jī)添加。
- 由于主鍵值的隨機(jī)性,將會有更多的頁面拆分
- UUID很大,需要的字節(jié)數(shù)是列的兩倍。它不僅影響主鍵,還影響所有關(guān)聯(lián)的外鍵。
bigint
此外,如果您使用的是SQL Server,MySQL或MariaDB,則默認(rèn)表將被組織為聚簇索引,從而使所有這些問題變得更糟。
因此,最好避免使用 for 實(shí)體標(biāo)識符。如果您確實(shí)需要從應(yīng)用程序生成唯一標(biāo)識符,那么最好使用64 位時間排序的隨機(jī) TSID。UUID
新的 JPQL 函數(shù)
JPQL 通過許多新功能得到了增強(qiáng),例如,,,,,,數(shù)字函數(shù)。CEILINGFLOOREXPLNPOWERROUNDSIGN
但是,我發(fā)現(xiàn)最有用的是日期/時間函數(shù):EXTRACT
List<Post> posts = entityManager.createQuery(""" select p from Post p where EXTRACT(YEAR FROM createdOn) = :year """, Post.class) .setParameter("year", Year.now().getValue()) .getResultList();
這很有用,因?yàn)槿掌?時間處理通常需要特定于數(shù)據(jù)庫的函數(shù),并且擁有一個可以呈現(xiàn)適當(dāng)?shù)奶囟ㄓ跀?shù)據(jù)庫的函數(shù)的泛型函數(shù)肯定很方便。
可自動關(guān)閉的實(shí)體管理器和實(shí)體管理器工廠
雖然Hibernateand已經(jīng)擴(kuò)展了接口,但現(xiàn)在JPAand也遵循了這種做法:SessionSessionFactoryAutoClosableEntityManagerEntityManagerFactory
Although you might rarely need to rely on that because Spring takes care of the on your behalf, it’s very handy when you have to process the programmatically.EntityManagerEntityManager
冬眠 6
雖然Java 17和JPA 3.1為您帶來了一些功能,但Hibernate 6提供了大量的增強(qiáng)功能。
JDBC 優(yōu)化
以前,Hibernate使用關(guān)聯(lián)的列別名讀取JDBC列值,這被證明很慢。出于這個原因,Hibernate 6 已切換到按基礎(chǔ) SQL 投影中的位置讀取基礎(chǔ)列值。ResultSet
除了速度更快之外,進(jìn)行此更改還有一個非常好的副作用?;A(chǔ) SQL 查詢現(xiàn)在更具可讀性。
例如,如果您在 Hibernate 5 上運(yùn)行此 JPQL 查詢:
Post post = entityManager.createQuery(""" select p from Post p join fetch p.comments where p.id = :id """, Post.class) .setParameter("id", 1L) .getSingleResult();
將執(zhí)行以下 SQL 查詢:
SELECT bidirectio0_.id AS id1_0_0_, comments1_.id AS id1_1_1_, bidirectio0_.title AS title2_0_0_, comments1_.post_id AS post_id3_1_1_, comments1_.review AS review2_1_1_, comments1_.post_id AS post_id3_1_0__, comments1_.id AS id1_1_0__ FROM post bidirectio0_ INNER JOIN post_comment comments1_ ON bidirectio0_.id=comments1_.post_id WHERE bidirectio0_.id=1
如果您在Hibernate 6上運(yùn)行相同的JPQL,將如何改為運(yùn)行以下SQL查詢:
SELECT p1_0.id, c1_0.post_id, c1_0.id, c1_0.review, p1_0.title FROM post p1_0 JOIN post_comment c1_0 ON p1_0.id=c1_0.post_id WHERE p1_0.id = 1
好多了,對吧?
語義查詢模型和條件查詢
Hibernate 6提供了一個全新的實(shí)體查詢解析器,能夠從JPQL和Criteria API生成規(guī)范模型,即語義查詢模型。
通過統(tǒng)一實(shí)體查詢模型,現(xiàn)在可以使用 Jakarta 持久性不支持的功能(如派生表或公用表表達(dá)式)來增強(qiáng)條件查詢。
有關(guān) Hibernate 語義查詢模型的更多詳細(xì)信息,請查看本文。
舊的休眠標(biāo)準(zhǔn)已被刪除,但標(biāo)準(zhǔn) API 已通過 提供許多新功能得到增強(qiáng)。HibernateCriteriaBuilder
例如,您可以使用函數(shù)進(jìn)行不區(qū)分大小寫的 LIKE 匹配:ilike
HibernateCriteriaBuilder builder = entityManager .unwrap(Session.class) .getCriteriaBuilder(); CriteriaQuery<Post> criteria = builder.createQuery(Post.class); Root<Post> post = criteria.from(Post.class); ParameterExpression<String> parameterExpression = builder .parameter(String.class); List<Post> posts = entityManager.createQuery( criteria .where( builder.ilike( post.get(Post_.TITLE), parameterExpression) ) .orderBy( builder.asc( post.get(Post_.ID) ) ) ) .setParameter(parameterExpression, titlePattern) .setMaxResults(maxCount) .getResultList();
但是,這只是一個基本示例。使用新的,您現(xiàn)在可以渲染:HibernateCriteriaBuilder
方言增強(qiáng)功能
在Hibernate 5中,您必須根據(jù)底層數(shù)據(jù)庫版本選擇大量版本,這在Hibernate 6中得到了極大的簡化:Dialect
此外,您甚至不需要在 Spring 配置中提供,因?yàn)樗梢詮?JDBC 解析。DialectDatabaseMetaData
有關(guān)此主題的更多詳細(xì)信息,請查看此文章。
自動重復(fù)數(shù)據(jù)刪除
您還記得在使用時為實(shí)體重復(fù)數(shù)據(jù)刪除提供關(guān)鍵字是多么煩人嗎?DISTINCTJOIN FETCH
List<Post> posts = entityManager.createQuery(""" select distinct p from Post p left join fetch p.comments where p.title = :title """, Post.class) .setParameter("title", "High-Performance Java Persistence") .setHint(QueryHints.HINT_PASS_DISTINCT_THROUGH, false) .getResultList();
如果你忘記發(fā)送提示,那么Hibernate 5會將關(guān)鍵字傳遞給SQL查詢,并導(dǎo)致執(zhí)行計劃運(yùn)行一些額外的步驟,這些步驟只會讓你的查詢變慢:PASS_DISTINCT_THROUGHDISTINCT
Unique (cost=23.71..23.72 rows=1 width=1068) (actual time=0.131..0.132 rows=2 loops=1) -> Sort (cost=23.71..23.71 rows=1 width=1068) (actual time=0.131..0.131 rows=2 loops=1) Sort Key: p.id, pc.id, p.created_on, pc.post_id, pc.review Sort Method: quicksort Memory: 25kB -> Hash Right Join (cost=11.76..23.70 rows=1 width=1068) (actual time=0.054..0.058 rows=2 loops=1) Hash Cond: (pc.post_id = p.id) -> Seq Scan on post_comment pc (cost=0.00..11.40 rows=140 width=532) (actual time=0.010..0.010 rows=2 loops=1) -> Hash (cost=11.75..11.75 rows=1 width=528) (actual time=0.027..0.027 rows=1 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on post p (cost=0.00..11.75 rows=1 width=528) (actual time=0.017..0.018 rows=1 loops=1) Filter: ( (title)::text = 'High-Performance Java Persistence eBook has been released!'::text ) Rows Removed by Filter: 3
有關(guān) JPA 中如何工作的更多詳細(xì)信息,請同時閱讀本文。
DISTINCT
情況不再如此,因?yàn)楝F(xiàn)在實(shí)體對象引用重復(fù)數(shù)據(jù)刪除是自動完成的,因此您的查詢不再需要關(guān)鍵字:JOIN FETCHDISTINCT
List<Post> posts = entityManager.createQuery(""" select p from Post p left join fetch p.comments where p.title = :title """, Post.class) .setParameter("title", "High-Performance Java Persistence") .getResultList();
結(jié)論
Spring 6 真的值得升級到。除了受益于Java 17提供的所有語言優(yōu)化之外,所有其他框架依賴項(xiàng)還提供了大量新功能,這些依賴項(xiàng)已集成到Spring 6中。
例如,Hibernate 6提供了許多優(yōu)化和新功能,可以滿足您的許多日常數(shù)據(jù)訪問需求。
到此這篇關(guān)于將應(yīng)用程序進(jìn)行Spring6遷移的最佳方式的文章就介紹到這了,更多相關(guān)Spring6遷移的最佳方式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Java中配置ElasticSearch集群環(huán)境賬號密碼的問題
這篇文章主要介紹了Java中配置ElasticSearch集群環(huán)境賬號密碼的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04IDEA運(yùn)行SSM項(xiàng)目的超詳細(xì)圖解教程
SSM項(xiàng)目部署其實(shí)很簡單,下面這篇文章主要給大家介紹了關(guān)于IDEA運(yùn)行SSM項(xiàng)目的超詳細(xì)圖解教程,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10基于Java實(shí)現(xiàn)緩存Cache的深入分析
本篇文章是對Java實(shí)現(xiàn)緩存Cache進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06java開發(fā)使用StringUtils.split避坑詳解
這篇文章主要為大家介紹了java開發(fā)使用StringUtils.split避坑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11springboot實(shí)現(xiàn)多文件上傳功能
這篇文章主要為大家詳細(xì)介紹了springboot實(shí)現(xiàn)多文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-11-11詳解Java中AC自動機(jī)的原理與實(shí)現(xiàn)
AC自動機(jī)是一個多模式匹配算法,在模式匹配領(lǐng)域被廣泛應(yīng)用。本文將詳細(xì)為大家介紹AC自動機(jī)的原理與實(shí)現(xiàn)方法,感興趣的可以了解一下2022-05-05