JPA 查询的类型
admin
2024-03-22 13:55:24
0

1. 概述

在本教程中,我们将讨论不同类型的JPA查询。此外,我们将专注于比较它们之间的差异,并扩展每个它们的优缺点。

2. 设置

首先,让我们定义将用于本文所有示例的UserEntity类:

@Table(name = "users")
@Entity
public class UserEntity {@Idprivate Long id;private String name;//Standard constructor, getters and setters.}

JPA 查询有三种基本类型:

  • Query,用 Java 持久性查询语言 (JPQL) 语法编写
  • NativeQuery,用纯SQL语法编写
  • 标准 API 查询,通过不同方法以编程方式构造

让我们探索它们。

3.查询

查询在语法上类似于 SQL,通常用于执行 CRUD 操作:

public UserEntity getUserByIdWithPlainQuery(Long id) {Query jpqlQuery = getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id");jpqlQuery.setParameter("id", id);return (UserEntity) jpqlQuery.getSingleResult();
}

查询从用户表中检索匹配的记录,并将其映射到用户实体对象。

还有两个额外的查询子类型:

  • 类型化查询
  • 命名查询

让我们看看它们的实际效果。

3.1.类型查询

我们需要注意前面示例中的return语句。JPA 无法推断查询结果类型是什么,因此,我们必须强制转换。

但是,JPA 提供了一个特殊的 Query 子类型,称为TypedQuery。如果我们事先知道查询结果类型,则始终首选此操作。此外,它使我们的代码更可靠,更易于测试。

让我们看一个TypedQuery替代方案,与我们的第一个示例相比:

public UserEntity getUserByIdWithTypedQuery(Long id) {TypedQuery typedQuery= getEntityManager().createQuery("SELECT u FROM UserEntity u WHERE u.id=:id", UserEntity.class);typedQuery.setParameter("id", id);return typedQuery.getSingleResult();
}

这样,我们可以免费获得更强的键入,避免将来可能的转换异常。

3.2.命名查询

虽然我们可以在特定方法上动态定义Query,但它们最终会发展成为难以维护的代码库。如果我们可以将一般用法查询保存在一个集中的、易于阅读的地方会怎样?

JPA还让我们用另一个称为NamedQueryQuery子类型来解决这个问题。

我们可以在orm.xml或属性文件中定义NamedQuery

此外,我们可以在实体类本身上定义NamedQuery,从而提供一种集中、快速且简单的方法来读取和查找实体的相关查询。

所有命名查询都必须具有唯一的名称。

让我们看看如何将NamedQuery添加到我们的UserEntity类中:

@Table(name = "users")
@Entity
@NamedQuery(name = "UserEntity.findByUserId", query = "SELECT u FROM UserEntity u WHERE u.id=:userId")
public class UserEntity {@Idprivate Long id;private String name;//Standard constructor, getters and setters.}

如果我们在版本 8 之前使用 Java,@NamedQuery注解必须分组在@NamedQueries注解中。从 Java 8 开始,我们可以简单地在Entity类中重复@NamedQuery注释。

使用NamedQuery非常简单:

public UserEntity getUserByIdWithNamedQuery(Long id) {Query namedQuery = getEntityManager().createNamedQuery("UserEntity.findByUserId");namedQuery.setParameter("userId", id);return (UserEntity) namedQuery.getSingleResult();
}

4.原生查询

NativeQuery只是一个SQL查询。这些使我们能够释放数据库的全部功能,因为我们可以使用 JPQL 限制语法中不可用的专有功能。

这是有代价的。我们使用NativeQuery失去了应用程序的数据库可移植性,因为我们的 JPA 提供程序无法再从数据库实现或供应商中抽象出特定细节。

让我们看看如何使用产生与前面示例相同的结果的NativeQuery

public UserEntity getUserByIdWithNativeQuery(Long id) {Query nativeQuery= getEntityManager().createNativeQuery("SELECT * FROM users WHERE id=:userId", UserEntity.class);nativeQuery.setParameter("userId", id);return (UserEntity) nativeQuery.getSingleResult();
}

我们必须始终考虑NativeQuery是否是唯一的选择。大多数时候,一个好的JPQL查询可以满足我们的需求,最重要的是,从实际的数据库实现中保持一个抽象级别。

使用NativeQuery并不一定意味着将我们锁定在一个特定的数据库供应商上。毕竟,如果我们的查询不使用专有的 SQL 命令并且只使用标准的 SQL 语法,那么切换提供程序应该不是问题。

5.查询、命名查询和本机查询

到目前为止,我们已经了解了Query,NamedQueryNativeQuery

现在,让我们快速重新审视它们并总结它们的优缺点。

5.1.查询

我们可以使用entityManager.createQuery(queryString) 创建一个查询。

接下来,让我们探讨一下查询的优缺点:

优点:

  • 当我们使用EntityManager 创建查询时,我们可以构建动态查询字符串
  • 查询是用 JPQL 编写的,因此它们是可移植的

缺点:

  • 对于动态查询,可能会根据查询计划缓存将其多次编译为本机 SQL 语句
  • 查询可能分散到各种 Java 类中,并与 Java 代码混合在一起。因此,如果项目包含许多查询,则可能难以维护

5.2.命名查询

一旦定义了NamedQuery,我们就可以使用EntityManager 引用它:

entityManager.createNamedQuery(queryName);

现在,让我们看看命名查询的优缺点:

优点:

  • 在加载持久性单元时编译和验证命名查询。也就是说,它们只编译一次
  • 我们可以集中NamedQuery以使它们更易于维护 - 例如,在orm.xml、属性文件中或 on@Entity类中

缺点:

  • 命名查询始终是静态的
  • 命名查询可以在 Spring Data JPA 存储库中引用。但是,不支持动态排序

5.3.本机查询

我们可以使用EntityManager 创建一个NativeQuery

entityManager.createNativeQuery(sqlStmt);

根据结果映射,我们还可以将第二个参数传递给方法,例如Entity类,正如我们在前面的示例中所看到的那样。

NativeQuery也有优点和缺点。让我们快速看一下它们:

优点:

  • 随着我们的查询变得复杂,有时 JPA 生成的 SQL 语句并不是最优化的。在这种情况下,我们可以使用NativeQuery来提高查询效率
  • NativeQuery允许我们使用特定于数据库供应商的功能。有时,这些功能可以为我们的查询提供更好的性能

缺点:

  • 特定于供应商的功能可以带来便利和更好的性能,但我们通过失去从一个数据库到另一个数据库的可移植性来支付这种好处。

6.标准接口查询

条件API查询是以编程方式构建的类型安全查询,在语法上有点类似于 JPQL 查询:

public UserEntity getUserByIdWithCriteriaQuery(Long id) {CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(UserEntity.class);Root userRoot = criteriaQuery.from(UserEntity.class);UserEntity queryResult = getEntityManager().createQuery(criteriaQuery.select(userRoot).where(criteriaBuilder.equal(userRoot.get("id"), id))).getSingleResult();return queryResult;
}

直接使用标准API 查询可能令人生畏,但当我们需要添加动态查询元素或与JPA元模型结合使用时,它们可能是一个很好的选择。

7. 结论

在这篇快速文章中,我们了解了什么是 JPA 查询及其用法。

JPA 查询是从数据访问层抽象业务逻辑的好方法,因为我们可以依赖 JPQL 语法,并让我们选择的 JPA 提供程序处理查询转换。

本文中介绍的所有代码都可以在 GitHub 上找到。

相关内容

热门资讯

传承千年的西安甑糕,你了解它的... 西安甑糕是一款传统美食,它历史悠久,独具魅力,承载着这座古老城市的饮食文化和记忆,凭借软糯香甜的口感...
“能喝奶茶就不要喝水”?网红店... 据媒体报道,近日“奈雪的茶”河南驻马店一家门店张贴通知称“能喝奶茶就不要喝水”,此事引发争议。 涉...
数据看出游 | 透过数据看“五... 央视网消息:山河远阔,人间烟火。“五一”假期已开启,很多朋友已经暂别忙碌日常,准备好奔赴一场“诗与远...
武当山重拳整治旅游乱象:千年仙... 站在紫霄宫前的千年银杏树下,看着手持电子导览器的游客们有序排队上香,突然想起十年前初访武当时的场景—...
竹韵烟火醉五一!紫竹院“文化+... “五一”小长假期间,紫竹院公园内绿意盎然、竹影婆娑,游人如织。优质的生态景观与精心打造的文化活动,为...
视频|“咖香+露营”双场联动,... 4月30日,由南沙区商务局、南沙区文化广电旅游体育局、南沙区人民政府港湾街道办事处共同指导,南沙区餐...
“五一”假期首日天津交通“动脉...   新华社天津5月1日电(记者刘惟真)谷雨已过,立夏将至,正是游览风景的好时节。“五一”假期首日,天...
想了解西北青甘大环线及甘南地区... 第一天:西宁集结与青海湖初遇 清晨抵达西宁曹家堡机场,凉爽的高原空气瞬间洗去了旅途疲惫。当地导游阿乐...
“五一”来招宝山,奔赴禅意与野... “五一”期间 招宝山旅游风景区 以登顶鳌柱塔为打卡主线 推出“占鳌头·跃龙门”祈福活动 这两天,招宝...
勒泰商业中心第12届全城盛宴在... 4月30日,一场别开生面的美食盛宴—— 勒泰商业中心第12届全城盛宴在庄里街开幕,本届为期 6天的全...
枣阳样本:解码乡村旅游如何重塑... 晨雾中的凤凰山庄飘着柴火腊肉的香气,研学导师正带着孩子们辨认野菜。停车场里鄂A、鄂S牌照的车辆排到村...
重要提醒!@出游的你 “五一”假期到了 旅游热度持续攀升 户外探险、露营野炊、打卡“网红景点” 登山徒步、高空蹦极、游泳潜...
“五一”文旅消费热度高涨 云南... 云南网讯(记者彭锡)“五一”假期首日,国内文旅市场一片火热,文化地标、山水景点、城市乡村等地都吸引了...
西安兵马俑景区“五一”假期可夜... 极目新闻记者 郭迩 今年“五一”假期,位于陕西西安的秦始皇帝陵博物院景区,每天增加15000张门票,...
网红小城如何迎五一?淄博“烧烤... 今天是五一假期首日,全国多个网红城市及知名景区迎来“人从众”模式,市民外出旅游热情高涨。为避免人潮汹...
想深度领略长城魅力?这六个方面... 长城作为中国的象征之一,是世界文化遗产,吸引着来自全球的游客。漫步长城,能欣赏壮丽景色,感受历史的厚...
《北上》带火取景地 五一假期两... “今天先来巴城拍一张和运河人家的合影,明天再去淮安拍一张。”5月1日,从上海来江苏昆山过假期的张女士...