Hibernate入门(7):HQL查询

时间:2022-09-17 14:56:10
使用 Hibernate 进行 CURD 操作时候,插入、更新、删除操作可以直接通过对持久化实体(PO)实例来进行,对于查询操作,Hibernate 提供了以下3种方式来进行:
  • HQL 查询;
  • Criteria 条件查询(hibernate 5.x 已经废弃);
  • SQL 查询;

以下示例代码中出现的 HibernateUtil 类是一个封装的Session管理类,详看:HibernateUtil

Hibernate HQL查询


HQL(Hibernate Query Language)是Hibernate提供的一种面向对象的查询语言,语法类似于SQL;
SQL 的操作对象是数据表、列等数据库对象,HQL 的操作对象是类、实例、属性等;

HQL 的基本使用

HQL 查询依赖于 Query 类,每一个 Query 对应一个查询对象; Query 类支持链式调用,常用的 API 如下:
Query createQuery(String HQLString) 根据 HQL 语句创建 Query 实例
Query setXX(String key,XX xx) hibernate 5.2 以前的方式传递参数方式:设置 HQL 语句中的参数 ,如 setInteger(String key,Integer value),setString(String key,String value)等
Query  setParameter(String key,Object value)
setParameter(int position,Object val)
hibernate5.2 之后的传递参数的方式,具体用法见下面;
Query setFirstResults(int index) 设置返回的结果集从第几条记录开始
Query setMaxResults(int maxNum) 设置本次放回结果集的最大结果数目
List list() 返回查询的结果列表,以 List<Object> 的方式,返回列表中的每一个 Object 对应一条查询结果记录,可能是一个PO持久化实体,也可能是一个包含所有返回属性的 Object[] 数组;

基本示例 其中实体 Users 的建模如下:
Entity Users
Property int id
String name
Date createDate
String icon
123456789101112131415161718192021222324252627282930313233343536373839
HQL语句模板和参数设置
HQL语句一般使用模板的方式编写,以提高灵活性,类似与 JDBC 中的PreparedStatement ,当然也可以直接填写参数;
HQL 模板的占位符 有2种方式,一种为 “:N” 占位符(N为参数变量),一种为“?”占位符
1
//方式1
2
String hqlStr = "select u from Users as u " +      
3
                        "where u.icon = :iconType ";     //:iconType 指明一个命名为“iconType”的参数
4
List list  = session.createQuery(hqlStr)           
5
            .setParameter("iconType","1")           // 设置模板中参数“iconType”的值为"1"
6
            .list();                                   
7
//方式2
8
String hqlStr2 = "select distinct u from Users as u " +
9
                "where u.icon = ? ";     //? 指明一个参数
10
List list2  = session.createQuery(hqlStr2)
11
             .setParameter(0,"1")     //设置模板中第1个参数的值为“1”;
12
             .list();

Query 返回结果列表
Query 返回的结果是以 List<Object> 的方式返回,返回List中的每一个 Object 对应一条查询结果记录; 这个 Object 可以是一个PO持久化实体(在查询结果可以转化为某个PO持久化实体时),也可以是一个包含所有返回属性的 Object[] 数组,如以上基本示例中的2个示例;



HQL 的基本语法


HQL 语句的语法基本类似于SQL,大部分 SQL99 中的关键字可以通用于 HQL 语句,HQL支持以下语法: 这些语法和 SQL99 中是基本一样的; 123456 示例
1
//查询User类实例中 age > 12 的实例,依据 icon 属性分组,每个分组以 age 升序排序,返回所有符合要求的实例
2
select u from User u
3
where u.age > 12
4
order by u.age asc
5
group by u.icon
6
7
//查询User实例中以 name 属性以 'A' 开头的实例,返回所有符合要求的实例的 name,id 属性
8
select u.name u.id from User u 
9
where u.name like "A%"

HQL 中的聚合函数

HQL 支持在选出的属性上使用聚合函数,这些函数和SQL中的完全相同,如:avg ,count,max,min,sum 示例: 123

HQL 中的条件表达式

HQL where子句中支持 SQL 的所有运算符,同时也支持 EJB-QL 的运算符;
SQL 运算符 数学运算符::+ - * / 等;
二进制运算符:= 、>、<、!= 、like 等;
逻辑运算符:and、or、not 等;
字符串连接符,函数:|| (如 str || str2),concat(str1,str2)
其他运算符:in、not in、between、is null 、is not null、is empty、is not empty、member of、not member of 等
时间操作函数:current_time()、current_date()、current_timestamp()、second()、minute()、hour()等
EJB-QL 运算符 substring()、trim()、lower()、upper()、length()、locate()、abs()、sqrt()、bit_length()等

关联连接

HQL 支持两种方式的关联连接(join)方式:隐式(implict)、显式(explict); 在使用时优先推荐使用显式连接,隐式连接在 hibernate 3.2 之后 只能自动作用与普通的组件属性和1-1的关联实体,对于1-N、N-N的关联实体只能通过显式连接,隐式连接直接通过"."调用关联对象,底层会自动转化为 SQL99 的 交叉连接; 以下介绍显式连接:
1)关联连接类型:
  • inner join / join : 内连接
  • left join:左外连接
  • right join:右外链接
  • full join:全连接
※ 注意这些连接类型都会在底层转化为相应的SQL,前提条件是这些数据库要能支持这些关联连接操作;

2)关联连接基本语法 1
select 实体实例/实体属性 from 实体 [as] 实体实例(别名)
2
inner join 关联实体 [as] 关联实体实例(别名)
3
with 提供额外的关联连接条件,类似于SQL中的on
示例:
123456789101112
3)解决关联实体延迟加载的问题
对于集合属性,hibernate 默认采用延迟加载的策略。比如User中含有一个集合属性 articles,当User被加载时,默认不加载 articles,当 User 所在的 Session 被关闭时,User的实例将无法访问其关联的 articles。为了解决这个问题,有两种方式: ① 在关联实体的注解标签中,设置属性 fetch=FetchType.EAGER ② 在相关的HQL中使用 fetch 关键字,如下: 1
select u from User u
2
inner join fetch u.articles
※ fetch 关键字无法与 Query.setMaxResults() ,Query.setFirstResults() 方法共用; ※ full join fetch ,right join fetch 没有任何意义;

子查询

HQL 提供的子查询语法类似于 SQL,类似如下: 123


HQL 命名查询


Hibernate 支持将 HQL 语句放置到持久化实体的注解中,通过这种方式能进一步提高程序的解耦; 命名查询使用 @NamedQuery 标签,可以将多个 @NamedQuery 放置到一个 @NamedQueries 中 ,示例使用如下: User.java 1
@Entity
2
@Table(name="users")
3
@NamedQuery(name="query1",query="select u from Users u where icon = :iconType")
4
5
public class Users {
6
    @Id
7
    @GeneratedValue(strategy= GenerationType.IDENTITY)
8
    @Column(name="user_id")
9
    private int id;
10
11
    @Column(name="create_date")
12
    @Temporal(TemporalType.DATE)
13
    private Date createDate;
14
   ......
15
}
Test.java 1234567891011



DML风格的批量更新/删除

HQL 语句除了可以用于查询外,也可以用与批量 update,insert,如下: 1
 public static void main(String[] args){
2
        Session session = HibernateUtil.currentSession();
3
        Transaction tran = session.beginTransaction();
4
        
5
     //更新数据
6
        String hqlUpdate = "update User u set u.point = u.point + :increasePoint";
7
        int updateCount = session.createQuery( hqlUpdate)
8
                .setParameter("increasePoint",12)
9
                .executeUpdate();
10
11
     //删除数据
12
        String hqlDelete = "delete from User where point < :lowesrPoint";
13
        int deletedCount = session.createQuery(hqlDelete)
14
                .executeUpdate();
15
16
17
        tran.commit();
18
        HibernateUtil.closeSession();
19
 }