Hibernate提供了几种检索方式,包括HQL,QBC,QBE。
一、HQL(Hibernate Query Language)
HQL查询时一种面向对象的查询,没有表,字段的概念,而是使用类,对象,属性的概念来查询所需要的信息。
如果使用传统的JDBC API来查询数据,需要编写SQL语句,面向的是数据库中的表和属性,然后还要将查询结果以对象的形式放到集合中存储。Hibernate已经将数据库中的表格和对象POJO相对应,因此可以直接面向对象(及其属性)查询所需要的数据,直接保存到List对象中,不用再次封装。
Hibernate支持属性查询(投影查询,动态实例查询),条件查询(参数查询),连接查询,分页查询,内置聚集函数。
下面将列举一些例子,看一下Hibernate中HQL查询是怎么进行的,以及不同查询的HQL语句的格式。
使用HQL查询时,可以遵循以下步骤:
获得Session对象-->编写HQL语句-->创建Query对象-->执行查询,获得结果-->对结果进行处理
1、查询所有图书对象
假设有一个表格Books,在Hibernate中POJO为Books,字段有title,author,price。要求查询所有的图书信息。
public class TestHQL {
public static void main (String[] args){
TestHQL t=new TestHQL();
t.exeHQL_1();
}
public void exeHQL_1(){
//获得Session
Session session= HibernateSessionFactory.getSession();
//编写HQL语句
String hql="from Books";
//创建Query对象
Query query=session.createQuery(hql);
//执行查询,获得结果
List list=query.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
Books book=(Books) itor.next();
//book中得到的是数据库中的一条记录,也是一个Books对象
}
}
}
2、对查询结果进行排序
重写TextHQL对象的exeHQL方法,将查询的图书结果按照价格降序排列。HQL语句中添加 "order by [属性] desc"
。
public void exeHQL_2(){
//获得Session
Session session = HibernateSessionFactory.getSession();
//编写HQL语句
String hql="from Books as b order by b.price desc";
//创建Query对象
Query query=session.createQuery(hql);
//执行查询,获得结果
List list=query.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
Books book=(Books) itor.next();
//book中得到的是数据库中的一条记录,也是一个Books对象
}
}
3、检索图书对象中的部分属性——属性查询(投影查询与动态实例查询)
以上查询的结果是将对象的所有属性都放到结果集中,但是有的时候我们不需要这么多属性,在数据库中的一个表中体现,就是只需要这个表的几个列(字段),而在对象中体现,就是我们只需要这个对象的部分属性。
重写TextHQL对象的exeHQL方法,只查询图书信息中的书名和作者。
public void exeHQL_3(){
//获得Session
Session session = HibernateSessionFactory.getSession();
//编写HQL语句
String hql="select b.title,b.author from Books as b";
//创建Query对象
Query query=session.createQuery(hql);
//执行查询,获得结果
List list=query.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
//因为我们只选取了Books对象中的某两个属性,它已经不是一个Books对象,所以只能用Object来存放查询结果
Object[] object = (Object[]) itor.next();
//分别输出书名和作者
System.out.println(object[0]+" "+object[1]);
}
}
因为在投影查询时,返回的查询结果是一个对象数组,不易操作,因此我们可以将检索出来的属性封装到一个实体类的对象中,这就叫动态实例查询。
首先我们在Books类中添加一个只有书名和作者的构造函数。
public Books (String title ,String author){
this.title=title;
this.author=author;
}
重写TextHQL对象的exeHQL方法,只查询图书信息中的书名和作者,并且将结果属性封装到一个实体类的对象中。
public void exeHQL_4(){
//获得Session
Session session = HibernateSessionFactory.getSession();
//编写HQL语句
String hql="select new Books(b.title,b.author) from Books as b";
//创建Query对象
Query query=session.createQuery(hql);
//执行查询,获得结果
List list=query.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
**Books book= (Books)itor.next();**
//book中是一个只有两个属性的book对象,直接用book.title和book.author来访问该记录的属性
}
}
4、条件查询(参数查询)
在实际应用中,可能最多的是根据指定的条件进行查询,即对于一张表,我们通过某字段满足某条件的筛选,得到我们需要的一些元组(记录)。
依旧使用Books表来举例,比方说我们需要得到与C++有关的书籍(title中有C++),因此sql语句可能是这样的:
select * from Books where title like "%C++%";
那么使用HQL语句可以有两种方式来形容这种匹配,相应也就有个两种条件查询形式,分别是参数位置查询和参数名字查询。
这两种查询形式的区别也就在于这个某字段满足某条件的筛选的形式不同,参数位置查询中用?表示,参数名字查询中以”:”开头,后面跟着参数名字。我们都需要再对这两个筛选条件进行补充。补充的方式是query的setString方法。具体情况有一点不同。总结一下如下所示:
参数位置查询
- 使用?表示条件
query.setString(int index, String value);index表示?在HQL语句中的位置,第一个?的index为0,第二个?的index位置为1,依次类推。
public void exeHQL_5(){
//获得Session
Session session = HibernateSessionFactory.getSession();
//编写HQL语句
String hql=”from Books b where b.title like ? “;
//创建Query对象
Query query=session.createQuery(hql);
//补充hql的条件
query.setString (0,”%C++%”);
//执行查询,获得结果
List list=query.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
Books book= (Books)itor.next();
//book中是一个只有两个属性的book对象,直接用book.title和book.author来访问该记录的属性
}
}
参数名字查询
- 使用”:”开头,后面跟着参数名字。
query.setString(String name,String value);name指HQL中的”:”后面参数名字,value指补充的条件值。
public void exeHQL_6(){
//获得Session
Session session = HibernateSessionFactory.getSession();
//编写HQL语句
String hql=”from Books as b where b.title=:bookTitle”;
//创建Query对象
Query query=session.createQuery(hql);
//补充hql的条件
query.setString(“bookTitle”,”C++ Primer中文版”)
//执行查询,获得结果
List list=query.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
Books book= (Books)itor.next();
//book中是一个只有两个属性的book对象,直接用book.title和book.author来访问该记录的属性
}
}
5、连接查询
数据库的连接查询涉及到多个表(一般涉及到两个表),HQL支持各种连接查询,包括内连接,外连接和交叉连接。
在连接查询这一部分,将不会书写重复的代码,只给出HQL语句的书写。我们给出两个表:
- Books(bookId,title,author,publishers)
- Publishers(publisherId,name)
内连接
内连接是指两个表中指定的关键字相等的值才会出现在查询结果中的一种查询方式。在HQL中使用关键字“inner join”进行内连接。
String hql = "from Books b inner join b.publishers p where p.name='清华大学出版社'";
同样,这样给出的属性是两个表中所有的属性值,可以使用select关键字进行投影查询。
注:b.publishers使用了Hibernate的关联映射。
隐式内连接
隐式内连接诶是指HQL语句中看不到join关键字,但是实际上已经发生了内连接。
String hql = “from Books b,Publishers p where b.publishers=p and p.name='清华大学出版社'";
左外连接
左外连接指:包含left join左表所有行,如果左表中某行在右表没有匹配,则结果中对应行右表的部分全部为空(NULL)。
String hql = "from Books b left join b.publishers p where p.name='清华大学出版社'";
右外连接
右外连接指:包含right join右表所有行,如果右表中某行在左表没有匹配,则结果中对应行左表的部分全部为空(NULL)。
String hql = "from Books b right join b.publishers p where p.name='清华大学出版社'";
6、分页查询
批量查询数据时,在单个页面上显示所有查询结果会存在一些问题。因此Query提供了两个接口用于分页显示:
- setFirstResult(int firstResult):设定从哪个对象开始查询
setMaxResult(int maxResult):设定一次返回多少个对象
public void exeHQL_7(){
//获得Session
Session session = HibernateSessionFactory.getSession();
//编写HQL语句
String hql=”from Books as b order by b.price desc”;
//创建Query对象
Query query=session.createQuery(hql);
//设置分页查询
query.setFirshResult(0);
query.setMaxResult(3);
//执行查询,获得结果
List list=query.list();
//处理结果,结果集中只有3个结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
Books book=(Books) itor.next();
//book中得到的是数据库中的一条记录,也是一个Books对象
}
}
7、内置聚集函数
在HQL语句中,可以使用下列聚集函数:
- count:统计记录总数
- min():最小值
- max():最大值
- sum():总值
avg() :平均值
String hql1 = “select count(b) from Books b”;
String hql2 = “select avg(b.price) from Books b”;
8、子查询
根据外层查询与子查询语句是否有关,分为相关子查询和无关子查询。
相关子查询
检索books表中所有图书数量超过1本的出版社:
String hql = "from Publishers p where (select count(*) from p.bks >1)";
无关子查询
检索所有低于平均价的图书对象:
String hql = "from Books b where (select avg(b1.price) from Books b1 )";
二、 QBC(Query By Criteria)
Criteria是Hibernate API 提供的一个查询接口,它使用一种封装了基于字符串形式的查询语句的API来查询对象。Criteria也是由Hibernate Session创建的。
Criterion和Projection的说明
Criterion
- Criterion是Criterion的查询条件。
- Criterion提供add()方法来添加查询条件。
- Criterion接口的主要实现包括:Example、Junction和SimpleExpression,Junction的实际使用是它的两个子类conjunction和disjunction,分别是使用AND和OR操作符进行连接查询条件集合。
- Criterion接口的Example实现类用来提供QBE(Query By Example)检索方法。
- Criterion的实例可以通过Restirctions工具类来创建,Restrictions提供了大量的静态方法。
Projection
- Project主要是让Criteria能够进行报表查询,并可以实现分组。
- Project主要由SimpleProjection、ProjectionList和Property三个实现。
- 其中SimpleProjection和ProjectionList的实例化是由内建的Projections来完成。
- Property是对某个字段进行查询条件的设置,通过criteria的add(Project)方法加入到查询条件中去。
使用QBC查询时,可以遵循以下步骤:
- 获得Session对象
- 创建Criteria对象
- 使用Restrictions对象编写查询条件,并将查询条件加入到Criteria对象中
- 执行查询,获得结果
- 对结果进行处理
基本查询
public void exeCriteria_1(){
//获得session对象
Session session = HibernateSessionFactory.getSession();
//创建Criteria对象
Criteria criteria = session.createCriteria(Books.class);
//对查询结果暗战编号升序排序
criteria.addOrder(Order.asc("id"));
//执行查询,获得结果
List list=criteria.list();
//处理结果
Iterrator itor = list.iterator();
while(itor.hasNext()){
Books book=(Books) itor.next();
//book中得到的是数据库中的一条记录,也是一个Books对象
}
}
条件查询
通过Restriction工具类的相应方法动态构造查询条件,并将查询条件加入Criteria对象,从而实现查询功能。
首先在main()方法中调用exeCriteria()方法,并传入参数Books对象,Books对象中表明了查询条件。
public void exeCriteria_2(Books condition){
//获得Session对象
Session session = HibernateSessionFactory.getSession();
//创建Criteria对象
Criteria criteria = session.createCriteria(Books.class);
//使用Restrictions对象编写查询条件,并将查询条件放入Criteria中
if(condition!=null){
if(condition.getTitle!=null && !condition.getTitle().equals("")){
criteria.add(Restrictions.like("title",condition.getTitle()));
}
if(condition.getAuthor!=null && !condition.getAuthor().equals("")){
criteria.add(Restriction.like("author",condition.getAuthor()));
}
}
//执行查询,获得结果
List list = criteria.list();
//遍历查询结果
Iterator itor = list.iteratr();
while(itor.hasNext()){
Books book = itor.next();
//获得一个满足条件的Books对象
}
}
在main方法中调用exeCriteria方法,并传入参数:
Books condition =new Books();
condition.setTitle("C++");
condition.setAuthor("美");
tc.exeCriteria_2(condition);
分组查询
public void testCriteria_3(){
//获得session对象
Session session = HibernateSessionFactory.getSession();
//创建Criteria
Criteria criteria = session.createCriteria(Books.class);
//构建ProjectionList对象
ProjectionList pList = Projections.projectionList();
//1.创建分组依据,对出版社进行分组
pList.add(Projections.groupProperty("publishers"));
//2.统计各分组中的记录数
pList.add (Projections.rowCount());
//3.统计各分组中的图书单价总和
pList.add(Projections.sum("unitPrice"));
//为Criteria对象设置Projection
criteria.setProjection(pList);
//执行查询,获得结果
List list = criteria.list();
//遍历查询结果
Iterator itor = list.iteratr();
while(itor.hasNext()){
Object[] obj= (Object[])itor.next();
Publishers publisher = (Publishers)obj[0];
//输出每个出版社的名称,图书总和,单价总和
System.out.println("出版社名称:"+publisher.getName()+" 图书总数:"+obj[1]+" 单价总和" +obj[2]);
}
}