开发者

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

目录
  • 介绍
  • Java17
    • 文本块
    • 记录
  • JPA 3.1
    • UUID 实体属性
    • 新的 JPQL 函数
  • 冬眠 6
    • JDBC 优化
    • 方言增强功能
  • 结论

    介绍

    在本文中,我们将了解如何将现有应用程序迁移到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
        w编程客栈here 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,则默认表将被组织为聚簇索python引,从而使所有这些问题变得更糟。

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

    新的 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

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

    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生成规范模型,即语义查询模型。

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

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

    有关 Hibe开发者_JS学习rnate 语义查询模型的更多详细信息,请查看本文。

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

    例如,您可以使用函数进行不区分大小写的 LIKE 匹配:ilike

    HibernateCriteriaBuilder builder = entityManager
        .unwrap(Session.class)
        .getCriteriaBuilder();
     
    CriteriaQuery<Post> criteria = builder.createQuery(Post.class);
    Root<Post> post = criter编程客栈ia.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

    • 全部联盟
    • 窗口函数
    • 派生表
    • CTE和递归CTE

    方言增强功能

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

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

    此外,您甚至不需要在 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)
                  ->http://www.devze.com  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 
           js                 (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迁移的最佳方式内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜