JPQL-Query查询实例详解

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: JPQL-Query查询实例详解

前面学习了JPQL语言和Query接口。这里学习一下如果通过JPQL和Query接口进行数据的查询、更新和删除。

【1】普通查询

首先说明一下FROM子句和Select…FROM。

  • from 子句是查询语句的必选子句。
  • Select 用来指定查询返回的结果实体或实体的某些属性。
  • From 子句声明查询源实体类,并指定标识符变量(相当于SQL表的别名)。


如果不希望返回重复实体,可使用关键字 distinct 修饰。select、from 都是 JPQL 的关键字,通常全大写或全小写,建议不要大小写混用。

代码实例如下:

@Test
public void testHelloJPQL(){
  String jpql = "select c FROM Customer c WHERE c.age > ?";
  Query query = (Query) entityManager.createQuery(jpql);
  //占位符的索引是从 1 开始
  query.setParameter(1, 1);
  List<Customer> customers = query.getResultList();
  System.out.println(customers.size());
}

控制台输出如下:

可以看到就是一条普通的查询语句。

但是在写JPQL时,需要注意,这一切面向对象。即对象+属性相当于表+列,可以联想一下Hibernate的HQL语言。

如果不写 select 而是直接使用from子句,表明获取对象的全部属性。

String jpql = FROM Customer c WHERE c.age > ?;


需要注意的是查询一个对象的所有属性时,并不能像MySQL那样使用 * 号标志。下面语句是错误的,不符合JPQL的规范。

select * FROM Customer c WHERE c.age > ?


当然,你可以查询部分属性

默认情况下, 若只查询部分属性, 则将返回 Object[] 类型的结果. 或者 Object[] 类型的 List。

.

也可以在实体类中创建对应的构造器, 然后再 JPQL 语句中利用对应的构造器返回实体类的对象.

代码实例如下:

@Test
public void testPartlyProperties(){
  String jpql = "SELECT c.lastName, c.age FROM Customer c WHERE c.id > ?";
  List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList();
  System.out.println(result);
  Object[] objects = (Object[]) result.get(0);
  System.out.println(objects[0]);
}

控制台输出如下:

可以看到,获取到的list是一个list<object[]>,解析起来是比较麻烦的。故而,我们更希望使用如下方式:

@Test
public void testPartlyProperties(){
  String jpql = "SELECT new Customer(c.lastName, c.age) FROM Customer c WHERE c.id > ?";
  List result = entityManager.createQuery(jpql).setParameter(1, 1).getResultList();
  System.out.println(result);
}

控制台输出如下:

这样获取到的是list<Customer>,这样解析起来就很友好了。

【2】createNamedQuery和createNativeQuery

① createNamedQuery 适用于在实体类前使用 @NamedQuery 标记的查询语句。

代码示例如下:

@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?")
@Cacheable(true)
@Table(name="jpa_cutomers")
@Entity
public class Customer {
  private Integer id;
  private String lastName;
  private String email;
  private int age;
  private Date createdTime;
  private Date birth;
  public Customer() {
  }
//...
}

测试代码实例如下:

@Test
public void testNamedQuery(){
  Query query = entityManager.createNamedQuery("testNamedQuery").setParameter(1, 3);
  Customer customer = (Customer) query.getSingleResult();
  System.out.println(customer);
}

控制台输出如下:

② createNativeQuery 适用于本地 SQL

即,你可以像MySQL那样写sql语句进行查询。

代码实例如下:

@Test
public void testNativeQuery(){
  String sql = "SELECT age FROM jpa_cutomers WHERE id = ?";
  Query query = entityManager.createNativeQuery(sql).setParameter(1, 3);
  Object result = query.getSingleResult();
  System.out.println(result);
}

控制台输出如下:


【3】(Hibernate)查询缓存

① 不使用查询缓存

多次查询同条语句,代码实例如下:

@Test
public void testQueryCache(){
String jpql = "FROM Customer c WHERE c.age > ?";
Query query = entityManager.createQuery(jpql);
//占位符的索引是从 1 开始
query.setParameter(1, 1);
List<Customer> customers = query.getResultList();
System.out.println(customers.size());
query = entityManager.createQuery(jpql);
//占位符的索引是从 1 开始
query.setParameter(1, 1);
customers = query.getResultList();
System.out.println(customers.size());
}

控制台输出如下:


② 使用查询缓存

persistence.xml配置如下:

<!-- 二级缓存相关 -->
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
<!--  这里表明使用查询缓存 -->
<property name="hibernate.cache.use_query_cache" value="true"/>

代码实例如下:

@Test
public void testQueryCache(){
  String jpql = "FROM Customer c WHERE c.age > ?";
  // QueryHints.HINT_CACHEABLE设置为true
  Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
  //占位符的索引是从 1 开始
  query.setParameter(1, 1);
  List<Customer> customers = query.getResultList();
  System.out.println(customers.size());
  query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
  //占位符的索引是从 1 开始
  query.setParameter(1, 1);
  customers = query.getResultList();
  System.out.println(customers.size());
}

控制台输出如下:

【4】更新和删除

JPQL的更新和删除主要 用的是query.executeUpdate()方法;

代码实例如下:

@Test
public void testExecuteUpdate(){
  String jpql = "UPDATE Customer c SET c.lastName = ? WHERE c.id = ?";
  Query query = entityManager.createQuery(jpql).setParameter(1, "YYY").setParameter(2, 12);
  query.executeUpdate();
}

控制台输出如下:

删除同上。

【5】order by,group by 和having子句

JPQL是面向对象的,和hibernate一致。此外,像排序、分组等和普通MySQL并无差异。

group by 子句用于对查询结果分组统计,通常需要使用聚合函数。

常用的聚合函数主要有 AVG、SUM、COUNT、MAX、MIN 等,它们的含义与SQL相同。

例如:

select max(o.id) from Orders o

没有 group by 子句的查询是基于整个实体类的,使用聚合函数将返回单个结果值,可以使用Query.getSingleResult()得到查询结果。

例如:

Query query = entityManager.createQuery(
          "select max(o.id) from Orders o");
Object result = query.getSingleResult();
Long max = (Long)result;

group by实例:

//查询 order 数量大于 2 的那些 Customer
@Test
public void testGroupBy(){
  String jpql = "SELECT o.customer FROM Order o "
      + "GROUP BY o.customer "
      + "HAVING count(o.id) >= 2";
  List<Customer> customers = entityManager.createQuery(jpql).getResultList();
  System.out.println(customers);
}

Having 子句用于对 group by 分组设置约束条件,用法与where 子句基本相同。

不同是 where 子句作用于基表或视图,以便从中选择满足条件的记录;having 子句则作用于分组,用于选择满足条件的组,其条件表达式中通常会使用聚合函数。


order by 实例:

@Test
public void testOrderBy(){
  String jpql = "FROM Customer c WHERE c.age > ? ORDER BY c.age DESC";
  Query query = entityManager.createQuery(jpql).setHint(QueryHints.HINT_CACHEABLE, true);
  //占位符的索引是从 1 开始
  query.setParameter(1, 1);
  List<Customer> customers = query.getResultList();
  System.out.println(customers.size());
}

order by子句用于对查询结果集进行排序。和SQL的用法类似,可以用 “asc“ 和 "desc“ 指定升降序。

如果不显式注明,默认为升序。

【6】关联查询与Fetch

在JPQL中,很多时候都是通过在实体类中配置实体关联的类属性来实现隐含的关联(join)查询。

例如:

select o from Orders o where o.address.streetNumber=2000 

上述JPQL语句编译成以下SQL时就会自动包含关联,默认为左关联。

在某些情况下可能仍然需要对关联做精确的控制。为此,JPQL 也支持和 SQL 中类似的关联语法。

如:

left out join / left join 
inner join 
left join / inner join fetch 

其中,left join和left out join等义,都是允许符合条件的右边表达式中的实体为空。

左外连接实例如下:

@Test
public void testLeftOuterJoinFetch(){
  String jpql = "FROM Customer c LEFT OUTER JOIN FETCH c.orders WHERE c.id = ?";
  Customer customer = 
      (Customer) entityManager.createQuery(jpql).setParameter(1, 7).getSingleResult();
  System.out.println(customer.getLastName());
  System.out.println(customer.getOrders().size());
}

控制台输出如下:


需要注意的是,这里JPQL用到了FETCH。如果不加FETCH呢?

代码实例如下:

@Test
public void testLeftOuterJoinFetch(){
  String jpql = "FROM Customer c LEFT OUTER JOIN  c.orders WHERE c.id = ?";
  List<Object[]> result = entityManager.createQuery(jpql).setParameter(1, 7).getResultList();
  System.out.println(result);
}

控制台输出如下:

“fetch”连接允许仅仅使用一个选择语句就将相关联的对象或一组值的集合随着他们的父对象的初始化而被初始化。

在默认的查询中,Entity中的集合属性默认不会被关联,集合属性默认是延迟加载( lazy-load )。那么,left fetch/left out fetch/inner join fetch提供了一种灵活的查询加载方式来提高查询的性能。

综上,在使用JPQL语言时 ,需要时刻记得和hibernate一致–面向对象。如果你使用的Query为createNativeQuery,才可以像使用普通MySQL一样进行数据操作。

【7】子查询

JPQL也支持子查询,在 where 或 having 子句中可以包含另一个查询。

当子查询返回多于 1 个结果集时,它常出现在 any、all、exist s表达式中用于集合匹配查询。

它们的用法与SQL语句基本相同。

子查询实例如下:

@Test
public void testSubQuery(){
  //查询所有 Customer 的 lastName 为 YY 的 Order
  String jpql = "SELECT o FROM Order o "
      + "WHERE o.customer = (SELECT c FROM Customer c WHERE c.lastName = ?)";
  Query query = entityManager.createQuery(jpql).setParameter(1, "YY");
  List<Order> orders = query.getResultList();
  System.out.println(orders.size());
}

控制台输出如下:



相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
SQL 数据可视化 BI
SQL语句及查询结果解析:技巧与方法
在数据库管理和数据分析中,SQL语句扮演着至关重要的角色
|
6月前
|
SQL
SQL语句两个字段或多个字段同时order by 排序
SQL语句两个字段或多个字段同时order by 排序
1064 0
|
6月前
|
SQL 关系型数据库 数据库连接
Hasor【环境搭建 03】Dataway接口配置服务使用DataQL聚合查询引擎(SQL执行器实现分页查询举例说明+报错 Query dialect missing 原因分析及解决)
Hasor【环境搭建 03】Dataway接口配置服务使用DataQL聚合查询引擎(SQL执行器实现分页查询举例说明+报错 Query dialect missing 原因分析及解决)
149 0
|
6月前
|
SQL Java 数据库连接
Hibernate - QBC和本地SQL对象检索详解
Hibernate - QBC和本地SQL对象检索详解
64 0
SQL 使用in关键字查询多个字段
SQL 使用in关键字查询多个字段
|
SQL 索引
查询SQL尽量不要使用select *,而是具体字段
查询SQL尽量不要使用select *,而是具体字段
|
SQL JSON Java
JPA的EntityManager来实现SQL或者HQL语句查询
JPA的EntityManager来实现SQL或者HQL语句查询
基础查询 SQL3查询结果去重&&SQL4查询结果限制返回行数&&SQL5将查询后的列重新命名
基础查询 SQL3查询结果去重&&SQL4查询结果限制返回行数&&SQL5将查询后的列重新命名
180 0
基础查询 SQL3查询结果去重&&SQL4查询结果限制返回行数&&SQL5将查询后的列重新命名
|
SQL 索引
一、查询SQL尽量不要使用select *,而是具体字段
一、查询SQL尽量不要使用select *,而是具体字段
130 0
SQL.查询-多条件-动态条件查询
SQL.查询-多条件-动态条件查询
102 0
SQL.查询-多条件-动态条件查询

相关课程

更多
下一篇
无影云桌面