目录
- 一、Hibernate 的 HQL 查询
- 1.1、查询所有数据
- 1.2、条件查询
- 1.3、排序查询
- 1.4、统计查询
- 1.5、分页查询
- 1.6、投影查询
- 二、Hibernate 的 QBC 查询
- 2.1、基本查询
- 2.2、条件查询
- 2.3、排序查询
- 2.4、统计查询
- 2.5、分页查询
- 2.6、投影查询
- 2.7、离线查询
在 Hibernate 中,查询方式有 HQL 和 Criteria 查询两种方式,HQL是Hibernate Query Language的缩写,语法类似于 SQL 语句,可以直接使用实体类名称及属性名称来查询,它提供更加丰富灵活、更为强大的查询能力。
Criteria 查询对查询条件进行了面向对象封装,符合编程人员的思维方式,不过HQL(Hibernate Query Language)查询提供了更加丰富的和灵活的查询特性,因此 Hibernate将 HQL 查询方式立为官方推荐的标准查询方式,HQL 查询在涵盖 Criteria 查询的所有功能的前提下,提供了类似标准 SQL 语句的查询方式,同时也提供了更加面向对象的封装。
一、Hibernate 的 HQL 查询
HQL 语法类似于 SQL,有 SQL 的关键词如 select 、from 、order by 、count()、where 等,完整的HQL语句形式如下: Select/update/delete…… from …… where …… group by …… having …… order by …… asc/desc。
Hibernate 的 HQL 查询中,通过 Session
对象的 createQuery(String HQL)
方法,获取 Query
对象, Query
中传入查询的 HQL 语句,之后通过 Query
对象的 list()
方法,获取查询的结果集。
HQL 书写规范:
- 在查询语句中省略
select
关键字 - 使用类名称替代数据库中的表名称
- 使用实体类的属性名称代替数据库表中的列名称
HQL 查询步骤:
Query query = session.createQuery(String HQL);
:获取查询的Query
对象query.setParameter(arg0,arg1);
:设置查询条件参数,参数下标从0开始List list = query.list();
:获取查询结果集
1.1、查询所有数据
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 查询数据库表中的所有数据
@Test
public void testHQL01() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
// 使用session的createQuery(String HQL)获取 Query 对象
Query query = session.createQuery("from User");
// 使用 query对象的list()方法,获取查询结果集
List list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.2、条件查询
在条件查询中,HQL 书写方式与 SQL 一样,使用 ?
作为参数的占位符,通过 setParameter(arg0, arg1)
来设定参数的值,其中:
arg0
:表示参数的小标,从 0 开始;arg1
:表示参数的具体值;
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 条件查询,查询昵称里面有蚂蚁的用户
@Test
public void testHQL02() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
// 使用session的createQuery(String HQL)获取 Query 对象
Query query = session.createQuery("from User where nickname like ?");
// 使用模糊查询
query.setParameter(0, "%蚂蚁%");
// 使用 query对象的list()方法,获取查询结果集
List list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.3、排序查询
在排序查询中,HQL 书写方式与 SQL 一样,使用 order by 属性名称 desc/asc
来进行排序。
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 排序查询
@Test
public void testHQL03() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("from User order by uid desc");
List list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.4、统计查询
在 Hibernate 中,使用 HQL 语句,也可以使用聚合函数 (count()、avg()、sum()、max()、min())
进行查询。使用聚合函数式, HQL 语句的写法如下:
Query query = session.createQuery("select count(*) from User");
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 统计查询
@Test
public void testHQL04() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("select count(*) from User");
// 使用聚合函数中,除了使用 group
// by进行分组的情况下,返回的都是唯一的结果,此时可以用query的uniqueResult()方法,接收唯一结果
// 使用 Long 类型进行接收
Long count = (Long) query.uniqueResult();
System.out.println(count);
}
}
1.5、分页查询
在 Hibernate 的分页查询中,通过 query.setFirstResult(0)
和 query.setMaxResults(2)
方法分别设置查询的开始位置和每页显示的数量,从而达到分页查询的效果。
query.setFirstResult(0)
:设置查询的开始位置,从0开始query.setMaxResults(2)
:设置每页的显示数据量
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 分页查询
@Test
public void testHQL05() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("from User");
query.setFirstResult(0);
query.setMaxResults(2);
List list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
1.6、投影查询
在 Hibernate 框架中,当我们只需要查出某个对象中的个别属性的时候,如目前只需要查出用户的用户名和密码两个属性,如果使用 HQL 查询的方式,将会查找出该对象的全部属性,此时将会降低查询的速度和浪费系统的资源。
如果我们使用Query query = session.createQuery(select username , password from User);
此时通过 query.list();
方法,我们得到的结果集是 List
类型的,不符合面向对象的特性,而且结果集不方便使用。
为了解决这一问题,Hibernate 也给出了解决方案投影查询,通过 Query query = session.createQuery("select new User(username,password ) from User");
此时,通过 query.list()
方法得到的结果集是 list
类型的,但是其中 User
对象除 username 和 password 以外的属性均为 null。
需要注意的是:在使用投影查询中的 HQL 语句中,出现了 new 关键字,这意味着,我们需要在普通Java类中添加所要查询属性的有参构造函数,此外,为了保证该普通 Java 类符合 JavaBean 的规范,我们需要声明其无参构造函数,不然程序运行时会报出 org.hibernate.hql.ast.QuerySyntaxException
异常。
User 实体类
package com.hibernate.domain;
import java.util.Date;
public class User {
private Integer uid;
private String username;
private String password;
private String nickname;
private String realname;
private Date birthday;
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getRealname() {
return realname;
}
public void setRealname(String realname) {
this.realname = realname;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User() {}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", password=" + password + ", nickname=" + nickname
+ ", realname=" + realname + ", birthday=" + birthday + "]";
}
}
投影查询:
package com.hibernate.test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestHQL {
// 投影查询:查询用户名和密码
@Test
public void testHQL06() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Query query = session.createQuery("select new User(username, password) from User");
// 所查询得到的结果集仍然是List 类型
List list = query.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
二、Hibernate 的 QBC 查询
Hibernate 中的 QBC 查询方式,全称为 Query By Criteria
,通过 Session
对象的 createCriteria(Class clazz)
方法创建 Criteria
对象,之后通过 Criteria
对象的 list()
方法获取查询结果集。它是一种面向对象的查询方式,QBC 查询把生成语句的过程全部融入到方法中了。
2.1、基本查询
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 基本查询
@Test
public void testQBC01() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
// 使用 createCriteria(Class clazz) 创建 Criteria 对象
Criteria criteria = session.createCriteria(User.class);
List list = criteria.list();
for (User user : list) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.2、条件查询
Hibernate QBC 查询进行条件查询时候,通过 Criteria
的 add()
方法,添加查询条件。
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 条件查询,通过 add()方法添加查询条件
@Test
public void testQBC02() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 通过 Restrictions 添加具体的条件
criteria.add(Restrictions.like("nickname", "%蚂蚁%"));
List users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.3、排序查询
Hibernate QBC 查询进行排序查询时候,通过 Criteria
的 addOrder()
方法,添加排序查询的条件。addOrder(Order.asc(属性名称))
进行升序查询和 addOrder(Order.desc(属性名称))
进行降序查询
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 排序查询
@Test
public void testQBC03() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 通过 addOrder() 添加排序条件
criteria.addOrder(Order.desc("uid"));
List users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.4、统计查询
QBC 查询中,Criteria
通过 criteria.setProjection(Projections.XXX)
方法来设定聚合函数。如使用 Projections.rowCount()
获取数据表中的总记录数,通过 Projections.count("实体类属性名称")
获取该属性有属性值的数据条记录数。
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 统计查询
@Test
public void testQBC04() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 获取数据库表中具有uid属性值的数据条数
criteria.setProjection(Projections.count("uid"));
Long count = (Long) criteria.uniqueResult();
System.out.println(count);
tx.commit();
session.close();
}
}
2.5、分页查询
QBC 和 HQL 中的分页查询所用的方法和方法的含义是一模一样的。通过 query.setFirstResult(0)
和 query.setMaxResults(2)
方法分别设置查询的开始位置和每页显示的数量,从而达到分页查询的效果。
query.setFirstResult(0)
:设置查询的开始位置,从0开始query.setMaxResults(2)
:设置每页的显示数据量
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 分页查询
@Test
public void testQBC05() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 设置分页条件
criteria.setFirstResult(0);
criteria.setMaxResults(2);
List users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.6、投影查询
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 投影查询
@Test
public void testQBC06() {
Session session = HibernateUtil.openSession();
Transaction tx = session.beginTransaction();
tx.begin();
Criteria criteria = session.createCriteria(User.class);
// 通过Projections.projectionList().add()添加所要查询的属性名
criteria.setProjection(
Projections.projectionList().add(Property.forName("username")).add(Property.forName("password")));
List users = criteria.list();
for (User user : users) {
System.out.println(user);
}
tx.commit();
session.close();
}
}
2.7、离线查询
在 JavaWeb 项目中,客户端查询实体总共经以下步骤:
- 客户端提交查询条件;
- 表现层 servlet 接收到客户端提交的查询条件,开启
Session
和Transaction
,创建Criteria
对象,将查询条件封装到所创建的criteria
对象中,并将criteria
对象传递到业务层; - 业务层将接收的
criteria
对象传递给持久层; - 持久层接收
criteria
对象,查询数据库,并将查询结果依次传递给业务层、表现层,最后传递到客户端;
存在问题:
此时发现,在表现层中出现了开启 Session
和 Transaction
,创建 Criteria
对象等属于持久层的操作,不符合 MVC
的程序设计规范,对后期程序的维护造成压力;
解决方式:使用 QBC 查询的离线查询,创建 DetachedCriteria
对象,该对象的获取不需要 Session
,可以直接获得。
- 客户端提交查询条件,
- 表现层 servlet 接收到客户端提交的查询条件,创建
DetachedCriteria
对象,封装查询条件;并将criteria
对象传递到业务层; - 业务层将接收的
DetachedCriteria
对象传递给持久层; - 持久层接收
DetachedCriteria
对象,将其转化成为Criteria
对象,查询数据库,并将查询结果依次传递给业务层、表现层,最后传递到客户端;
package com.hibernate.test;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import com.hibernate.domain.User;
import com.hibernate.utils.HibernateUtil;
public class TestQBC {
// 模拟表现层 —— Servlet
@Test
public void servletDetachedCriteria() {
// 创建DetachedCriteria对象
DetachedCriteria dc = DetachedCriteria.forClass(User.class);
// 封装客户端提交的查询条件
dc.add(Restrictions.like("nickname", "%蚂蚁%"));
// 将封装好查询条件的DetachedCriteria对象传递给业务层
List users = seviceDetachedCriteria(dc);
for (User user : users) {
System.out.println(user);
}
}
// 模拟业务层代码
public List seviceDetachedCriteria(DetachedCriteria dc) {
Session session = null;
Transaction tx = null;
try {
// 获取与当前线程绑定的 Session 对象
session = HibernateUtil.getCurrentSession();
tx = session.beginTransaction();
tx.begin();
return daoDetachedCriteria(dc);
} catch (Exception e) {
tx.rollback();
} finally {
tx.commit();
}
return null;
}
// 模拟持久层代码
public List daoDetachedCriteria(DetachedCriteria dc) {
// 获取当前线程绑定的session
Session session = HibernateUtil.getCurrentSession();
// 将业务层传递的DetachedCriteria对象转化为Criteria对象
Criteria criteria = dc.getExecutableCriteria(session);
// 返回查询结果集
return criteria.list();
}
}