1.Hibernate Query Language课程介绍
HQL查询子句
检索对象——from子句(指定要查询的持久化对象)
选择——select子句(选择查询持久化对象中的指定属性 )
限制——where子句(限制持久化对象的查询范围)
排序——order by子句(对查询结果进行排序)
学习目标:
1、了解HQL定义以及HQL语句形式;
2、掌握Query对象的使用;
3、能够编写出符合数据查询要求的HQL语句
2.了解HQL
HQL定义
Hibernate query language的缩写,hibernate查询语言
HQL和SQL语言比较相似,HQL是面向对象的查询语言。HQL映射配置的持久化类及其属性,SQL则是数据库表。除此之外,从数据库查询方面的功能上来讲,SQL能实现的数据库查询功能,HQL几乎可以同样实现。实际上作为一个ORM对象关系映射框架,Hibernate框架会将编写好的HQL语句解析成SQL语句来完成最终的数据库查询操作。
HQL提供了丰富灵活的查询特性,是Hibernate官方推荐查询方式。HQL语句形式
select子句:用来指定查询结果中的对象和属性,并指定以何种数据类型返回 (在最前面)
from子句:用来指定hql语句的查询目标,即映射配置的持久化类及其属性
where子句:逻辑表达式,用来设置查询条件,限制返回结果和范围
group by子句:分组查询语句
having子句:对分组进行限制条件设置
order by子句:用来指定查询结果中的实例对象的排序
注:From子句在HQL语句中不可或缺的组成部分,一个最简单的HQL语句形式只要有from就可以了,其他的子句都可以省略,这点与SQL语句不同
- 初学HQL要注意的问题
1、HQL是面向对象的查询语言,其查询主体是持久化类及其属性,而SQL查询主体是数据库表与表的字段;HQL对Java【类与属性大小写敏感】,SQL语句对大小写不敏感;
2、HQL与SQL在形式上非常相似,特别是HQL在设计上尽量符合之前SQL开发人员的开发习惯,在使用上非常容易与SQL混淆,但是我们不能被表象所迷惑,要认清本质;
3、HQL对【关键字不区分大小写】,比如之前提到的几个SQL子句其中的关键字,from,where,group by,having,order by…等,只要拼写正确,大小写并不重要,但是为了代码的可读性与美观性,习惯上对HQL的所有关键字小写
3.准备查询–org.hibernate.Query接口
准备查询
1.org.hibernate.Query接口
2.准备查询–Query实例的创建
3.执行查询
Query接口简介
1.org.hibernate.Query接口定义有执行查询的方法(该方法完成HQL语句的解析与执行过程,并返回查询的结果。就像SQL语句没有jdbc接口,它也就是普通的字符串变量,HQL语句也一样,编写好的HQL语句也就是一个普通的字符串变量,而hibernate框架就负责解析HQL语句,然后根据配置信息生成相应的SQL语句来执行数据库的查询操作,那么完成这个过程依靠的就是Query接口);
2.Query接口支持方法链编程风格,使得程序代码更为简洁(方法链编程:调用方法后,返回的结果依然是调用这个方法的对象,可以在调用方法后直接调用该对象的其他方法,这样可以使用一个程序语句完成多个方法的调用与执行。在Query接口中,方法链编程使用最多的场景是查询参数的动态设置,特别是多个参数的设置)
3.Query实例的创建:
a.Session的createQuery()方法创建Query实例
b.createQuery方在调用时需要传递一个参数(即要查询的HQL语句),createQuery(hql)
4.Query执行查询
a.Query接口的list()方法执行HQL查询
b.list()方法返回结果数据类型为java.util.List,List集合中存放符合查询条件的持久化对象
4.Query接口应用编程示例
HQL语句中可以直接使用”from 类名”就可以查询到此类对应数据库表中的所有信息.不需要像sql那样”select*from 表名”,直接”form 类名”即可.
list()方法返回的是HQL语句所查询的类的持久化对象的集合.所以一般定义一个带泛型的List集合来存储.
Query query=session.createQuery("from Student");
List<Student> list=query.list();
for(List l:list){
System.out.println(l);
}
注意:HQL是面向对象的查询,查询的是类,不像sql一样,直接查询表.因此在from 后面加的是类名(注意大小写).list()方法会根据查询的类名然后去映射文件中找到相应的数据库表,此时便把HQL语句解析成sql语句.再查询到相应的记录,最后返回记录的持久化对象的集合.
对于Hiberante5.2.4,query.list()方法已经弃用:
public class SelletTest {
private Session session;
private Transaction transaction;
@Before
public void setUp() {
session = HibernateSessionFactory.openSession();
transaction=session.beginTransaction();
}
@Test
public void selletTest() {
String hql = "from Seller";
Query query = session.createQuery(hql, Seller.class);
// 注:hibernate5.2.4已经弃用了query.list()方法
List<Seller> sellers = query.getResultList();
for (Seller seller : sellers) {
System.out.println(seller);
}
}
@After
public void destroy(){
}
}
在这里我还遇到了什么问题呢?
用list方法是可以正常使用的,但是运行后在控制台却报错了,有一个类在运行时找不到了,antlr类,这个类缺乏之后在创建hql语句这个环节就会报错。antlr.jar,/hibernate/lib/required,Another Tool for Language Recognition,可以构造语言识别器,解析HQL需要的jar包。下载之后就成功了,注意报错是有两个一个是运行时无法找到类,还有一种是找不到类,有所区别
5.检索对象—from子句
from子句简介
1.最简形式,唯一不可或缺的子句。
2.为什么跟sql语句相比没有select也能使用呢?这是因为from指定了hql语句查询主体——持久化类及属性,当我们编写的HQL语句只有from子句时,HQL框架默认查询该持久化类的所有实例以及该持久化类映射配置的信息,当HQL框架将HQL解析成SQL时,就会查询该持久化类映射的数据表中的所有映射字段信息,并将返回的查询结果封装成该持久化类的list集合
3.默认情况下,hibernate是不做外键的查询操作的,当需要用到外键是才会去查询外键所对应的持久类,在控制台输出语句中,已经输出过的外键所对应的持久类查询sql语句不再重复输出。from子句中持久化类的引用
1.不需要引入持久化类的全限定名,直接引入类名
全限定名:com.imooc.entity.Seller 类名:Seller
2.auto-import(自动引入)缺省情况,hibernate中解析hql语句时,会根据映射配置信息,自动完成持久化类的导入,写不写结果是一样的,为了简便所以直接写类名即可别名的使用
1.可以通过AS关键字(也可以省略)为被查询的类指定别名
2.在HQL语句其他部分通过别名引用该类(引用的持久化类较多不止一个时会方便很多)
3.别名命名习惯:与持久化类名相同,全部采用小写,可以参考Java变量名的命名;如果为了简洁,可以采用单字母命名
"from Seller s,Student st"
6.选择—select子句
选择—select子句
- 以Object[]形式返回选择的属性:
如果我们在select子句中只是指定了选择的对象和属性,但是没有指定返回的数据类型,那么默认查询结果就会以对象数组的形式来返回,默认object[]数组类型。
注意:
select子句中未指定返回数据类型,默认为Object[]
HQL的select查询语句中,如果指定了多个查询字段,则返回的是一个Object[]数组;如果只指定了一个查询字段,则返回的是一个Object对象。
public static void queryHibernate() {
Session session=HibernateUtil.getSession();
String hql="select s.sname,s.sex from Student s";
Query q=session.createQuery(hql);
List<Object[]> ls= q.list();
for (Object[] object : ls) {
System.out.println(object[0]);
System.out.println(object[1]);
}
HibernateUtil.closeSession(session);
}
//如果是单个查询字段的话就只需要把上面的Object[]中的[]去掉,打印输出时不需要指明下标,同时应当注意写语句要注意区分大小写。否则属性名系统会识别不了,对大小写比较敏感
- 以List形式返回选择的属性
以list形式返回,select子句中使用new list指定返回形式
public static void queryHibernate() {
Session session=HibernateUtil.getSession();
String hql="select new List(s.sname,s.sex) from Student s";
Query q=session.createQuery(hql);
List<List> ls= q.list();
for (List list: ls) {
System.out.println(list.get(0));
System.out.println(list.get(1));
}
HibernateUtil.closeSession(session);
}
- 以map形式返回选择的属性
需要在select子句中使用new map来指定返回数据类型,并且要注意在获取值的时候,map中的key值是我们属性在select子句中的相应的索引值,它的类型是字符串类型。
public static void queryHibernate() {
Session session=HibernateUtil.getSession();
String hql="select new Map(s.sname,s.sex) from Student s";
Query q=session.createQuery(hql);
List<Map> ls= q.list();
for (Map list: ls) {
System.out.println(list.get("0"));//注意这个key值就是我们属性在select子句中相应的位置信息,字符串类型
System.out.println(list.get("1"));
}
HibernateUtil.closeSession(session);
}
//除此之外还可以通过别名方式来获取我们的属性信息
public static void queryHibernate() {
Session session=HibernateUtil.getSession();
String hql="select new Map(s.sname as name,s.sex as se) from Student s";
Query q=session.createQuery(hql);
List<Map> ls= q.list();
for (Map list: ls) {
System.out.println(list.get("name"));
System.out.println(list.get("se"));
}
HibernateUtil.closeSession(session);
}
- 以自定义类型返回选择的属性
首先我们要在持久化类中定义相应的构造器
然后在select子句中定义相应的构造器以自定义类型来返回查询的结果
//实体类构造函数
public Student(String sname, String sex) {
super();
this.sname = sname;
this.sex = sex;
}
//测试方法
public static void queryHibernate() {
Session session=HibernateUtil.getSession();
String hql="select new Student(s.sname,s.sex) from Student s";
Query q=session.createQuery(hql);
List<Student> ls= q.list();
for (Student list: ls) {
System.out.println(list.getSname());//注意这个key值就是我们属性在select子句中相应的位置信息,字符串类型
System.out.println(list.getSex());
}
HibernateUtil.closeSession(session);
}
关于持久化类中无参构造方法的必要性
增加自定义构造器,一定要补充默认构造器,否则hql=” from classname” 会出错,因为在Hibernate没有指定查询返回集合的时候,Hibernate会自动去找默认构造器
- 获取独特的结果-distinct关键字
使用distinct关键字去除查询结果中的重复元素
String hql="select distinct c.sex from Customer c";
注:1、distinct使用时只能放在查询语句的第一个字段前面,且只对查询单个字段才有过滤效果。
2、如果查询语句中包含多个字段时,那么distinct将不再具有过滤功能,但运行也不会报错。
3、如果distinct没有放在查询语句的第一个字段前面, 或语句存在多个distinct,运行会出错。
7.限制—where子句
- 比较运算
1.=,<>,<,>,>=,<=
2.null值判断——is null或者 is not null
String hql="from Student s where s.age>16";
null值判断运算
is null 和 = null在HQL中是相同的
is not null 和 <>null 也是相同语义。
但!在SQL中不能使用=null,以及<>null
String hql="from Student s where s.age is null";
String hql="from Student s where s.age = null";
String hql="from Student s where s.age <> null";
- 范围运算
1.[not] in(列表)(列表既可以明确指出,也可以是子查询)
2.[not] between 值1 and 值2
String hql = "from Customer as c where c.age in(20,40)";
String hql = "from Customer as c where c.age not in(20,40)";
String hql = "from Customer as c where c.age between 20 and 40";
String hql = "from Customer as c where c.age not between 20 and 40";
- 字符串模式匹配
1.like关键字
2.通配符%(可以匹配任意个字符)、_(匹配一个字符)
//模糊查询匹配
String hql = "from Customer as c where c.name like '张_'";
String hql = "from Customer as c where c.address like '%北京%'";
- 逻辑运算
1.and(逻辑与)、or(逻辑或)
2.not(逻辑非)
String hql="from Commodity c where c.price between 100 and 4000 and c.category like '%电脑%'";
String hql1="from Commodity c where c.price between 100 and 4000 or c.category like '%电脑%'";
- 集合运算(是hql语句中比较特殊的运算符)
1.is [not] empty 集合[不]为空,不包含任何元素(转换为SQL语句中的exists运算)
2.member of 元素属于集合(转换为SQL语句中的in运算)
String hql = "from Order where o.orderItems is not empty ";
在HQL中使用+、-、*、/运算符
1.HQL语句中也可以使用+ - * / 四则运算
2.四则运算可以在where子句和select子句中使用查询单个对象(uniqueResult方法)
query接口的uniqueResult方法
1.该方法的返回是实例对象而不是返回集。
2.使用uniqueResult需要在where保证只有一个返回结果或者不存在,如果有多个,则会抛出异常
//查询单个对象 uniqueResult
String hql = "from Customer as c where c.id=1";
Query query = session.createQuery(hql);
Customer c = (Customer)query.uniqueResult();
System.out.println(c);
8.orderby子句
通过order by 子句对查询结果排序
1.升序排序 asc,默认使用升序排序
2.降序排序 desc
多个排序规则用“,”隔开;表示前一个规则中排序条件相同则用后一个排序规则
String hql = "from Commodity order by price asc"; // 升序
String hql = "from Commodity order by price desc"; // 降序
String hql = "from Commodity order by seller.id asc ,price desc, name asc";