HQL简介
HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:
在查询语句中设定各种查询条件(条件查询)
支持投影查询, 即仅检索出对象的部分属性
支持分页查询
支持连接查询
支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
提供内置聚集函数, 如 sum(), min() 和 max()
支持子查询
支持动态绑定参数
能够调用 用户定义的 SQL 函数或标准的 SQL 函数
说一下hql与sql的不同之处:最大的不同之处就是HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句. HQL 查询语句中的主体是域模型中的类及类的属性。
HQL入门
首先我们来看一下HQL的使用格式:
//进行HQL入门测试
public void test1() {
//创建hql查询语句
String hql = "";
//生成Query对象
Query query = session.createQuery(hql);
//执行hql语句返回结果
List<Kind> list = query.list();
//或
Kind result = (Kind) query.uniqueResult();
}
条件查询
下面我们先来看一下条件查询:条件查询基本上sql语句没有什么差别,只是把主体换成域模型中的类及类的属性,还有一点是在动态绑定参数时可以使用?占位符还可以使用命名占位符。
下面我们写一段代码测试一下:
@Test
//HQL的条件查询之?占位符动态绑定参数
public void test1() {
//创建hql查询语句
String hql = "from Kind where kid = ?";
//生成Query对象
Query query = session.createQuery(hql);
//设置占位符参数
query.setParameter(0,"1");
//执行hql语句返回结果
Kind result = (Kind) query.uniqueResult();
System.out.println(result);
}
@Test
//HQL的条件查询之命名占位符动态绑定参数
public void test2() {
//创建hql查询语句
//命名占位符格式:“:占位符名称”
String hql = "from Kind where kid = :kid";
//生成Query对象
Query query = session.createQuery(hql);
//设置占位符参数
query.setParameter("kid","1");
//
//执行hql语句返回结果
Kind result = (Kind) query.uniqueResult();
System.out.println(result);
}
排序
下面我们来使用一下排序功能,排序功能的hql实现和sql实现相同,只不过得将排序对象换成属性。@Test
//HQL的条件查询之排序
public void test3() {
//order by 属性名 排序规则
String hql = "from Kind order by kid desc";
Query query = session.createQuery(hql);
List<Kind> list = query.list();
for (Kind kind : list) {
System.out.println(kind);
}
}
分页的实现
哦了,下面我们来看一下分页查询的实现代码: @Test
//HQL的条件查询之分页查询
public void test4() {
String hql = "from Kind";
Query query = session.createQuery(hql);
//从第几行查询,从0行开始
query.setFirstResult(0);
//查询几行
query.setMaxResults(2);
List<Kind> list = query.list();
for (Kind kind : list) {
System.out.println(kind);
}
}
投影查询
投影查询,乍一听挺高大上,其实就是他妈的检索部分属性,话不多说,看看他是如何使用的吧!@Test
//HQL的投影查询
public void test5() {
//由于我们的Kind类就两个属性,所以我就以这种形式进行投影查询了,看着还复杂一点
String hql = "select kid,kname from Kind where kid = :kid";
Query query = session.createQuery(hql);
query.setParameter("kid","1");
Object[] kind = (Object[]) query.uniqueResult();
System.out.println(kind[0]);
System.out.println(kind[1]);
}
@Test
//HQL的投影查询
public void test6() {
//由上例可以看出,使用这种方式的投影查询不是很方便,
//我们期望的时返回一个封装到kind对象中的属性,为达到这一点就得看我们hql的了
//以这种方式创建kind对象,并且确保在该类中有其构造函数(注意要写无参构造函数)
String hql = "select new Kind(kname) from Kind where kid = :kid";
Query query = session.createQuery(hql);
query.setParameter("kid","1");
Kind result = (Kind) query.uniqueResult();
System.out.println(result);
}
连接查询
连接查询分类
1)内连接
1内连接
2迫切内连接
2)外链接
1左外连接与迫切左外连接
2右外连接与右外迫切连接
我们先来看一下内连接的知识吧!
先看一个普通内连接的代码演示:
@Test
//HQL的内连接查询
public void test7() {
//Kind k 看似是给Kind起的别名,实则是创建的对象的对象名,且必须设置
//inner join 后面在sql中跟的是另一个表,hql里面是对象.属性 ,当然了,
//这个属性必须在hbm.xml里面是一对多,或多对多。
String hql = "from Kind k inner join k.products where k.kid = :kid";
Query query = session.createQuery(hql);
query.setParameter("kid","1");
//返回值肯定不是一个对象即Object[] 中包含kind对象和product对象
List<Object[]> list = query.list();
for (Object[] object : list) {
System.out.print(object[0].getClass().toString());
System.out.println(object[1].getClass().toString());
}
}
我们在来看一下hibernate为我们编译的sql查询语句吧!
我们再来看一下查询结果的到的数组的类型:
好了,我们在来看一下迫切内连接的代码演示吧!
@Test
//HQL的迫切内连接查询
public void test8() {
//和普通内连接唯一的不同就是加了fetch
String hql = "from Kind k inner join fetch k.products";
Query query = session.createQuery(hql);
//迫切内连接多做了什么工作呢?就多做了一步,
//就是讲我们查询到的product对象封装到了kind对象中
List<Kind> list = query.list();
for (Kind kind : list) {
System.out.println(kind);
}
}
至于外连接我就不说了,和内连接没有什么差别,就是把几个关键字换一换。
其实我挺不明白这些什么连接的,既然是连接就一定是由某种关联关系,而hibernate会为我们级联查找,我很奇怪这个连接查询有什么用呢,可能是我经历太少的原因,这一点日后再来解答。
注意我们使用HQL查询到的对象,也放入了session的二级缓存中了。什么意思呢?就是你也可以对其进行直接修改hibernate会在提交事物时自动刷新缓存的内容到更新到数据库中。
代码证明:
@Test
//证明HQL查询出来的对象放入了二级缓存中
public void test8() {
String hql = "from Kind where kid = :kid";
Query query = session.createQuery(hql);
query.setParameter("kid","5");
Kind object = (Kind) query.uniqueResult();
System.out.println(object);
object.setKname("情趣生活");
}
上面的kid查询kind的sql语句我就不截图了,我们只看剩下的:
看到了吧!