7.HQL
Hibernate 支持两种主要的查询方式
(1)HQL(Hibernate Query Languge,Hibernate 查询语言)查询,,是一种面向对象的查询语言,其中没有表和字段的概念,只有类、对象和属性的概念;
HQL 是应用较为广泛的方式。
(2)Criteria 查询又称为“对象查询”,它用面向对象的方式将构造查询的过程做了封装。
7.1使用HQL需要四步
(1)得到Session;
(2)编写HQL语句;
(3)创建Query对象:Query接口是HQL 查询接口。它提供了各种的查询功能;
(4)执行查询,得到结果。
7.2HQL基本语法
HQL看上去很像SQL,但是我们不要被语法结构上的相似所迷惑,HQL是非常有意识的被设计为完全面向对象的查询。
HQL中没有表和字段的概念,只有类、对象和属性的概念,这点需要大家好好体会。
(1)选择where
where 子句指定限定条件
通过与SQL 相同的比较操作符指定条件
如:
=、<>、<、>、>=、<=
between、not between
in、not in
is、like
通过and、or 等逻辑连接符组合各个逻辑表达式
例如:
@Test
// 选择的测试
public void whereTest() {
String hqlString = "from Book b where lower(b.name) like '%spring%'";
Session session = HibernateUtil.currentSession();
Query query = session.createQuery(hqlString);
List<Book> books = query.list();
System.out.println(books);
}
(2)投影
选择出现在结果集中的字段
默认情况下结果为对象数组组成的集合
可使用结果转换器
@SuppressWarnings("rawtypes")
@Test
// 投影的测试
public void projectionTest() {
Session s = HibernateUtil.currentSession();
String queryString = "select b.name,b.count from Book b";
Query query = s.createQuery(queryString);
List l = query.list();
// 投影的结果:对象数组的集合——集合中的元素是对象数组
// System.out.println(l.get(0).getClass());
for (Object object : l) {
Object[] data = (Object[]) object;
System.out.println("name==" + data[0] + ",count==" + data[1]);
}
}
@SuppressWarnings({ "unchecked" })
@Test
// 使用结果转换器
public void projectionTest2() {
Session s = HibernateUtil.currentSession();
String queryString = "select b.name as name,b.count as count from Book b";
Query query = s.createQuery(queryString);
// 根据别名 装配Book类对象
query.setResultTransformer(new AliasToBeanResultTransformer(Book.class));
List<Book> l = query.list();
for (Book book : l) {
System.out.println("name==" + book.getName() + ",count=="
+ book.getCount());
System.out.println(book.getPress());
}
}
(3)参数绑定有两种方法,分别是利用定位参数和利用命名参数。
通用查询参数绑定方法:
Query接口提供多个设置参数的方法,用来绑定大多数Hibernate内建类型的参数,例如setInteger()、setTimestamp()、setLocale() 等。
还有一种允许绑定任何hibernate类型实参的一般方法setParameter(),该方法可以自动找出正确的类型
@Test
// 参数绑定测试:占位符
public void paramTest1() {
String hqlString = "from Book b where b.name like ?";
Session session = HibernateUtil.currentSession();
Query query = session.createQuery(hqlString);
String name = "Spring";
query.setString(0, "'%" + name + "%'");// 定位参数从0开始计数
List<Book> books = query.list();
}
@Test
// 参数绑定测试:命名参数按参数名字来进行匹配
public void paramTest2() {
String hqlString = "from Book b where b.name like :name";
Session session = HibernateUtil.currentSession();
Query query = session.createQuery(hqlString);
String name = "Spring";
query.setString("name", name);// 命名参数按参数名字来进行匹配
List<Book> books = query.list();
}
@Test
// 参数绑定测试: 通用的传参方法
public void paramTest3() {
String hqlString = "from Book b where b.name like :name or b.price > :price";
Session session = HibernateUtil.currentSession();
Query query = session.createQuery(hqlString);
String name = "Spring";
// query.setDouble("price", 30f);
// query.setString("name", name);
// 通用的传参方法
query.setParameter("price", 30f);
query.setParameter("name", name);
List<Book> books = query.list();
System.out.println(books);
}
我们也可以在Hibernate中使用定位参数,代码如下:
String hql = "from Position where name like ? and createDay> ?";
Query query = sf.openSession().createQuery(hql). setParameter(0,aName).setParameter(1,aDate);
请记住Hibernate定位参数是从0开始计数的
(4)分页
Query接口支持对查询结果进行分页处理,例如:
query.setFirstResult(40);
query.setMaxResults(20);
这两行代码意味着从第41个对象(setFirstResult方法的参数是开始获取对象的行数,从0开始编号)开始,获取接下来的20个对象(setMaxResults方法的参数是获取对象的数目)。
@Test
// 测试分页
public void pagerTest() {
String hqlString = "from Student";
Session session = HibernateUtil.currentSession();
Query query = session.createQuery(hqlString);
query.setFirstResult(10);
query.setMaxResults(10);
List<Student> students = query.list();
System.out.println(students);
}
(5)分组函数
组函数有count()、min()、max()、sum()和avg(),其含义和SQL中定义的一样。
@Test
// 分组与统计
public void groupTest() {
Session s = HibernateUtil.currentSession();
String queryString = "select count(*) from Book b";
Query query = s.createQuery(queryString);
long i = (Long) query.uniqueResult();// 获得单个值
System.out.println("书籍数目:" + i);
}
(6)连接查询
@Test
public void joinTest2() {
Session s = HibernateUtil.currentSession();
String queryString = "select b,t from Book b join b.type t";// 按属性来做连接查询
Query query = s.createQuery(queryString);
List list = query.list();
for (Object obj : list) {
Object[] pair = (Object[]) obj;
Book book = (Book) pair[0];
Type type = (Type) pair[1];
System.out.println(book.getName() + ",类型是:" + type.getName());
}
}
查询中的延迟加载
默认的Hibernate采用延迟加载策略:主对象的关联对象或集合并不是立即抓取的,加载主对象时,关联对象或集合为代理对象(假设为对象,却没有源对象的值),只有到使用这些关联对象的时候,才会被初始化(加载)。
可使用强制热抓取关联数据: fetch
@Test
// fetch join 强制热抓取关联数据,改变默认加载策略(延迟的)
public void joinTest3() {
Session s = HibernateUtil.currentSession();
String queryString = "select b from Book b join fetch b.type ";// 按属性来做连接查询
Query query = s.createQuery(queryString);
List<Book> list = query.list();
for (Book book : list) {
System.out.println(book.getName() + ",类型是:"
+ book.getType().getName());
}
}
(7)子查询
@Test
// 查询借阅次数最多的学生
public void subSelectTest() {
//按借书的多少查找出学生的排名
String hql = " select rc.stu.id from Record rc group by rc.stu order by count(rc.stu) desc";
Query query = HibernateUtil.currentSession().createQuery(hql);
query.setMaxResults(1);
int stu_id = (Integer) query.uniqueResult();
Student student = (Student) HibernateUtil.currentSession().get(Student.class, stu_id);
System.out.println(student);
}