首先来看一下,hibernate提供的几种检索方式:
1.导航对象图检索方式 :根据已经加载的对象,导航到其他对象。例如,对于已经加载的Customer对象,调用它的getOrders().iterator()方法就可以导航到所有关联的Order对象,假如在关联级别使用了延迟加载检索策略,那么首次执行此方法时,Hibernate会从数据库中加载关联的Order对象,否则就从缓存中取得Order对象。
2、OID检索方式 :按照对象的OID来检索对象。Session的get()和load()方法提供了这种功能。如果在应用程序中事先知道了OID,就可以使用这种检索对象的方式。
3、HQL检索方式 :Hibernate提供了Query接口,它是Hibernate提供的专门的HQL查询接口,能够执行各种复杂的HQL查询语句。
4、QBC检索方式 :使用QBC(Query By Criteria)API来检索对象。这种API封装了基于字符串形式的查询语句,提供了更加面向对象的接口。
前两种在前面我们都熟练的用过多次了,现在我们来看一下HQL检索方式。HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相似。在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。它具有以下功能:
–在查询语句中设定各种查询条件
–支持投影查询,即仅检索出对象的部分属性
–支持分页查询
–支持连接查询
–支持分组查询,允许使用having和group by关键字
–提供内置聚集函数,如sum()、min()和max()
–支持子查询,即嵌入式查询
–支持动态绑定参数
下面我们通过一个实例来看一下HQL检索的步骤:
//创建一个Query对象 Query query=session.createQuery("from Customer as c where " +" c.name=:customerName " +"and c.age=:customerAge"); //动态绑定参数 query.setString("customerName","Tom"); query.setInteger("customerAge",21); //执行查询语句,返回查询结果 List result= query.list();
从上面这个实例我们可以看出:
(1)通过Session的createQuery()方法创建一个Query对象,它包含一个HQL查询语句。HQL查询语句可以包含命名参数,如“customerName”和“customerAge”都是命名参数。
(2)动态绑定参数。Query接口提供了给各种类型的命名参数赋值的方法,例如setString()方法用于为字符串类型的customerName命名参数赋值。
(3)调用Query的list()方法执行查询语句。该方法返回List类型的查询结果,在List集合中存放了符合查询条件的持久化对象。
Query中还提供了良好的方法连编程方式,查看hibernate的API我们可以发现,query类提供的set方法的返回值还是query对象,这样可以使代码更为简介:例如。
List result=session.createQuery("……") .setString("customerName","Tom") .setInteger("customerAge",21) .list();
QBC
采用HQL检索方式时,在应用程序中需要定义基于字符串形式的HQL查询语句。 QBC API 提供了检索对象的另一种方式,它主要由Criteria接口、Criterion接口和Expression类组成,它支持在运行时动态生成查询语句。
QBC检索步骤:
1)调用Session的createCriteria()方法创建一个Criteria对象。
2)设定查询条件。Expression类提供了一系列用于设定查询条件的静态方法,这些静态方法都返回Criterion实例,每个Criterion实例代表一个查询条件。Criteria的add()方法用于加入查询条件。
3)调用Criteria的list()方法执行查询语句。该方法返回List类型的查询结果,在List集合中存放了符合查询条件的持久化对象。下面还是通过一个实例来看一下QBC查询的具体步骤:
//创建一个Criteria对象 Criteria criteria=session.createCriteria(Customer.class); //设定查询条件,然后把查询条件加入到Criteria中 Criterion criterion1= Expression.like("name", "T%") ; Criterion criterion2= Expression.eq("age", new Integer(21)) ; criteria=criteria.add(criterion1); criteria=criteria.add(criterion2); //执行查询语句,返回查询结果 List result=criteria.list();
对于以上程序代码,当运行Criteria的list()方法时,Hibernate执行的SQL查询语句为:
select * from CUSTOMERS where NAME like 'T%' and AGE=21;
注:Expression;类是org.hibernate.criterion.Restrictions的子类,所以也可以换成该类。Criteria也是采用的方法连的编程风格,因为add方法返回值也是Criteria,就像下面这段代码:
List result=session.createCriteria(Customer.class).add(Expression.like("name", "T%") .add(Expression.eq("age", newInteger(21)) .list();
Query和Criteria接口都提供了用于分页显示查询结果的方法:
–setFirstResult(int firstResult):设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0。默认情况下,Query和Criteria接口从查询结果中的第一个对象,也就是索引位置为0的对象开始检索。
–setMaxResult(int maxResults):设定一次最多检索出的对象数目。默认情况下,Query和Criteria接口检索出查询结果中所有的对象。
分页查询:
采用HQL检索方式 :
Query query = session.createQuery("from Customer c order by c.name asc"); query.setFirstResult(0); query.setMaxResults(10); List result = query.list();
采用QBC检索方式
Criteria criteria = session.createCriteria( Customer.class); criteria.addOrder( //criteria里面提供添加排序方式的方法 Order.asc("name") ); criteria.setFirstResult(0); criteria.setMaxResults(10); List result = criteria.list()
上面我们大体了解了hql语句和QBC两种查询方式,具体的用法我们来看一下,首先看一下HQL.
我们平时查询的时候,HQL语句总是”from 类名”,这样查询,这是我们想要查询出对应对象的所有属性。当我们只是想查询实体类的其中的几个字段,而不是整个实体类的对象时,我们就需要把前面省略的hql语句加上了。例如HQL语句:select s.name,s.age from student s ,他代表只是查询student表中的name和age属性,其他的不要。这时调用query。List()方法时返回的不是一个个对象了,因为我们查询的只是对象的一部分属性。那查询到的list集合里是什么东东呢。其实list对象中里面每一个元素是一个object对象的数组,每一个数组包含查询对象的几个字段。这些数据只是一些游离的数据。我们想获得的字段数据可以用下面方式去遍历。
代码如下:
以上情况还可以用另一种方式来解决但这种方式方式成功执行的前提是,在student实体类里面构造了包含name和age两个属性的构造方法。
Query query = session.createQuery("select new Student(s.name, s.age) from Student s"); List list = query.list(); for(int i = 0; i < list.size(); i++) {Student student = (Student)list.get(i) System.out.println(student.getName() + ", " + student.getAge()); System.out.println(student.getCardId());//此处返回空,数据库没有查该字段 }
通过上面HQL语句我们可以看出,这时查询出来的就是一个个student对象了,而不是一个个游离的数据了,这里一定要注意HQL语句的写法。这种写法在sql语句中肯定是不支持的。
HQL语句进行内连接查询:from Team t join t.student;这条内连接语句意思为让team表和student表进行内连接查询。很多同学回想没有on语句,查询条件是什么呢?这是由于hbm文件已经注明了表之间的字段连接关系,所以他会自动去on连接。下面看一下自动生成的sql语句大家就没白了。
Hibernate自动生成的查询语句为:
Hibernate配置给我们提供了一个格式化sql语句的配置,配置sql_format的属性为true,就会向上面那样,得到格式化的sql语句。
在内连接查询结果中,刚开始我有这么一个疑问,连接查询得到的结果集是两个表中的并集集合,那得到的对象到底是哪一个呢?不是student。也是不是team。原来,hibernate早就给我们准备了这个东西。当我们调用list方法获得结果的集合时,得到的集合实际上是object数组的集合。这个数组里面一般有两个对象,像上面那条hql语句就是得到的student对象和team对象数组的集合,下面我们就看一下具体的代码实现:
Query query = session.createQuery("from Team t join t.students"); List list = query.list(); for(int i = 0; i < list.size(); i++) { Object[] obj = (Object[]) list.get(i); Team team = (Team)obj[0]; Student student = (Student)obj[1]; System.out.println(team.getTeamName()); System.out.println(student.getName()); }
内连接中还深藏着一个不为人知的秘密,当我们把延迟加载设为true,也就是让他延迟加载对应对象信息时,我们在session关闭之后去遍历list集合,这时你会发现一样的加载出来对应的student的信息,这时因为内连接查询把配置文件中的延迟加载信息给覆盖掉了。在session关闭之前就把对应的对象信息给加载出来了。
hql中实体参数设置
下面我们在来看一下hibernate用hql中实体参数设置,所谓实体参数设置就是在利用HQL语句执行操作时,对HQL语句中设置参数,以前我们接触到的都是一些基本数据类型的参数设置,hibernate中都提供了相应的set方法,下面我们来看一下下面一个hql查询:
Team team=session.get(Team.class,1); Query query = session.createQuery("from student s where s.team=:team and s.age>20");
在这个地方,我们查询的条件为学生对应的team对象与刚查询出来的对象相等。在hibernateAPI中提供了两种方式设置这个地方的参数,下面我们一一来看一下:
1.第一种:
query.setParameter("team",team,Hibernate.entity(Team.class));这种方式需要三个参数,第一个参数是指定设定的参数,这里设置的是上面hql语句中的team参数,第二个参数是设置参数的值,第三个参数是一个Type类型的数据,hibernate中提供了一个Hibernate类,他里面包含了大量的静态工具方法,其中就有获得Type对象的方法entity。
2.第二种:
query.setEntity("team",team),这个方法比较简单,并且比较实用,我们在大多数的时候都使用这一个,他和设置基本数据类型的set方法比较相识。直接设置参数名和参数值就OK了。
值得注意的是,这里的hql语句这样比较两个对象是否相等,其实在hibernate底层会转换成对应的外键关联。
过滤:
hibernateAPI提供了一个起到过滤器作用的方法,这个方法就是createFiter(object collection,string s)方法,他有两个参数,第一个参数是指所要过滤的对象,也就是集合对象,第二个参数指的是过滤语句,其实就是hql语句的一部分:例如下面这段代码:
Query query = session.createFilter(team.getStudents(), "where age > 20"); Listlist = query.list();
QBC:作为真正的面向对象对数据库进行操作的一种方式,其内部提供了大量的API对数据库操作和条件,下面我们根据具体示例来看一下其API的的用法:
//增加年龄限制12-30岁 Criteria criteria = session.createCriteria(Student.class).add( Restrictions.between("age", new Integer(12), new Integer(30))); //增加name条件限制,名字以t开头的 Criteria criteria = session.createCriteria(Student.class).add( Restrictions.like("name", "t%")); //增加范围限制,名字必须是"jerry", "spark", "tom"中的一个 String[] names = { "jerry", "spark", "tom" }; Criteria criteria = session.createCriteria(Student.class).add( Restrictions.in("name", names)); //对查询到的数据进行排序,以age升序,以cardid降序 Criteria criteria = session.createCriteria(Student.class).addOrder( Order.asc("age")).addOrder(Order.desc("cardId")); //执行数据查询 Listlist = criteria.list();