将应用程序进行Spring6迁移的最佳使用方式

 更新时间:2023年03月27日 11:13:31   作者:allway2  
这篇文章主要介绍了将应用程序进行Spring6迁移的最佳方式,以及如何充分利用此升级,需要的朋友可以参考下,如有错误的地方还请指正

介绍

在本文中,我们将了解如何将现有应用程序迁移到Spring 6以及如何充分利用此升级。

本文中的提示基于我在Hypersistence Optimizer和高性能 Java Persistence 项目中添加对 Spring 6 的支持所做的工作。

Java17

首先,Spring 6 将最低 Java 版本提升到 17 个,这太棒了,因为你现在可以使用文本块和记录。

文本块

多亏了文本块,您的注释将更具可读性:@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
);

有关 Java 文本块的更多详细信息,请查看本文

记录

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 构造函数表达式中使用 theJava 的简单名称,是因为我从Hibernate Type 项目中注册了以下内容:PostCommentRecordClassClassImportIntegrator

properties.put(
    "hibernate.integrator_provider",
    (IntegratorProvider) () -> Collections.singletonList(
        new ClassImportIntegrator(
            List.of(
                PostCommentRecord.class
            )
        )
    )
);

有关 Java 记录的更多详细信息,请查看本文

这还不是全部!Java 17 改进了 forand 的错误消息,并添加了模式匹配 forand。NullPointerExceptionswitchinstanceOf

JPA 3.1

默认情况下,Spring 6 使用 Hibernate 6.1,而 Hibernate 6.1 又使用 Jakarta Persistence 3.1。

现在,3.0版本标志着从Java持久性到Jakarta Patersistence的迁移,因此,出于这个原因,您必须将软件包导入替换为命名空间。javax.persistencejakarta.persistence

这是迁移到 JPA 3 必须进行的最重要的更改。与此同时,发布了3.1版本,但这个版本只包括Hibernate已经支持的一些小改进。

UUID 实体属性

例如,JPA 3 现在支持基本类型:UUID

@Column(
    name = "external_id",
    columnDefinition = "UUID NOT NULL"
)
private UUID externalId;

您甚至可以将它们用作实体标识符:

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

但这只是一个糟糕的主意,因为使用 anfor 主键会导致很多问题:UUID

  • 索引页将很少填充,因为每个新的 UUID 都将在 B+树聚集索引中随机添加。
  • 由于主键值的随机性,将会有更多的页面拆分
  • UUID很大,需要的字节数是列的两倍。它不仅影响主键,还影响所有关联的外键。bigint

此外,如果您使用的是SQL Server,MySQL或MariaDB,则默认表将被组织为聚簇索引,从而使所有这些问题变得更糟。

因此,最好避免使用 for 实体标识符。如果您确实需要从应用程序生成唯一标识符,那么最好使用64 位时间排序的随机 TSIDUUID

新的 JPQL 函数

JPQL 通过许多新功能得到了增强,例如,,,,,,数字函数。CEILINGFLOOREXPLNPOWERROUNDSIGN

但是,我发现最有用的是日期/时间函数: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();

这很有用,因为日期/时间处理通常需要特定于数据库的函数,并且拥有一个可以呈现适当的特定于数据库的函数的泛型函数肯定很方便。

可自动关闭的实体管理器和实体管理器工厂

虽然Hibernateand已经扩展了接口,但现在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提供了大量的增强功能。

JDBC 优化

以前,Hibernate使用关联的列别名读取JDBC列值,这被证明很慢。出于这个原因,Hibernate 6 已切换到按基础 SQL 投影中的位置读取基础列值。ResultSet

除了速度更快之外,进行此更改还有一个非常好的副作用。基础 SQL 查询现在更具可读性。

例如,如果您在 Hibernate 5 上运行此 JPQL 查询:

Post post = entityManager.createQuery("""
    select p
    from Post p
    join fetch p.comments
    where p.id = :id
    """, Post.class)
.setParameter("id", 1L)
.getSingleResult();

将执行以下 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上运行相同的JPQL,将如何改为运行以下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提供了一个全新的实体查询解析器,能够从JPQL和Criteria API生成规范模型,即语义查询模型。

通过统一实体查询模型,现在可以使用 Jakarta 持久性不支持的功能(如派生表或公用表表达式)来增强条件查询。

有关 Hibernate 语义查询模型的更多详细信息,请查看本文

旧的休眠标准已被删除,但标准 API 已通过 提供许多新功能得到增强。HibernateCriteriaBuilder

例如,您可以使用函数进行不区分大小写的 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();

但是,这只是一个基本示例。使用新的,您现在可以渲染:HibernateCriteriaBuilder

方言增强功能

在Hibernate 5中,您必须根据底层数据库版本选择大量版本,这在Hibernate 6中得到了极大的简化:Dialect

此外,您甚至不需要在 Spring 配置中提供,因为它可以从 JDBC 解析。DialectDatabaseMetaData

有关此主题的更多详细信息,请查看此文章

自动重复数据删除

您还记得在使用时为实体重复数据删除提供关键字是多么烦人吗?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();

如果你忘记发送提示,那么Hibernate 5会将关键字传递给SQL查询,并导致执行计划运行一些额外的步骤,这些步骤只会让你的查询变慢: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

有关 JPA 中如何工作的更多详细信息,请同时阅读本文DISTINCT

情况不再如此,因为现在实体对象引用重复数据删除是自动完成的,因此您的查询不再需要关键字: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();

结论

Spring 6 真的值得升级到。除了受益于Java 17提供的所有语言优化之外,所有其他框架依赖项还提供了大量新功能,这些依赖项已集成到Spring 6中。

例如,Hibernate 6提供了许多优化和新功能,可以满足您的许多日常数据访问需求。

到此这篇关于将应用程序进行Spring6迁移的最佳方式的文章就介绍到这了,更多相关Spring6迁移的最佳方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java使用gzip实现文件解压缩示例

    java使用gzip实现文件解压缩示例

    这篇文章主要介绍了java使用gzip实现文件解压缩示例,需要的朋友可以参考下
    2014-03-03
  • Java汉字转成汉语拼音工具类

    Java汉字转成汉语拼音工具类

    这篇文章主要为大家详细介绍了Java汉字转成汉语拼音工具类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • mybatis 查询返回Map<String,Object>类型

    mybatis 查询返回Map<String,Object>类型

    本文主要介绍了mybatis 查询返回Map<String,Object>类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Java设计模式之备忘录模式使用详解

    Java设计模式之备忘录模式使用详解

    这篇文章主要介绍了Java设计模式中备忘录模式的使用,备忘录设计模式也叫作快照模式,主要用于实现防丢失、撤销、恢复等功能,本文将通过示例为大家讲解备忘录模式的定义与使用,需要的同学可以参考一下
    2024-02-02
  • Java中如何使用Gson将对象转换为JSON字符串

    Java中如何使用Gson将对象转换为JSON字符串

    这篇文章主要给大家介绍了关于Java中如何使用Gson将对象转换为JSON字符串的相关资料,Gson是Google的一个开源项目,可以将Java对象转换成JSON,也可能将JSON转换成Java对象,需要的朋友可以参考下
    2023-11-11
  • 详解spring与jdbc整合操作

    详解spring与jdbc整合操作

    这篇文章主要为大家详细介绍了spring与jdbc整合操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • 上传自己的jar包到maven中央仓库的快速操作方法

    上传自己的jar包到maven中央仓库的快速操作方法

    网络上可以搜索到很多jar包到中央仓库,但是都不是多适合自己的项目,于是自己动手写个,本文档通过sonatype上传jar包至maven中央仓库,Sonatype通过JIRA来管理OSSRH仓库,具体实例代码跟随小编一起看看吧
    2021-08-08
  • java中的String定义的字面量最大长度是多少

    java中的String定义的字面量最大长度是多少

    这篇文章主要介绍了java中的String定义的字面量最大长度是多少,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • Java中的StampedLock实现原理详解

    Java中的StampedLock实现原理详解

    这篇文章主要介绍了Java中的StampedLock实现原理详解,ReentrantReadWriteLock采用悲观读,第一个读线程拿到锁后,第二个/第三个读线程可以拿到锁,特别是在读线程很多,写线程很少时,需要的朋友可以参考下
    2024-01-01
  • 浅谈Java中的参数传递问题

    浅谈Java中的参数传递问题

    这篇文章主要介绍了Java中的参数传递问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04

最新评论