Hibernate的其他API
Query
Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。
HQL:Hibernate Query Language :Hibernate查询语言。这种语言与SQL的语法及其类似,是一个面向对象的查询语言。
SQL的操作对象是数据表、列等数据库对象,而HQL操作对象是类、对象、属性等。
Query 接口用来执行 HQL,Query 接口实例可以从 Session 对象 session
中生成:session.createQuery(String hql)
1 | // HQL 查询 |
通过 JPA EntityManager 创建
1 | // JPQL 查询 |
Query对象在Session对象关闭之前有效,否则会抛出SessionException异常。因为Session对象就想JDBC中的Connection 对象,即数据库的一次连接。关闭Connection对象,Statement对象就不能再使用,所以关闭Session后就不能再使用Query对象了。
Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
通过Query即可以执行hql语句:
1 | Query query = session.createQuery("hql语句"); |
又可以执行本地sql语句:
1 | SQLQuery sqlQuery = session.createSQLQuery("本地sql语句"); |
其中SQLQuery是Query的子类
Query 接口的主要方法
Query 的主要方法:
setxxx()
:用于设置HQL语句中问号或者变量的值;
setString(int position,String value);
设置HQL中的“?”的值,其中position代表“?”在HQL中的位置,value是要为“?”设置的值
1 | Query query=session.createQuery("from UserInfoPO u where u.age>? and u.useName like ?"); |
setString(String paraName,String value);
设置HQL中“:”后所跟变量的值;其中 paraName代表HQL中“:”后边的变量名,value是该变量的值:
1 | Query query=session.createQuery("from UserInfoPO u where u.age>:minAge and u.useName like:useName"); |
setParameter()
方法:参数绑定方法
位置参数绑定
1 | Query<Student> query = session.createQuery( |
命名参数绑定
1 | Query<Student> query = session.createQuery( |
分页控制方法:
setFirstResult
:设定从哪一个对象开始检索,参数表示这个对象在查询结果中的索引位置,起始值为0,默认情况下,从查询结果的第一个对象开始检索
setMaxResults
:一次检索最多返回多少数目
1 | Query<Student> query = session.createQuery("FROM Student ORDER BY name", Student.class); |
list()
;返回查询结果,并把查询结果转换成list对象
1 | Query query=session.createQuery("from UserInfoPO u where u.age>:minAge and u.useName like:useName"); |
getResultList();
:也可以获取结果列表
1 | List<Student> students = query.getResultList(); |
executeUpdate()
:执行更新,删除:
1 | Query<?> updateQuery = session.createQuery( |
标量结果
1 | Query<Long> countQuery = session.createQuery( |
- 查询所有表当中信息
1 | public class HibernateDemo5 { |

查询指定字符的数据(条件查询)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public class HibernateDemo5 {
// Query
public void demo01() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 通过Session活动Query接口
// String hql = "from Customer";
String hql = "from Customer where cust_name like ?";
Query query = session.createQuery(hql);
query.setParameter(0, "王%");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
}分页查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class HibernateDemo5 {
// Query
public void demo01() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 通过Session活动Query接口
//分页查询
String hql = "from Customer";
Query query = session.createQuery(hql);
//设置分页
query.setFirstResult(0);//相当于MySQL当中limit的第一个参数
query.setMaxResults(3);
//query.setParameter(0, "王%");
List<Customer> list = query.list();
for (Customer customer : list) {
System.out.println(customer);
}
transaction.commit();
}
}
Criteria与条件查询
Criteria API 是一种面向对象的查询方式,它允许你通过编程方式构建查询条件,而无需编写 SQL 或 HQL。这种方式也被称为 QBC(Query By Criteria),即 “条件查询”
使用QBC(Query By Criteria);更加面向对象的一种查询方式。
Criteria接口与Query接口非常类似,也是Hibernate的查询接口,它允许创建并执行面向对象方式的查询。
Criteria的主要作用:
- Criteria查询通过面向对象的设计,将数据查询条件封装为一个对象。简单的说,Criteria查询可以看成是传统SQL语言的对象化表示。
- Criteria接口完全封装了基于字符串形式的查询语句,它更擅长于执行动态查询。
条件查询查询的步骤:
- 获得Hibernate的Session对象。
- 以Session对象创建Criteria对象。
- 使用Restrictions的方法为Criteria对象设置查询条件,Order工具类的方法设置排序方式,Projections工具类的方法进行统计和分组。
- 向Criterion查询添加Criterion查询条件。
- 执行Criteria的list()或uniqueResult()方法返回结果集。
核心组件
- Criteria:主查询接口,通过
session.createCriteria(EntityClass.class)
创建。 - Criterion:查询条件(如
eq
,like
,gt
等),通过Restrictions
工具类生成。 - Projection:结果集投影(如
count
,avg
,group by
等),通过Projections
工具类生成。 - Order:排序规则,通过
Order.asc()
或Order.desc()
创建。 - DetachedCriteria:独立于 Session 的查询对象,可在多个 Session 中复用。
1 | import org.hibernate.*; |
在条件查询中,Criteria接口代表一次查询,该查询本身不具备任何数据筛选功能,Session调用createCriteria(Class clazz)方法对某个持久化类创建条件查询实例。
常用的Criteria操作方法:
- add()方法:它用来设置查询的条件,可以根据查询条件的个数,追加任意个add()方法。
- addOrder()方法:用来设置查询结果集的排序规则,相当于SQL语句中的order by子句。
- createCriteria()方法:当需要从多张表中联合查询时可使用createCriteria()方法。
- setFirstResult(int firstResult):设置查询返回的第一行记录。
- setMaxResults(int maxResults):设置查询返回的记录数。
1 | //分页查询前10条 |
常用查询条件
方法 | 说明 | 示例 |
---|---|---|
eq(property, value) |
等于 | Restrictions.eq("age", 20) |
ne(property, value) |
不等于 | Restrictions.ne("name", "张三") |
gt(property, value) |
大于 | Restrictions.gt("age", 18) |
ge(property, value) |
大于等于 | Restrictions.ge("score", 90) |
lt(property, value) |
小于 | Restrictions.lt("age", 30) |
le(property, value) |
小于等于 | Restrictions.le("price", 100.0) |
like(property, value) |
模糊查询(支持 % 和 _ ) |
Restrictions.like("name", "张%") |
in(property, values) |
包含在集合中 | Restrictions.in("id", Arrays.asList(1, 2, 3)) |
isNull(property) |
为空 | Restrictions.isNull("email") |
isNotNull(property) |
不为空 | Restrictions.isNotNull("phone") |
and(criterion1, criterion2) |
逻辑与 | Restrictions.and(gt("age", 18), like("name", "张%")) |
or(criterion1, criterion2) |
逻辑或 | Restrictions.or(eq("status", 1), isNull("deleted")) |
HQL查询
HQL查询语句
HQL ——(Hibernate Query Language):Hibernate语言查询它是完全面向对象的查询语句,查询功能非常强大,具备继承、多态和关联等特性 。Hibernate官方推荐使用HQL进行查询。 QBC——(Query By Criteria):标准化对象查询,以对象的方式进行查询,将查询语句封装为对象操作。优点:可读性好,符合Java 程序员的编码习惯。 Native SQL Queries:原生SQL查询,直接使用数据库提供的SQL方言进行查询。
HQL是Hibernate Query Language的缩写,HQL的语法与SQL相似,但HQL是一种面向对象的查询语言。SQL的操作对象是数据表、列等数据库对象,而HQL操作对象是类、对象、属性等。
Hibernate查询语言(HQL)是面向对象的查询语言,其结构与SQL查询相似,不同的是,HQL查询的主体是持久化类而不是数据表。
HQL提供了一种应用和数据库之间的抽象,提高了可移植性。
HQL子句本身大小写无关,但是其中出现的类名和属性名必须注意大小写。
HQL是完全面向对象的查询语言,支持继承和多态等特性。
HQL语句本身是不区分大小写的,也就是说HQL语句的关键字、函数都是不区分大小写的。但HQL语句中所有使用的包名、类名、实例名、属性名都区分大小写。
HQL查询依赖于Query类,每个Query对象对应一个查询对象。查询步骤如下:
- 获取Hibernate Session对象。
- 编写HQL查询语句。
- 以HQL语句为参数,调用session的createQuery方法,创建查询对象Query。
- 如果HQL语句中带有参数,则调用Query的setXxx方法,对参数赋值。
- 调用Query的list, unique Result等方法,查询获得结果。
from子句
from是最简单的HQL语句,也是最基本的HQL语句。from关键字后紧跟持久化类的类名。
1 | from Person |
from后还可以同时出现多个持久化类,此时将产生一个笛卡尔积或跨表的连接。但实际上这种用法很少使用,因为通常需要使用跨表连接时,可以考虑使用隐式连接或者显式连接,而不是直接在from后紧跟多个表名。
基本查询结构
1 | SELECT [DISTINCT] 属性列表 |
1 | // 查询所有学生 |
关联和连接
当程序需要从多个数据表中取得数据时,SQL语句将会考虑多表连接查询。Hibernate使用关联映射来处理底层数据表之间的连接,一旦提供了正确的关联映射后,当程序通过Hibernate进行持久化访问时,将可利用Hibernate关联来进行连接。
HQL支持两种关联连接形式:显式和隐式。
隐式连接不需要使用join关键字,使用英文点号(.)来隐式连接关联实体,而Hibernate底层将自动进行关联查询。
1 | // 查询部门名称为"研发部"的学生 |
使用显示连接可以为相关联的实体,甚至是关联集合中的全部元素指定一个别名。
- inner join内连接,可简写为join
- left outer join左外连接
- right outer join右外连接
- full join全连接
1 | String hql="select p from person p inner join p.myevent e where e.title like'%上课%'"; |
隐式连接和显式连接的区别:
隐式连接底层将转换成SQL99的交叉连接,显式连接将转换成SQL99的inner join、left join、right join等连接。 隐式连接和显式连接查询后返回的结果不同。当HQL省略关键字select时,隐式连接返回的结果是多个被查询实体组成的集合;显示连接查询返回的是被查询的持久化对象和被关联的持久化对象组成的数组。
隐式连接查询中,在HQL中,省略select,直接使用from开头 例如:from Message m where m.topic.id=3 对Message和Topic进行了连接查询,但是结果只包含Message的数据,结果为:List
显示连接查询中,在HQL中,省略select,直接使用from开头 例如:from Message m join m.topic t where t.id=3; 对Message和Topic进行了连接查询,每条记录包含Message和Topic两个实体的数据,两个实体构成一个数组,多条记录构成集合,结果为:List<Object[ ]>
SELECT子句
select子句用于选择指定的属性或直接选择某个实体,当然select选择的属性必须是from后持久化类包含的属性。
select选择的属性是实体类的属性;结果是一个集合,集合中的每个元素是一个Object数组:Object[]
查询特定属性
1 | // 只查询姓名和年龄 |
使用 DTO
1 | // 创建DTO类 |
聚合函数
HQL中支持的聚合函数有:concat(str,str)、substring()、trim()、lower()、upper()、length()、abs()、sqrt()、mod()、count()、avg()、min()、max()、sum()、current_date()、current_time()、current_timestamp()、day()、 month()、year()等。
也可以支持数学运算和连接符号等 同时也支持经验证SQL函数,如length()、lower()、upper()、trim()等 可以使用distinct去除重复数据
1 | // 统计各年龄段学生数量 |
WHERE子句
where子句用来筛选选中的结果,缩小选择范围。如果没有持久化实例命名别名,则可以直接使用属性名来引用属性。
where子句中支持大部分SQL的表达式:
设置参数
1 | // 冒号+参数名 |
基本条件
1 | // 比较运算 |
集合查询
1 | // IN 查询 |
HQL子查询
如果底层数据库支持子查询(所谓子查询就是,要查询的字段及信息在A表,条件在B表),则可以在HQL语句中使用子查询。与SQL中子查询相似的是,HQL中的子查询也需要使用()。
如果子查询返回多条记录,则可以使用下面关键字:
- all:表示子查询语句返回的所有记录。
- any:表示子查询语句返回的任意一条结果。
- some:与”any”等价。
- in:与”=any”等价。
- exists:表示子查询语句至少返回一条记录。
如果在子查询中操作集合,HQL提供了一组操纵集合的函数和属性:
size()函数和size属性:获得集合中元素的数量。 minIndex()函数和minIndex属性:对于建立了索引的集合获得最小索引值(关于集合索引参考第一部分映射值类型集合)。 minElement()函数和minElement属性:对于包含基本类型的元素集合,获得集合中值最小的元素。 maxElement()函数和maxElement属性:对于包含基本类型元素的集合,获得集合中值最大的元素。 element()函数:获得集合中所有元素。
更新和删除
更新:执行删除操作调用Query接口的executeUpate()方法,然后提交事务
HQL:Delete from Student where id = 10
删除:执行删除操作调用Query接口的executeUpate()方法,然后提交事务
HQL:update Student set age = 20,name=‘李四’ where id = 20
SQL查询
Hibernate还支持使用原生SQL查询,使用原生SQL查询可以利用某些数据库的特性,或者需要将原有JDBC应用迁移到Hibernate应用上,也可能需要使用原生SQL查询。类似于HQL查询,原生SQL查询也支持将SQL语句放在配置文件中配置,从而提高程序的解耦。命名SQL查询还可以用于调用存储过程。
SQL查询是通过SQLQuery接口来表示的,SQLQuery 接口是Query 接口的子接口,因此完全可以调用Query 接口的方法:
- list():获取记录集。
- uniqueResult():返回唯一记录。
- addEntity():将查询到的数据封装为特定的实体。
- setFirstResult():设置结果集的起点。
- setMaxResults():设置获取记录的最大条数。
- addScalarˈskeɪlə ():将查询的记录关联成标量值。
执行SQL查询的步骤:
- 获取Session对象。
- 编写SQL语句。
- 以SQL语句作为参数,调用Session的createSQLQuery()方法创建查询对象。
- 调用SQLQuery对象的addScalar()或addEntity()方法将选出的结果与标量值或实体进行关联。
- 如果SQL语句包含参数,则调用Query的setXxx()方法为参数赋值。
- 调用Query的list()方法或uniqueResult()方法返回查询的结果集。
标量查询
最基本的SQL查询就是获得一个标量(数值)列表。
标量查询(Scalar Query)是指直接返回数据库列值(而非实体对象)的查询方式。
1 | session.createSQLQuery("select * from student").list(); |
默认情况下,查询语句将返回由Object数组组成的List,数据的每个元素时student表的列值,Hibernate会通过ResultSetMetadata
来判定所返回数据列的实际顺序和类型。如果select后面只有一个字段,那么返回的List集合元素就不是数组,而只是单个的变量值。
当执行 SQL 查询且未指定返回类型时,Hibernate 默认返回
List
,每个数组元素对应数据库的一列:
1 | // 默认行为:返回 Object [] 列表 |
如果 SQL 中只选择一个字段,Hibernate 会直接返回
List<列类型>
:
1 | SQLQuery query = session.createSQLQuery("SELECT name FROM student"); |
使用 addScalar()
指定返回类型
addScalar()
方法用于明确指定返回列的类型,避免 Hibernate
通过 ResultSetMetadata
动态推断类型,从而提高性能,因此建议为这些数据列指定更明确的返回值类型。明确指定返回值类型通过addScalar()方法实现。addScalar()主要有两个作用:
- 指定查询结果包含那些数据列——没有被addScalar()选出的列将不会包含在查询结果里面中。
- 指定查询结果中数据列的数据类型。
1 | SQLQuery query = session.createSQLQuery("SELECT id, name, age FROM student"); |
此时Hibernate不再需要使用ResultSetMetadata来获取信息,而是直接从ResultSet中取出name列的值,并把name列的数据类型当成字符串处理。因此,即使使用了“*”作为查询的字段列表,但Hibernate查询的结果也只是name字段所组成的表。
在原生SQL查询里,程序指定的原生SQL语句时标准的SQL语句,因此SQL语句中使用的就是数据表、数据列等对象,而不是持久化类、属性。
实体查询
前面的标量值查询只是返回一些标量的结果集,这种查询方式与使用JDBC查询的效果基本类似。查询返回多个记录行,每个记录对应一个列表的元素,每个列表元素是一个数组,每个数组元素对应当前行、当前列的值。
如果查询返回了某个数据表的全部数据列,且该数据表有对应的持久化类映射,接下来就可把查询结果转换成实体。将查询结果转换成实体,可以使用SQLQuery提供的多个重载addEntity()方法。
使用 addEntity(Class entityClass)
方法将查询结果映射为实体
1 | List list = session.createSQLQuery("select * from animal") |
注意事项:
- 必须查询所有列:SQL
中需包含实体类映射的所有字段(通常用
SELECT *
)。 - 外键列必须存在:若实体包含
@ManyToOne
等关联,SQL 必须返回对应的外键列(如owner_id
)。 - 列名与属性名需匹配:默认情况下,数据库列名需与实体属性名一致(或通过
@Column
注解映射)。
在原生SQL中一样支持使用参数,这些参数既可以使用问号+索引的占位符参数(?N),也可以使用名字参数。
不仅如此,如果在SQL语句中显式使用了多表连接,则SQL语句可以选出多个数据表的数据。Hibernate还支持将查询结果转换成多个实体。如果要将查询结果转换成多个实体,则SQL字符串中应为不同数据表指定不同的别名,并调用addEntity(String alias,Class entityClass)方法将不同的数据表转换成不同实体。
当 SQL 中使用列别名时,需通过
@Column
注解或ResultTransformer
显式映射:1
2
3
4
5
6
7
8
9// SQL 使用别名
SQLQuery query = session.createSQLQuery("SELECT id AS animal_id, name FROM animal");
// 方法一:在实体类的属性上添加 @Column 注解
private Long id;
// 方法二:使用 ResultTransformer
query.setResultTransformer(Transformers.aliasToBean(Animal.class));不仅如此,Hibernate还可以将查询结果转换成非持久化实体(即普通的JavaBean),只要该JavaBean为这些数据提供了对应的setter和getter方法即可。Query接口提供了一个setResulltTransformer()方法,该方法可接受一个Transformers对象,通过使用该对象即可把查询到的结果集转换成JavaBean集。 使用
Transformers.aliasToBean(Class)
将结果映射到普通 JavaBean:1
2
3
4
5
6
7
8// 创建 JavaBean
public class AnimalDTO {
private Long id;
private String name;
private String ownerName;
// getter/setter 方法
}1
2
3
4
5
6
7String sql = "SELECT a.id, a.name, o.name AS ownerName " +
"FROM animal a JOIN owner o ON a.owner_id = o.id";
SQLQuery query = session.createSQLQuery(sql);
query.setResultTransformer(Transformers.aliasToBean(AnimalDTO.class));
List<AnimalDTO> dtos = query.list();