hibernate之HQL
1.HQL介绍:
HQL检索方式:使用面向对象的HQL查询语言:
HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相似。在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。它有如下功能:
在查询语句中设定各种查询条件
支持投影查询,即仅检索出对象的部分属性
支持分页查询
支持连接查询
支持分组查询,允许使用HAVING和GROUP BY关键字
提供内置聚集函数,如sum(), min()和max()
支持子查询
支持动态绑定参数
能够调用用户定义的SQL函数或标准的SQL函数
HQL检索方式包括以下步骤:
通过Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句,HQL查询语句可以包含命名参数
动态绑定参数
调用Query相关方法执行查询语句;
2. hql和sql区别/异同
HQL SQL
类名/属性 表名/列名
区分大小写,关键字不区分大小写 不区分大小写
别名 别名 as a
?,从下标0开始计算位置(hibernate5之后不支持) ?,从顺序1开始计算位置
:命名参数 不支持:命名参数
面向对象的查询语言 面向结构查询语言
3. 处理返回的结果集
测试类(HqlTest):
完整的HqlTest.java:
package com.cbw.five.test;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.cbw.foer.entity.Book;
import com.two.uitl.SessionFactoryUtils;
public class HqlTest {
private Session session;
private Transaction transaction;
@Before
public void before() {
session = SessionFactoryUtils.openSession();
transaction = session.beginTransaction();
}
@After
public void after() {
transaction.commit();
session.close();
}
/**
* 返回对象(多个)
*/
@Test
public void testList1() {
Query query = session.createQuery("from Book");
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
/**
* 返回单个列段,用字符串就可以接受
*/
@Test
public void testList2() {
Query query = session.createQuery("select b.bookName as ss from Book b");
List<String> list = query.list();
for (String b : list) {
System.out.println(b);
}
}
/**
* 查两个列段及以上,默认返回的是Object【】
*/
@Test
public void testList3() {
Query query = session.createQuery("select b.bookId,b.bookName as ss from Book b");
List<Object[]> list = query.list();
for (Object[] b : list) {
System.out.println(Arrays.toString(b));
}
}
/**
* 注意map是函数,所以不区分大小写,返回的是map集合
*/
@Test
public void testList4() {
Query query = session.createQuery("select new mAp(b.bookId,b.bookName) from Book b");
List<Map> list = query.list();
for (Map b : list) {
System.out.println(b);
}
}
/**
* 查两个列段及以上,也可返回对象,前提是有对应的构造函数
*/
@Test
public void testList5() {
Query query = session.createQuery("select new Book(b.bookId,b.bookName) from Book b");
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
/**
* HQL语句支持占位符
*/
@Test
public void testList6() {
// Query query = session.createQuery("from Book where bookId = :bookId");
// query.setParameter("bookId", 1);
// Book b = (Book) query.getSingleResult();
// System.out.println(b);
Query query = session.createQuery("from Book where bookId in (:bookIds)");
query.setParameterList("bookIds", new Integer[] {1,2,4});
// List<Integer> params = new ArrayList<Integer>();
// params.add(1);
// params.add(2);
// params.add(4);
// query.setParameterList("bookIds", params);
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
/**
* HQL支持连接查询
*/
@Test
public void testList7() {
Query query = session.createQuery("select o.orderNo,oi.quantity from Order o,OrderItem oi where o = oi.order");
List<Object[]> list = query.list();
for (Object[] b : list) {
System.out.println(Arrays.toString(b));
}
}
/**
* HQL支持聚合函数
*/
@Test
public void testList8() {
Query query = session.createQuery("select count(*) from Book");
Long singleResult = (Long) query.getSingleResult();
System.out.println(singleResult);
}
/**
* HQL分页
*/
@Test
public void testList9() {
Query query = session.createQuery("from Book");
query.setFirstResult(2);
query.setMaxResults(3);
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
}
单个测试:
3.1 单个对象
select没有逗号
/**
* 返回对象(多个)
*/
@Test
public void testList1() {
Query query = session.createQuery("from Book");
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
结果:(把数据库中多个对象查出)
3.2
返回单个列段,用字符串就可以接受
如果只查询单个属性,那只能用字符串接受
/**
* 返回单个列段,用字符串就可以接受
*/
@Test
public void testList2() {
Query query = session.createQuery("select b.bookName as ss from Book b");
List<String> list = query.list();
for (String b : list) {
System.out.println(b);
}
}
结果:
3.3
Object[] 接受
b.bookId, b.bookName
查两个列段及以上就不能用Stirng接受了,默认返回的是Object【】
/**
* 查两个列段及以上,默认返回的是Object【】
*/
@Test
public void testList3() {
Query query = session.createQuery("select b.bookId,b.bookName as ss from Book b");
List<Object[]> list = query.list();
for (Object[] b : list) {
System.out.println(Arrays.toString(b));
}
}
3.4 Map
注意map是函数,所以不区分大小写,返回的是map集合
new Map(b.bookId as bid, b.bookName as bname)
/**
* 注意map是函数,所以不区分大小写,返回的是map集合
*/
@Test
public void testList4() {
Query query = session.createQuery("select new mAp(b.bookId,b.bookName) from Book b");
List<Map> list = query.list();
for (Map b : list) {
System.out.println(b);
}
}
结果:(会标出相应的下标)
3.4 new 构造方法(attr1,attr2)
new Book(b.bookId, b.price)
单个列段
/**
* 查两个列段及以上,也可返回对象,前提是有对应的构造函数
*/
@Test
public void testList5() {
Query query = session.createQuery("select new Book(b.bookId,b.bookName) from Book b");
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
构造函数
public Book(Integer bookId, String bookName) {
super();
this.bookId = bookId;
this.bookName = bookName;
}
结果( 查两个列段及以上,也可返回对象,前提是有对应的构造函数):
4. hql中使用占位符
4.1 ?占位符
从下标0开始计算位置
hibernate5之后不再支持?占位符
4.2 :命名参数
/**
* HQL语句支持占位符
*/
@Test
public void testList6() {
// Query query = session.createQuery("from Book where bookId = :bookId");
// query.setParameter("bookId", 1);
// Book b = (Book) query.getSingleResult();
// System.out.println(b);
Query query = session.createQuery("from Book where bookId in (:bookIds)");
//数组
query.setParameterList("bookIds", new Integer[] {1,2,7});
//集合
// List<Integer> params = new ArrayList<Integer>();
// params.add(1);
// params.add(2);
// params.add(7);
// query.setParameterList("bookIds", params);
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
不仅支持传数组,还有集合
结果(查询1。2。7):
5. 连接查询
/**
* HQL支持连接查询
*/
@Test
public void testList7() {
Query query = session.createQuery("select o.orderNo,oi.quantity from Order o,OrderItem oi where o = oi.order");
List<Object[]> list = query.list();
for (Object[] b : list) {
System.out.println(Arrays.toString(b));
}
}
结果(查询出所有的映射关系)
6. 聚合函数
sum
avg
max
min
count
/**
* HQL支持连接查询
* sum
* count
* avg
* min
* max
*/
@Test
public void testList7() {
Query query = session.createQuery("select o.orderNo,oi.quantity from Order o,OrderItem oi where o = oi.order");
List<Object[]> list = query.list();
for (Object[] b : list) {
System.out.println(Arrays.toString(b));
}
}
结果(返回单行单列的数据,符合要就):
- hql分页
query.setFirstResult((page - 1) * row);// 设置起始记录下标
query.setMaxResults(row);// 设置返回的最大结果集
/**
* HQL分页
*/
@Test
public void testList9() {
Query query = session.createQuery("from Book");
query.setFirstResult(5);
query.setMaxResults(5);
List<Book> list = query.list();
for (Book b : list) {
System.out.println(b);
}
}
结果:
通用查询hql baseDao
版本一
通用 beasDao
public List<Book> list(Book book,PageBean pageBean){
Session session = SessionFactoryUtils.openSession();
String hql = "from Book where 1=1";
String bname = book.getBookName();
if(StringUtils.isNotBlank(bname)) {
hql +=" and bookName like :bookName";
}
Query query = session.createQuery(hql );
// 当 bname 不等于空的时候赋值
if(StringUtils.isNotBlank(bname)) {
query.setParameter("bookName", bname);
}
// 分页
if(pageBean !=null && pageBean.isPagination()) {
// 设置pageBean 起始下标
query.setFirstResult(pageBean.getStartIndex());
query.setMaxResults(pageBean.getRows());
}
List list = query.list();
return list;
}
问题:每增加一个查询就需要写一个这种语句,如果数量过多的话,导致重复代码过多。
版本二
通用 beasDao
package com.cbw.xFive.util;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.query.Query;
/**
* 基于hql语句的通用查询通用工具类
* 1、需要给拼接的hql语句的命名参数赋值(可以简化的)
* 2、分页(可以简化)
*
* 基于sql的分页的查询的做法
* 1、首先要查询出符合条件的总记录数
* 2、返回符合条件的记录
* 参数:sql ,pageBean,Class clz
* 1、 countSql = select count(*) from (sql) t;
* 2、 pageSql = sql + " limit " +start +" , " +rows
*
* 基于hql的分页的查询的做法
* hql = from Book where bookName like "%xxx%"
* hql = select * from Book where bookName like "%圣墟%"
* 1、countHql = select count(*) hql
*
*
* @author 17628
*
*/
public class BeasDao {
/**
* @param query 里面包含了带有参数的hql 语句,需要等待赋值
* "from Book where 1=1 and bookName like :bookName
* @param map
* =request.getParameterMap();
*/
public void setParam(Query query, Map<String, Object> paramMap) {
if(paramMap !=null && paramMap.size()!=0) {
// 遍历 paramMap 集合 得到前台传来的数据
Set<Entry<String, Object>> entrySet = paramMap.entrySet();
for (Entry<String, Object> entry : entrySet) {
// 遍历之后,给 query 赋值
String key = entry.getKey();
Object value = entry.getValue();
// 我们这里要考虑以下 传过来的是数组 还是集合
if(value instanceof Object[]) {
// 当 value 为数组时
query.setParameter(key, (Object [])value);
}else if(value instanceof Collection){
// 当 value 为集合时
query.setParameter(key, (Collection)value);
}else {
// 普通字符串
query.setParameter(key, value);
}
}
}
}
/**
* 拼装符合条件的总记录数
* 2、countHql = select count(*) hql
* hql 可以能为以下两种情况
* hql = from Book where bookName like "%xxx%"
* hql = select * from Book where bookName like "%圣墟%"
* 所以通过截取得到 from和后面的条件
*
* @param hql
* @return
*/
public String getCountSql(String hql) {
// toUpperCase() 转大写 。因为hql 区分大小写 ,我们干脆把hql语句转成 大写
// indexOf() 取 FROM 的下标
int fromIndex = hql.toUpperCase().indexOf("FROM");
return "select count(*)"+hql.substring(fromIndex);
}
/**
* 基于hql通用查询方法
*
* @param hql 最终传来的 hql 语句
* @param pageBean 分页
* @param paramMap =request.getParameterMap(); 前台传来的 值
* @param session 创建 Query 对象
* @return
*/
public List executeQuery(String hql,PageBean pageBean,Map<String,Object> paramMap,Session session) {
List list = null;
Query query = null;
if(pageBean != null && pageBean.isPagination()) {
// 获取查询的总数量
String countHql =getCountSql(hql);
Query createQuery = session.createQuery(countHql);
this.setParam(createQuery, paramMap);
//将总行数放入PageBean对象
pageBean.setTotal(createQuery.getSingleResult().toString());
// 返回符合条件的记录
query = session.createQuery(hql);
//给预定于的hql语句的命名参数赋值。有多少赋多少
this.setParam(query, paramMap);
//设置开始位置(下标从0开始)
query.setFirstResult(pageBean.getStartIndex());
//这是偏移量,就是一页展示几条数据
query.setMaxResults(pageBean.getRows());
list=query.list();
}else {
// 不分页
query=session.createQuery(hql);
this.setParam(query, paramMap);
list=query.list();
}
return list;
}
}
BookDao
它需要继承 BaseDao
public List<Book> listPlus(Book book,PageBean pageBean){
Session session = SessionFactoryUtils.openSession();
String hql = "from Book where 1=1";
String bname = book.getBookName();
// 这个是jsp 自动传递过来的,不与要手写,模拟一下
Map<String, Object> map = new HashMap<String, Object>();
if(StringUtils.isNotBlank(bname)) {
hql +=" and bookName like :bookName";
map.put("bookName", bname);
}
List list = super.executeQuery(hql, pageBean, map, session);
session.close();
return list;
}
JUnit 测试
@Test
public void testList11() {
Book b = new Book();
PageBean pageBena = new PageBean();
pageBena.setPage(3);
// b.setBookName("%圣墟%");
List<Book> list = this.bookDao.listPlus(b, pageBena);
for (Book book : list) {
System.out.println(book);
}
}