HIbernate提供了以下几种检索对象的方式:
①、导航对象图检索方式:根据已经加载的对象,导航到其他对象。例如,对于已经加载的Customer对象,调用它的getOrders().iterator()方法就可以导航到所关联的Order对象。
②、OID检索方式:按照对象的OID来检索对象,session的get()和load()方法提供了这种功能。如果在应用程序中事先知道了OID,就可以使用这种检索对象的方式。
③、HQL检索方式:使用面向对象HQL查询语言,Hibernate提供的Query接口,它是Hibernate提供的专门的HQL查询接口,能够执行各种复杂的HQL查询语句。
④、QBC检索方式:使用QBC(Query By Criteria)API来检索对象,
⑤、本地SQL检索方式。
⑥、QBE检索方式:QBC的子功能。
一、Hibernate检索方式简介:
当直接使用JDBC API查询数据库时,必须在应用程序中嵌入冗长的SQL语句。
1、HQL检索方式(Hibernate Query Language) HQL是面向对象查询语言。
2、QBC检索方式(Query By Criteria) QBC API提供了检索对象的另一种方式,它主要是有Criteria接口、Criterion接口和Expression类组成,它支持在运行时动态生成查询语句。
3、QBE检索方式(Query By Example) 它是QBC的子功能。QBE允许先创建一个对象样板,然后检索出所有和这个样板相同的对象。
4、Sql检索方式:Sql检索方与HQL检索方式都使用Query接口,区别在于SQL检索方式通过Session的createSQLQuery()方法来创建Query对象。
二、HQL检索方式
1、使用别名:
通过HQL检索一个类的实例时,如果查询语句的其他地方需要引用它,应该为这个类指定一个别名,例如:from Customer as customer where customer.name=:name。as关键字用于设定别名,也可以将as关键字省略。
2、多条查询:
HQL和QBC都支持多态查询,多态查询指查询出当前类及所有子类的实例。
3、对查询结果排序
HQL与QBC都支持对查询结果排序,HQL采用order by关键字对查询结果排序,而QBC采用Order类对查询结果排序。
//hql检索方式
Query query=session.createQuery("from Customer customer order by customer.name");
//QBC方式
Criteria criteria=session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("name"));
4、分页查询:
Query和Criteria接口都提供了用于分页显示查询结果的方法:
setFirstResult(int firstResult):设定从哪一个对象开始检索。
setMaxResult(int maxResult):设定一次最多检索出的对象数目。
5、检索单个对象
Query和Criteria接口都提供了以下用以执行查询语句并返回查询结果的方法
list()方法:返回一个list类型的查询结果,在List集合中存放了所有满足查询条件的持久化对象。
uniqueResult()方法:返回单个对象
6、在HQL查询语句中绑定参数
session=HibernateUtil.getSession();
Query query=session.createQuery("from Customer as customer where customer.name='"+name+"'");
List customers=query.list();
return customers;
上面的代码尽管可以,但是不安全,Hibernate采用参数绑定机制来避免以上问题,Hibernate的参数绑定机制依赖于JDBC API中PreparedStatement的预定义Sql语句功能。参数绑定有以下优点:
①、非常安全。
②、能够利用底层数据库预编译SQL语句的功能,提供查询数据的性能。预编译是指在底层数据库系统只需要编译SQL语句一次,把编译出来的可执行代码保存在缓存中,如果多次执行相同形式的SQL语句,不需要重新编译,只要从缓存中获得可执行代码即可。
参数绑定的形式有两种:
<1>、按参数名字绑定
在HQL查询语句中定义命名参数,命名参数以“:”开头,形式如下:
Query query=session.createQuery("from Customer customer where customer.name=:name and customer.age=:age");
以上的HQL语句中定义了两个参数:name,age。下面接下里调用Query的setXXX()方法绑定参数。
query.setString("name",name);
<2>、按参数位置绑定
在HQL中使用“?”来定义参数的位置,则HQL为
Query query=session.createQuery("from Customer customer where customer.name=? and customer.age=?");
query.setString(0,name);
query.setInteger(1,age);
7、在映射文件中定义命名查询语句
Hibernate允许再映射文件中定义字符串形式的查询语句。在程序中通过Session的getNamedQuery()方法获取该查询语句。
8、设定查询条件
HQL查询语句也通过where字句来设定查询条件,值得注意是,在where字句中给出的是对象的属性名,而不是字段名。对于QBC查询,必须创建一个Criterion对象来设定查询条件。
HQL和QBC支持的各种运算
HQl运算符 | QBC运算符 | 含义 |
= | Expression.eq() | 等于 |
<> | Expression.not(Expression.eq()) | 不等于 |
> | Expression.gt() | 大于 |
>= | Expression.ge() | 大于等于 |
< | Expression.lt() | 小于 |
<= | Expression.le() | 小于等于 |
is null | Expression.isNull() | 等于空值 |
is not null | Expression.isNotNull() | 非空值 |
in | Expression.in() | 等于列表中的某一值 |
not in | Expression.not(Expression.in()) | |
between 值1 and 值2 | Expression.between() | |
not between 值1 and 值2 | Expression.not(Expression.between()) | |
like | Expression.like() | |
and | Expression.and()或者Expression.conjunction() | |
or | Expressioin.or() | |
not | Expression.not() |
9、连接查询
HQL与QBC也支持各种各样的链接查询,如内连接、外连接和交叉连接,迫切内连接、迫切外连接。
查询类型 | HQL语法 | QBC语法 |
内连接 | inner join或 join | Criteria.createAlias() |
迫切内连接 | inner join fetch 或join fetch | 不支持 |
隐式内连接 | 不支持 | |
左外连接 | left outer join或者left join | 不支持 |
迫切左外连接 | left outer join fetch 或者 left join fetch | FetchMode.EAGER |
右外连接 | right outer join | 不支持 |
交叉连接 | ClassA,ClassB | 不支持 |
三、高级查询-------动态查询
1、HQL与QBC能够完成许多相同的任务,相比之下,HQL能更加直观的表达复杂的查询语句,而通过QBC表达复杂的查询语句很麻烦。因此如果,在程序运行前就明确了查询语句的内容(也成为静态查询),应该优先考虑HQL查询方式。但是如果只有在程序运行时才能明确查询 语句的内容(也称为动态查询),QBC比HQL更加方便。
在实际应用中,经常有这样的查询需求:用户在客户界面的查询窗口输入查询条件,按下查询按钮后,业务层执行查询操作,返回匹配的查询结果。
通过HQL来生成动态查询语句:
public List findCustomers(String username,String password){
session=HibernateUtil.getSession();
StringBuffer hqlStr=new StringBuffer("from SysUser as user");
if(username!=null)
hqlStr.append(" where user.username like :username");
if(password!=null && username!=null)
hqlStr.append(" and user.password=:password");
if(password!=null && username==null)
hqlStr.append(" where customer.password=:password");
Query query=session.createQuery(hqlStr.toString());
if(username!=null)
query.setString("username", username);
if(password!=null)
query.setString("password", password);
List list=query.list();
System.out.println(list.size());
return list;
}
如果采用QBC检索方式,可以简化编程:
public List findCustomers2(String username,String password){
session=HibernateUtil.getSession();
Criteria cri=session.createCriteria(SysUser.class);
if(username!=null)
cri.add(Expression.like("username", username,MatchMode.ANYWHERE));
if(password !=null)
cri.add(Expression.eq("password", password));
List list=cri.list();
System.out.println(list.size());
return list;
}
也可以使用QBE检索方式:
public List findCustomers3(Customer customer){
session=HibernateUtil.getSession();
Example exampleCustomer=Example.create(customer);
exampleCustomer.ignoreCase().enableLike(MatchMode.ANYWHERE);
exampleCustomer.excludeZeroes();
Criteria cri=session.createCriteria(SysUser.class).add(exampleCustomer);
return cri.list();
}
2、集合过滤
Session的createFilter()方法用来过滤集合。
四、本地SQL查询
HIbernate对本地SQL查询提供了内置的支持,为了把SQL查询返回的关系数据映射为对象,需要在SQL查询语句中为字段指定别名,Session的createSQLQuery()方法。
五、查询性能优化
Hibernate主要从以下几个方面来优化查询性能:
1、降低访问数据库的频率,减少select语句的数目。实现手段:
①、使用迫切左外连接或迫切内连接检索策略。
②、对延迟检索或立即检索设置批量检索数目。
③、使用查询缓存。
2、避免多余加载程序不需要访问的数据,实现手段:
①、使用延迟检索策略。
②、使用集合过滤。
3、避免报表查询数据占用缓存。实现手段为利用投影查询,查询出实体的部分属性。
4、减少select语句中的字段,从而降低访问数据库的数据量。实现手段:利用Query的iterate()方法。
六、iterate()方法
Query接口的iterate()方法和list()方法都能执行SQL查询语句,但是前者在有些情况下能轻微 提高查询性能。例如,以下程序代码两次检索Customer对象。
Query query1=session.CreateQuery("from Customer c");
List result1=query1.list();
Query query2=session.CreateQuery("from Customer c where c.age<30");
List result2=query2.list();
当第二次从数据库检索Customer对象时,Hibernate执行的SQL查询语句为select id,name ,age from customers where age <30
由于和以上查询结果对应的Customer对象已经存在于Session的缓存中,因此在这种情况下,Hibernate不需要重新创建Customer对象,只需要根据查询结果中的ID字段值返回缓存中匹配的Customer对象。可见,当第二次从数据库中检索Customer对象时,在select语句中其实只需要包含customer表的ID字段就可以了。
Query接口的iterate()方法首先检索ID字段,然后根据ID字段到Hibernate的第一级缓存以及第二级缓存中查找匹配的Customer对象,如果存在,就直接把它加入到查询结果集中,否则就执行额外的select语句,根据ID字段到数据库中检索该对象。
七、查询缓存
对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把查询结果存放在第二级缓存中。以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提供查询性能。如果查询结果中包含实体,第二级缓存只会存放实体的OID,而对于投影查询,第二级缓存会存放所有的数据值。
后面我们会详细介绍缓存。