[学习笔记] Hibernate之HQL实用技术

# 学习 # · 2021-03-13

使用HQL语句

1、Hibernate支持三种查询方式:HQL查询、Criateria查询、Native SQL查询。

2、HQL查询语言:是一种面向对象的查询语言,其中没有表和字段的概念,只有类、对象、属性的概念。

3、编写HQL语句:

(1)HQL语句除了Java类和属性的名称外,对大小写不敏感。在实际使用中通常对HQL中的关键字使用小写字母。

(2)from子句:

# 查询所有部门
from com.aduo.pojo.Dept --部门全限定类名
from Dept  --省略了包名
from Dept as dept --使用as指定Dept的别名为dept
from Dept dept --指定别名as可选

(3)select子句:用于选取对象和属性。

# 查询部门名称
select dept.deptName from Dept as dept
# 使用部门别名
select dept from Dept as dept

(4)where子句:用于表达查询的限制条件。

# 查询部门名称是SALES的部门对象
from Dept where deptName = 'SALES' 
# 使用指派的别名查询
from Dept as dept where dept.deptName = 'SALES'
# 查询部门地址不为NULL的部门对象 
from Dept dept where dept.loc is not null

(5)使用表达式:表达式一般用在where子句中。

# 查询部门名称是sales的部门对象,不区分大小写
from Dept dept where lower(dept.deptName) = 'sales'
# 查询2016年入职的员工
from Emp where year(hireDate) = 2016

(6)ordery by子句:用于按指定属性排序。

# 查询所有员工,按照入职时间升序排序
from Emp order by hireDate asc
# 查询所有员工,按照入职时间升序排序。如果入职时间相同,则按照工资降序排序。
from Emp order by hireDate, salary desc

4、执行HQL语句的步骤:

(1)获取Session对象:

session = HibernateUtil.currentSession();

(2)编写HQL语句:

String hql = "from Emp";

(3)创建Query对象:

Query query = session.createQuery(hql);

(4)执行查询,得到查询结果:

// 使用list()方法执行查询
List<Emp> empList = query.list();
for (Emp item : empList) {
    System.out.println(item.getEmpNo() + "\t" + item.getEname());
}

// 使用iterate()方法执行查询
Iterator<Emp> empIterator = query.iterate();
while (empIterator.hasNext()) {
    item = empIterator.next();
    System.out.println(item.getEmpNo() + "\t" + item.getEname());
}

5、list()方法和iterator()方法的区别:

(1)list()方法生成一条SQL查询语句,查询所有符合条件的记录。

(2)iterate()方法首先查询出所有符合条件的主键值,此处是empno,然后在需要某一对象的其他属性值时,オ生成按主键查询的SQL语句。即iterate()方法可能生成1+N条SQL语句(N为第一条语句获取的EMP对象的数量)。


在HQL语句中绑定参数

1、使用字符串拼接查询条件存在的弊端:

(1)从性能方面,Hibernate底层使用JDBC的PreparedStatement对象访问数据库。如果直接将属性值写在语句中,那么每次执行SQL语句, 数据库都会重新编译SQL语句,从而导致性能降低。

(2)从安全角度,这种字符串的拼装造成的漏洞是SQL注入攻击的主要目标。

(3)在实际开发中,不使用字符串拼接的方式来构建HQL语句,而使用参数绑定的方式。

2、参数绑定的形式:

(1)按参数位置绑定:下标从0开始。

String hql = "from Dept as dept where dept.deptName=?";
Query query = session.createQuery(hql);
query.setString(0, deptName);

(2)按参数名称绑定:可读性好,易维护,推荐使用。

String hql = "from Dept as dept where dept.deptName=:name";
Query query = session.createQuery(hql);
query.setString("name", deptName);

3、绑定各种类型的参数:

(1)为任意参数类型赋值:query接口提供了setXXX()重载方法针对具体数据类型进行赋值(XXX表示各种数据类型)。

setXXX(int position, XXX value);    // 按照位置传参赋值
setXXX(String name, XXX value);        // 按照参数名称传参赋值

(2)setParameter():用来绑定任意类型参数。

setParameter(int position,  Object value);    // 按照位置为参数赋值
setParameter(String name, Object value);    // 按照参数名为参数赋值

(3)setProperties():绑定命名参数与一个对象的属性值。

// 查询依赖多个条件,且类型各异
String hql = "from Emp where job=:job and sal>:sal";
Query query = session.createQuery(hql);
// 根据命名参数的名称,从conditions对象中相同名称属性上取值
query.setProperties(conditions);

4、实现动态查询:

// 动态生成HQL
StringBuilder hql = new StringBuilder("from Emp as emp where 1=1");
if (conditions.getJob() != null && conditions.getJob().length() > 0) {
    hql.append(" and emp.job=:job");
}
if (conditions.getSal() != null && conditions.getSal() != 0) {
    hql.append(" and emp.sal>:sal");
}
// 执行查询
Query query = session.createQuery(hql.toString());
query.setProperties(conditions);
query.list();

5、唯一结果查询:query接口的uniqueResult()可以用于查询唯一结果,当查询结果不唯一的情况下,uniqueResult()会报错。

String hql = "select count(id) from Emp where sal >= :sal";
Query query = session.createQuery(hql);
Long count = (Long)query.uniqueResult();

分页和投影

1、实现分页的步骤:

(1)使用count函数获得总记录数:

String hql = "select count(id) from Emp";  
Query query = session.createQuery(hql);
Long count = (Long) countQuery.uniqueResult();

(2)计算总页数:

int totalPages = (int) ((count%pageSize == 0 ) ? (count / pageSize) : (count / pageSize + 1));

(3)实现分页:

// 当前页号
int pageNo = 2;
// 每页显示的记录数
int pageSize = 3;

// 执行查询
Session session = null;
Transaction tx = null;
List<User> empList = null;
try {
    session = HibernateUtil.currentSession();
    tx = session.beginTransaction();
    String hql = "from emp order by empNo";
    Query query = session.createQuery(hql);
    query.setFirstResult((pageNo - 1) * pageSize);    //第一条记录的位置
    query.setMaxResults(pageSize);    //最大返回记录值
    empList = query.list();
    tx.commit();
} catch (HibernateException e) {
    e.printStackTrace();
    if (tx != null) {
        tx.rollback();
    }
}

// 遍历并输出结果
for (Emp item : empList) {
    System.out.println(item.getEmpNo() + "\t" + item.getEname());
}

2、使用投影查询:HQL投影查询是查询一个持久化类的一个或多个属性值,或者是通过表达式或聚合函数得到的值。

3、投影查询需要使用HQL的select子句,查询结果的封装主要分三种情况:

(1)封装成Object对象:每条查询结果只包含一个结果列。

String hql = "select deptName from Dept";
Query query = session.createQuery(hql);
query.list();

(2)封装成Object数组:每条查询结果包含多个结果列。

String hql="select deptNo,deptName from Dept";
Query query = session.createQuery(hql);
query.list();

(3)通过构造方法封装成对象(对象不是持久化状态,仅用于封装结果)

// 要求Dept类中有Dept(Integer deptNo, String deptName)和Dept()构造方法
String hql = "select new Dept(deptNo,deptName) from Dept";// dept队形只用于封装,非持久化状态
Query query = session.createQuery(hql);
query.list();
如无特殊说明,本博所有文章均为博主原创。

如若转载,请注明出处:一木林多 - https://www.l5v.cn/archives/267/

评论