将应用程序进行Spring6迁移的最佳使用方式
作者:allway2 发布时间:2021-08-28 12:03:58
介绍
在本文中,我们将了解如何将现有应用程序迁移到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 位时间排序的随机 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
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
全部联盟
窗口函数
派生表
CTE和递归CTE
方言增强功能
在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提供了许多优化和新功能,可以满足您的许多日常数据访问需求。
来源:https://blog.csdn.net/allway2/article/details/128068846
猜你喜欢
- 一、前言:垃圾回收:在未来的JDK中可能G1会为ZGC所取代先问自己几个问题:什么是垃圾?垃圾就是堆内存中(范指)没有任何指针指向的对象实体
- 在微服务架构下,我们在完成一个订单流程时经常遇到下面的场景:一个订单创建接口,第一次调用超时了,然后调用方重试了一次在订单创建时,我们需要去
- 水印种类及功能介绍 PDF水印分为两种:文本水印和图片水印。文本水印一般被用在商业领域,提醒读者该文档是受版权保护的,其他人不能抄
- Android Parcelable 源码解析大家都知道,要想在Intent里面传递一些非基本类型的数据,有两种方式,一种实现Parcela
- Android 图片选择可以达到的效果:1.第一个图片的位置放照相机,点击打开照相机2.其余的是显示全部存储的图片,点击一次是查
- spring Session 提供了一套用于管理用户 session 信息的API和实现。Spring Session为企业级Java应用的
- 在逆向一个Android程序时,如果只是盲目的分析需要阅读N多代码才能找到程序的关键点或Hook点,本文将分享一下如何快速的找到APP程序的
- Mybatis plus中like查询问题又谈到了Mybatis plus了,真的很是痛心疾首,在做模糊查询的时候出现了一个问题,版本还是2
- 概念Java中的集合就是一种容器,可以容纳不同种类的数据,这些容纳是建立在未知的基础上。优点1.可以动态保存任意多个对象,使用比较方便。2.
- 前言在上网的时候我们常常遇到文件上传的情况,例如上传头像、上传资料等;当然除了上传,遇见下载的情况也很多,接下来看看我们 servlet 中
- finalize方法是什么finalize方法是Object的protected方法,Object的子类们可以覆盖该方法以实现资源清理工作,
- 思路如下:给定一个含有n个元素的整型数组a,求a中所有元素的和。问题的难点在于如何使用递归上。如果使用递归,则需要考虑如何进行递归执行的开始
- 流程图 * vs过滤器 * 是SpringMVC的技术过滤器的Servlet的技术先过过滤器,过滤器过完才到DispatcherServle
- 实践过程效果代码public partial class Form1 : Form{ public Form1()
- 一、需求Jenkins大多数情况下都是用来部署Java项目,Java项目有一个特点是>需要编译和打包的,一般情况下编译和打包都是用ma
- 在网上看到一些人写关于条形码的代码都很长,有的甚至拿来卖,所以查了下资料,希望能对大家有帮助。我的实现原理是:其实Windows本身就有一个
- 本文实例讲述了Java链表(Linked List)基本原理与实现方法。分享给大家供大家参考,具体如下:在分析链表之前,我们先来对之前的动态
- DataBindings属性是很多控件都有的属性,作用有2方面。一方面是用于与数据库的数据进行绑定,进行数据显示。另一方面用于与控件或类的对
- Android系统支持的颜色是由4个值组成的,前3个为RGB,也就是我们常说的三原色(红、绿、蓝),最后一个值是A,也就是Alpha。这4个
- StringUtils.isBlank()的使用在校验一个String类型的变量是否为空时,可以使用StringUtils.isBlank方