Hibernate查询Query By Criterial

article/2025/11/9 22:53:34

提供的检索方式:
(1)导航对象图检索方式 
(2)OID检索方式
(3)HQL检索方式
(4)QBC检索方式[query by Criteria(标准)]
(5)本地SQL检索方式

1、简介

1.1 HQL检索方式
HQL(Hibernate query Language)是面向对象的查询语言,在Hibernate提供的检索方式中,HQL是使用最广泛的检索方式。功能:
a.在查询语句中设定各种查询条件
b.支持投影查询,即仅检索出对象的部分属性
c. 支持分页查询
d.支持连接查询
e.支持分组查询,允许使用having 和group by 关键字
f.提供内聚聚集函数,如sum(),min()和max()
g.支持子查询,即嵌入式查询
h.支持动态帮定参数
session的find方法以及Query 接口都是支持HQL检索方式的,这两者的区别在于,前者只是执行一些简单的HQL查询语句的便捷方式,它不具有动态邦定参数的功能,Query 接口才是真正的HQL查询接口。

//创建一个Query 对象
Query query = session.createQuery ("from Customer as c where c.name=:customerName and c.age=:customerAge");
//动态绑定参数
query.setString("customerName","Tom");
query.setInteger("customerAge",21);
//执行查询语句,返回结果
List result = query.list();

1.2 QBC检索方式

QBC提供的查询方式由:Criteria接口,Criterion接口和Expression类组成,支持在运行时动态生成查询语句。
//创建一个 Criteria对象
Criteria criteria = session.ceateCriteria(Customer.class);
//设定查询条件,然后把查询条件加入到Criteria中
Criterion criterion1 = Exception.like("name","T%");
Criterion criterion2 = Exception.eq("age",new Integer(21));
criteria = criteria.add(criterion1);
criteria = criteria.add(criterion2);
//执行查询语句,返回查询结果
List result = criteria.list();

QBE(Quary by Example)检索方式,是QBC的子功能。它允许先创建一个对象样板,然后检索出所有和这个样板相同的对象。
//创建一个Customer样板对象
Customer example = new Customer();
example.setAge(21);
List result = session.createCriteria(Customer.class)
                      .add(Example.create(example0)
                      .list();

1.3 SQL检索方式

HQL和QBC检索时,Hibernate会生成标准的SQL查询语句,适用于所有的数据库平台,这两种方式都是跨平台的。
有的应用程序可能需要根据底层数据库的SQL方言,来生成一些特殊的查询语句,这样可以利用SQL查询方式。
Query query = session.createSQLQuery("select {c.*} from CUSTOMERS c where c.NAME like :customerName and c.AGE = :customerAge ","c",Customer.class);
query.setString("customerName","T%");
query.setInteger("customerAge",21);
List result = query.list();

1.4 ....

1.5 适用别名

from Customer as c where c.name=:name
= from Customer c where c.name=:name

 1.6 多态查询

HQL和QBC都支持多态查询,多态查询是指查询出当前类及所有子类的实例,
session.createQuery("from Employee"); or session.createCriteria(Employee.class);
如果Employee类有两个子类:HourlyEmployee和SalariedEmployee,那么这个查询语句会查出所有的Employee实例,以及HourlyEmployee类和SalariedEmployee类的实例。
session.createQuery("from HourlyEmployee");
session.createCriteria(HourlyEmployee.class);//只检索子类

1.7 对查询结果排序

HQL采用 order by ,QBC采用Order类对结果排序
//HQL
Query query = session.createQuery("from Customer c order by c.name");
//QBC
Criteria criteria = session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("name"));

1.8 分页查询

Query和Criteria接口都提供了用于分页显示查询结果的方法
a.setFirstResult(int firstResult): 开始索引位置(从0开始)
b.setMaxResult(int maxResults):一次最多检索出的对象数目

1.9 检索单个对象

Query和Criteria接口都提供了以下用于执行查询语句并返回查询结果的方法。
a. list方法:返回一个list类型的查询结果(setMaxResult(1)即返回单个对象)
b. uniqueResult()方法:返回单个对象

1.10 在HQL查询语句中绑定参数

Hibernate参数机制依赖于JDBC API中的PreparedStatement的预定义SQL语句功能。优点:
a. 非常安全,
b.能够利用底层数据库预编译SQL语句的功能,提高查询数据的性能。预编译是指底层数据库系统只需编译SQL语句一次,把编译出来的可执行代码保存在缓存中,如果多次执行相同形式的SQL语句,不需要重新编译,只需要从缓存中获得执行代码即可。(而如果使用条件拼sql会每次都重新编译。)

1.10.1 参数绑定的形式
a.按照参数名字绑定,命名参数以":"开头。eg:c.name=:name
b.按照参数位置绑定,用?来定义参数的位置。eg:c.name=?
按名字绑定的优势:
a. 使程序代码有较好的可读性
b.按名字绑定有利于程序代码的维护,而对于按位置绑定方式,如果参数在HQL查询语句中的位置改变了,就必须修改相关帮定参数的代码,这削弱了程序代码的健壮性和可维护性。
c. 按名字绑定方式允许一个参数在HQL查询语句中出现多次。

1.10.2 绑定各种类型的参数
a.setXxxxx(),如:setInteger();
b.三个特殊的参数绑定方法
-->setEntity():把参数与一个持久化类的实例绑定,主要是用其中的OID进行查询
session.createQuery("from Order o where o.customer= :customer")
               .setEntity("customer",customer)
               .list();
对应的SQL:
select * from ORDERS where CUSTOMER_ID=1;

-->setParameter()方法:绑定任意类型的参数
query.setParameter("customer",customer,Hibernate.entity(Customer.class));
query.setParameter("orderNumber",orderNumber,HIbernate.STRING);
//某些类型Hibernate可以根据参数值的java类型推断出对应的映射类型,此时不需要显示指定一个摄类型
query.setParameter("orderNumber",orderNumber);
但是日期类型的一般要指定,因为有好几种可能

-->setProperties()方法:用于把命名参数与一个对象的属性值绑定
Customer customer = new Customer();
customer.setName("Tom");
customer.setAge(21);
Query query = session.createQuery("from Customer as c where c.name=:name and c.age=:age");
query.setProperties(customer);
:name 会和Customer对象的name属性匹配。

1.11 在映射文件中定义命名查询语句

<hibernate-mapping>
    <class name="mypack.Customer" table="CUSTOMERS">
     ...
    </class>

    <query name="findCustomersByName"><![CDATA[
                   from Customer c where c.name like :name
     ]]></query>

</hibernate-mapping>
<query>元素用于定义一个HQL查询语句,他和<class>元素并列,程序中使用方式:
Query query = session.getNameOfQuery("findCustomersByName");
query.setString("name",name);
List result = query.list();
<query>元素也可以用于定义一个本地SQL语句

2、设定查询条件

HQL查询通过where子句来设定查询条件,注意的是 from Customer c where c.name ='tom',注意的是,在where子句中给出的是对象的属性名,而不是字段名.
对于QBC查询,必须创建一个Criterion对象来设定查询条件,Expression类提供了创建Criterion实例的工厂方法。

 2.1 比较运算

2.2 范围运算

in、between ... and ...、等

2.3 字符串模式匹配

通配符:
%:匹配任意类型并且任意长度(可以=0)的字符串,如果是中文,需要两个百分号,即"%%"
_:匹配单个任意字符,常用来限制字符串的表达式长度。

 2.4 逻辑运算

3、连接查询

和SQL查询一样,HQL与QBC也支持各种各样的连接查询,如内连接、外连接和交叉连接,HQL和QBC还支持迫切内连接和迫切左外连接。

 迫切左外连接和迫切内连接不仅指定了连接查询方式,而且显式指定了关联级别的检索策略。

3.1 默认情况下关联级别的运行时检索策略


 3.2 迫切左外连接

----会采取迫切左外连接检索策略----

//HQL
Query query = session.createQuery("from Customer c left join fetch  c.orders o where c.name like 'T%'");
List result = query.list();

//QBC检索方式
List result = session.createCriteria(Customer.class)
                                     .setFetchMode("orders",FetchMode.EAGER)
                                     .add(Expression.like("name","T",MatchMode.START))
                                     .list();

HQL:left join fetch 关键字表示迫切左外连接检索策略。
QBC:FetchMode.EAGER表示迫切左外连接检索策略。所有的orders集合都被初始化,且返回的Customer对象集合中可能有重复的元素,可以使用HashSet来过滤:
HashSet set = new HashSet(result);

 3.3 左外连接

//HQL
Query query = session.createQuery("from Customer c left join c.orders o where c.name like 'T%'");
List result = query.list();
for(Iterator pairs = result.iterator();pairs.hasNext();){
     Object[] pars = (Object[])pairs.next();
     Customer customer = (Customer)pairs[0];
     Order order =(Order)pairs[1];
}

根据映射文件来决定orders集合的检索策略

 注:返回结果中与迫切左外连接的不同,迫切左外连接,返回customer,这里返回是对象数组(一行数据拆成了两个对象)

 如果希望返回的集合中仅包含Customer对象,可以在HQL查询语句中使用select关键字:
session.createQuery("select c from Customer c left join c.orders o where c.name like 'T%'");
但初始化orders的时间由映射文件决定

3.4 内连接

 

 同样可以设定select 关键字来使得之返回Customer对象。
QBC也支持内连接查询:
Criteria customerCriteria = session.createCriteria(Customer.class);
customerCriteria.add(Expression.like("name","T",MatchMode.START));
Criteria orderCriteria = customerCriteria.create(Criteria("orders"));
orderCriteria.add(Expression.like("orderNumber","T",MatchMode.START));
List result = orderCriteria.list();

另:等价于
List result = session.createCriteria(Customer.class)
.createAlias("orders","o")
.add(Expression.like("this.name","T",MatchMode.START)//Customer的默认别名=this
.add(Expression.like("o.orderNumber","T",MatchMode.START))
.list();

默认情况下,QBC只检索出Customer对象,以上代码等价于H
===>select c from Customer c  join c.orders o where c.name like 'T%' and o.orderNumber like 'T%'

 3.5 迫切内连接

session.createQuery("from Customer c inner join fetch c.orders o where c.name like 'T%'");

如果包含重复元素也可以用HashSet来过滤。

注: QBC不支持迫切内连接

3.6 隐式内连接

HQL:
通过o.customer.name的形式访问与Order关联的Customer对象的name属性
from Order o where o.customer.name like 'T%'
以上代码虽然没有使用join关键字,它隐式指明使用内连接查询,他和一下HQL查询语句等价:
from Order o join o.customer c where c.name like 'T%'

QBC:
不支持隐式内连接,必须显式指定

3.7 右外连接

3.8 使用SQL风格的交叉连接和隐式内连接

HQL支持SQL风格的交叉连接查询,eg:
from Customer,Order
这个SQL执行交叉连接查询,将返回CUSTOMERS表与ORDERS表的交叉组合。(n*m条结果)

HQL内连接查询语句:
from Customer c inner join c.orders  ;
如果Customer没有orders集合属性,可以采用SQL风格的隐式内连接查询语句:
from Customer c ,Order o where c.id = o.customer_id

3.9 关联级别运行时的检索策略

总结:
(1)如果在HQL或QBC程序代码中没有显示指定检索策略,将使用映射文件配置的检索策略,但有个例外,即HQL总是忽略映射文件中设置的迫切左外连接检索策略。也就是说,及时映射文件中设置了迫切左外连接检索策略,如果HQL查询语句中没有显示指定这种策略,那么HQL仍然采用立即检索策略。
(2)如果在HQL或QBC程序代码中显示指定了检索策略,就会覆盖映射文件配置的检索策略。
在HQL查询语句中显示指定的检索策略包括以下内容:
a. left join fetch
b. inner join fetch
QBC中FetchMode类的三个静态实例,指定检索策略
a.FetchMode.DEFAULT:默认值,采用映射文件中配置的检索策略。
b.FetchMode.EAGER:迫切左外连接
c. FetchMode.LAZY:显示指定延迟检索。(HQL中没有提供该功能)
(3)只允许在一个sql语句中迫切左连接检索一个集合(一对多或多对多关联),允许在一个查询语句中迫切左连接检索多个一对一关联或着多对一关联
(4)HQL支持的各种连接查询

 


http://chatgpt.dhexx.cn/article/IGX0tTyc.shtml

相关文章

SLUB和SLAB的区别

转载&#xff1a;http://www.cnblogs.com/tolimit/ 首先为什么要说slub分配器&#xff0c;内核里小内存分配一共有三种&#xff0c;SLAB/SLUB/SLOB&#xff0c;slub分配器是slab分配器的进化版&#xff0c;而slob是一种精简的小内存分配算法&#xff0c;主要用于嵌入式系统。慢…

[linux kernel]slub内存管理分析(7) MEMCG的影响与绕过

文章目录 背景前情回顾描述方法约定 MEMCG总览省流总结简介 slub 相关 memcg机制kernel 5.9 版本之前结构体初始化具体实现 kernel 5.9-5.14kernel 5.14 之后 突破slab限制方法cross cache attackpage 堆风水 总结 背景 前情回顾 关于slab几个结构体的关系和初始化和内存分配…

linux slub分配器,Vi Linux内存 之 Slub分配器(六)

再来看内置式对象&#xff0c;如下图所示。指针位于对象的头部&#xff0c;与对象共用存储空间。这是因为对象被分配出去之前&#xff0c;其存储空间是空闲的可用状态&#xff0c;可用于存放空闲对象指针。对象被分配出去后&#xff0c;也不再需要这个指针了&#xff0c;可以被…

一文给你解决linux内存源码分析- SLUB分配器概述(超详细)

SLUB和SLAB的区别 首先为什么要说slub分配器&#xff0c;内核里小内存分配一共有三种&#xff0c;SLAB/SLUB/SLOB&#xff0c;slub分配器是slab分配器的进化版&#xff0c;而slob是一种精简的小内存分配算法&#xff0c;主要用于嵌入式系统。慢慢的slab分配器或许会被slub取代&…

Linux内存管理(2):SLAB/SLUB系统(基于线性映射)

一、概述 伙伴系统最大限度地解决了内存管理地外碎片问题,但是对于内碎片问题却无能为力。但内核实际使用内存的时候,却大多是小于一个页的单位。为了解决内核自身使用小块内存的碎片问题,Linux引入了基于对象的内存管理(或者叫内存区管理,Memory Area Management),就是SL…

slub分配器学习系列之linux5.10

前言 前一篇文章对 linux5.10 的 slab 分配器底层实现进行了探究与学习。进一步地&#xff0c;本篇文章将对 linux5.10 的 slub 分配器进行探究&#xff0c;对比看看两者的实现有何不同&#xff0c;做了哪些"必要的"改进。 slub 分配器 关于 slub 分配器的基本原理…

linux内核虚拟内存之slub分配器

上一章主要讲述以页为最小单位进行内存分配的伙伴管理算法&#xff0c;较大程度上避免了内存碎片问题。而实际上对内存的申请却不是每次都申请一个页面的&#xff08;比如文件节点&#xff0c;任务描述符等结构体内存&#xff09;&#xff0c;通常是远小于一个内存页面的大小&a…

4.19内核SLUB内存分配器

初始化 内核的大部分管理数据结构都是通过kmalloc分配内存的&#xff0c;那么slab本身结构的内存管理就出现了一个鸡与蛋的问题&#xff0c;slab数据结构所需内存远小于一整页的内存块&#xff0c;这些最适合kmalloc分配&#xff0c;而kmalloc只有在slab初始化完之后才能使用。…

SLUB内存管理之slub初始化

在讲slub内存管理涉及的四个函数之前&#xff0c;先从slub内存分配算法的初始化开始。系统启动时&#xff0c;会进行slub内存分配算法的初始化&#xff0c;函数流程是&#xff1a;start_kernel() -> mm_init()->kmem_cache_init()。在start_kernel()函数中的setup_arch()…

SLUB DEBUG原理

1. 前言 在工作中&#xff0c;经常会遇到由于越界导致的各种奇怪的问题。为什么越界访问导致的问题很奇怪呢&#xff1f;在工作差不多半年的时间里我就遇到了很多越界访问导致的问题&#xff08;不得不吐槽下IC厂商提供的driver&#xff0c;总是隐藏着bug&#xff09;。比如说…

slub allocator工作原理

前言 在Linux中&#xff0c;伙伴系统&#xff08;buddy system&#xff09;是以页&#xff08;1page等于4K&#xff09;为单位管理和分配内存。对于小内存的分配&#xff0c;如果还是使用伙伴系统进行内存分配&#xff0c;就会导致严重浪费内存。此时&#xff0c;slab分配器就应…

SLUB缓存管理

注&#xff1a;本文分析基于linux-4.18.0-193.14.2.el8_2内核版本&#xff0c;即CentOS 8.2 1、关于SLUB 目前大多数系统都不使用slab作为缓存的管理模式&#xff0c;转而使用slub&#xff0c;比如CentOS 7和8默认都是使用slub管理器。slub是基于slab的进一步优化改进&#x…

slub debug(linux4.16.1)

在命令行选项中添加slub_debugUFPZ&#xff0c;以使能相关检测功能&#xff0c;其含义如下&#xff1a; &#xff08;1&#xff09;U&#xff1a;跟踪该slab内存的相关属性&#xff0c;如其创建时所属的cpu、进程、时间 &#xff08;2&#xff09;F&#xff1a;开启sanity检查功…

linux内核内存管理slub

一、概述 linux内存管理核心是伙伴系统&#xff0c;slab&#xff0c;slub&#xff0c;slob是基于伙伴系统之上提供api&#xff0c;用于内核内存分配释放管理&#xff0c;适用于小内存&#xff08;小于&#xff11;页&#xff09;分配与释放&#xff0c;当然大于&#xff11;页…

内存管理 slub算法

内核管理页面使用了2个算法&#xff1a;伙伴算法和slub算法&#xff0c;伙伴算法以页为单位管理内存&#xff0c;但在大多数情况下&#xff0c;程序需要的并不是一整页&#xff0c;而是几个、几十个字节的小内存。于是需要另外一套系统来完成对小内存的管理&#xff0c;这就是s…

linux slub分配器,slub分配器

原标题&#xff1a;slub分配器 概述&#xff1a; Linux的物理内存管理采用了以页为单位的buddy system(伙伴系统)&#xff0c;但是很多情况下&#xff0c;内核仅仅需要一个较小的对象空间&#xff0c;而且这些小块的空间对于不同对象又是变化的、不可预测的&#xff0c;所以需要…

Linux内存管理(八): slub分配器和kmalloc

kernel: 5.10 Arch: aarch64 上文 介绍过&#xff0c; 伙伴系统在分配内存时是以物理页为单位的&#xff0c;但在很多场景下&#xff0c;内存需要分配的大小是以字节为单位的&#xff0c;达不到一个物理页的大小。如果继续使用伙伴系统进行内存分配&#xff0c; 那么就会出现严…

Linux 踩内存 slub,Linux SLUB 内存分配器分析

本文简介 本文主要介绍了Linux SLUB分配的产生原因、设计思路及其代码分析。适合于对Linux内核&#xff0c;特别是对Linux内存分配器感兴趣的读者。 1.为何需要SLUB&#xff1f; Linux SLUB内存分配器合入Linux主分支已经整整10年了&#xff01;并且是Linux目前默认的内存分配器…

SLUB

 内核管理页面使用了2个算法:伙伴算法和slub算法,伙伴算法以页为单位管理内存,但在大多数情况下,程序需要的并不是一整页,而是几个、几十个字节的小内存。于是需要另外一套系统来完成对小内存的管理,这就是slub系统。slub系统运行在伙伴系统之上,为内核提供小内存管…

linux内存源码分析 - SLUB分配器概述

本文为原创&#xff0c;转载请注明&#xff1a;http://www.cnblogs.com/tolimit/ SLUB和SLAB的区别 首先为什么要说slub分配器&#xff0c;内核里小内存分配一共有三种&#xff0c;SLAB/SLUB/SLOB&#xff0c;slub分配器是slab分配器的进化版&#xff0c;而slob是一种精简的小内…