验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

如何将应用程序进行Spring6迁移

阅读:842 来源:乙速云 作者:代码code

如何将应用程序进行Spring6迁移

      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 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 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 位时间排序的随机 TSID。UUID

      新的 JPQL 函数

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

      但是,我发现最有用的是日期/时间函数:EXTRACT

      List 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 持久性不支持的功能(如派生表或公用表表达式)来增强条件查询。

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

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

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

      HibernateCriteriaBuilder builder = entityManager
          .unwrap(Session.class)
          .getCriteriaBuilder();
       
      CriteriaQuery criteria = builder.createQuery(Post.class);
      Root post = criteria.from(Post.class);
       
      ParameterExpression parameterExpression = builder
          .parameter(String.class);
           
      List 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 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

      情况不再如此,因为现在实体对象引用重复数据删除是自动完成的,因此您的查询不再需要关键字:JOIN FETCHDISTINCT

      List 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();
    分享到:
    *特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
    相关文章
    {{ v.title }}
    {{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
    你可能感兴趣
    推荐阅读 更多>