Hibernate提供异常强大的查询体系,使用Hibernat有多种查询方式可以选择:即可以使用Hibernate的HQL查询,也可以使用条件查询,甚至可以使用原生的SQL查询语句。不仅如此, Hibernate还提供了一种数据过滤功能,这些都用于筛选目标数据。
Hibernate是 Hibernate Query Language的缩写,HQL的语法很像SQL,但HQL是一种面向对象的查询语言。SQL的操作对象是数据表,列表数据库对象,而HQL的操作对象是类,实例,属性等。
HQL是完全面向对象查询语言,因此可以支持继承,多态等特性。
HQL查询依赖于Query类,每个Query实例对应一个查询对象。使用HQL查询按如下步骤进行:
(1)获取Hibernate Session对象。
(2)编写HQL语句。
(3)以HQL语句作为参数,调用Session的createQuery 方法创建查询对象。
(4)如果HQL语句包含参数,则调用Query的setXxx方法为参数赋值。
(5)调用Query对象的list()或uniqueResult()方法返回查询结果列表(持久化实体集)。
下面是一个用例:
Person和MyEvent两个类的代码及映射文件:
1 import java.util.HashSet; 2 import java.util.Set; 3 4 public class Person { 5 // 定义标识属性 6 private Integer id; 7 // 定义Person实例的name属性 8 private String name; 9 // 定义Person实例的age属性 10 private Integer age; 11 // 定义Person和MyEvent之间的关联关系 12 private Set<MyEvent> myEvents = new HashSet<MyEvent>(); 13 // 定义一个集合属性 14 private Set<String> emails = new HashSet<String>(); 15 16 // 无参数的构造器 17 public Person() { 18 } 19 20 // 初始化全部属性的构造器 21 public Person(Integer id, String name, Integer age) { 22 this.id = id; 23 this.name = name; 24 this.age = age; 25 } 26 27 // id属性的setter和getter方法 28 public void setId(Integer id) { 29 this.id = id; 30 } 31 32 public Integer getId() { 33 return this.id; 34 } 35 36 // name属性的setter和getter方法 37 public void setName(String name) { 38 this.name = name; 39 } 40 41 public String getName() { 42 return this.name; 43 } 44 45 // age属性的setter和getter方法 46 public void setAge(int age) { 47 this.age = age; 48 } 49 50 public Integer getAge() { 51 return this.age; 52 } 53 54 // myEvents属性的setter和getter方法 55 public void setMyEvents(Set<MyEvent> myEvents) { 56 this.myEvents = myEvents; 57 } 58 59 public Set<MyEvent> getMyEvents() { 60 return this.myEvents; 61 } 62 63 // emails属性的setter和getter方法 64 public void setEmails(Set<String> emails) { 65 this.emails = emails; 66 } 67 68 public Set<String> getEmails() { 69 return this.emails; 70 }
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="com.example.hql.pojo"> 6 <class name="Person" table="person"> 7 <id name="id" column="person_id"> 8 <generator class="native" /> 9 </id> 10 <property name="name" /> 11 <property name="age" /> 12 <!-- 映射和MyEvent实体的关联关系 --> 13 <set name="myEvents" table="person_event"> 14 <!-- 映射连接表中参照此表主键的外键列的列名 --> 15 <key column="person_id" /> 16 <many-to-many class="MyEvent" column="event_id" /> 17 </set> 18 <!-- 映射集合属性 --> 19 <set name="emails" table="person_email"> 20 <!-- 映射集合属性表中的外键列 --> 21 <key column="person_id" /> 22 <!-- 映射集合元素,集合元素是字符串 --> 23 <element type="string" column="email" /> 24 </set> 25 </class> 26 </hibernate-mapping>
1 import java.util.Date; 2 import java.util.HashSet; 3 import java.util.Set; 4 5 public class MyEvent { 6 // 定义标识属性 7 private Integer id; 8 // 定义MyEvent对象的名称 9 private String title; 10 // 定义MyEvent对象的发生时间 11 private Date happenDate; 12 // 定义MyEvent对象和Person对象的关联 13 private Set<Person> actors = new HashSet<Person>(); 14 15 // 无参数的构造器 16 public MyEvent() { 17 } 18 19 // 初始化全部属性的构造器 20 public MyEvent(Integer id, String title, Date happenDate) { 21 this.id = id; 22 this.title = title; 23 this.happenDate = happenDate; 24 } 25 26 // id属性的setter和getter方法 27 public void setId(Integer id) { 28 this.id = id; 29 } 30 31 public Integer getId() { 32 return this.id; 33 } 34 35 // title属性的setter和getter方法 36 public void setTitle(String title) { 37 this.title = title; 38 } 39 40 public String getTitle() { 41 return this.title; 42 } 43 44 // happenDate属性的setter和getter方法 45 public void setHappenDate(Date happenDate) { 46 this.happenDate = happenDate; 47 }
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 <hibernate-mapping package="com.example.hql.pojo"> 6 <class name="MyEvent" table="event"> 7 <id name="id" column="event_id"> 8 <generator class="native" /> 9 </id> 10 <property name="title" /> 11 <property name="happenDate" type="date" /> 12 <set name="actors" table="person_event"> 13 <key column="event_id" /> 14 <many-to-many class="Person" column="person_id" /> 15 </set> 16 </class> 17 </hibernate-mapping>
下面是查询代码
1 import java.text.SimpleDateFormat; 2 import java.util.Arrays; 3 import java.util.Date; 4 import java.util.Iterator; 5 import java.util.List; 6 7 import org.hibernate.Session; 8 import org.hibernate.Transaction; 9 import org.junit.Test; 10 11 import com.example.hql.pojo.Person; 12 import com.example.util.HibernateSessionFactory; 13 14 @SuppressWarnings("unchecked") 15 public class HqlQuery { 16 @Test 17 public void findPerson() { 18 // 开启Session 19 Session session = HibernateSessionFactory.getSession(); 20 // 开始事务 21 Transaction tx = session.beginTransaction(); 22 // 以HQL语句创建Query对象 23 // 执行setString方法为HQL语句的参数赋值 24 25 List<Person> persons = (List<Person>) session 26 .createQuery( 27 "select distinct p from Person p join p.myEvents where title = :eventTitle") 28 .setString("eventTitle", "很普通的事情").list(); 29 // 遍历查询结果 30 for (Iterator<Person> pit = persons.iterator(); pit.hasNext();) { 31 Person p = pit.next(); 32 System.out.println(p.getName()); 33 } 34 tx.commit(); 35 session.close(); 36 } 37 38 @Test 39 public void findPersonByHappenDate() throws Exception { 40 Session session = HibernateSessionFactory.getSession(); 41 Transaction tx = session.beginTransaction(); 42 // 解析出Date对象 43 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD"); 44 Date start = sdf.parse("2012-10-10"); 45 System.out.println("系统开始通过日期查找人:" + start); 46 List<Person> persons = session 47 .createQuery( 48 "select distinct p from Person p inner join p.myEvents event where event.happenDate between :firstDate and :endDate") 49 .setDate("firstDate", start).setDate("endDate", new Date()) 50 .list(); 51 // 遍历查询结果 52 for (Person p : persons) { 53 System.out.println(p); 54 } 55 tx.commit(); 56 session.close(); 57 } 58 59 @Test 60 public void findPersonProperty(){ 61 Session session = HibernateSessionFactory.getSession(); 62 Transaction tx = session.beginTransaction(); 63 List<Object[]> datas = session.createQuery("select distinct p.id, p.name, p.age from Person p join p.myEvents").list(); 64 for(Object[] data:datas){ 65 System.out.println(Arrays.toString(data)); 66 } 67 tx.commit(); 68 session.close(); 69 } 70 }
由上面HQL语句可以看出,执行HQL语句类似于用PreparedStatement执行SQL语句,因此HQL语句中可以使用占位符作为参数。HQL的占位符即可使用问号(?),这与SQL语句中的占位符完全一样;也可以使用有名字的占位符,使用有名字的占位符时,应该在占位符名字前增加冒号(:),如上HQL所示。
编写完HQL语句之后,就可使用Session的createQuery(hql)方法创建Query,Query对象使用setXxx()方法为HQL语句的参数赋值。Query的所有setXxx()方法都有两个版本,分别用于根据参数索引赋值和根据参数名字赋值。
Query对象可以连续多次围HQL参数赋值,这得益于Hibernate Query的设计。通常的setXxx()方法返回值都是void,单Hibernate Query的setXxx()方法返回值是Query本身,采用了 链式 设计的思想。因此,程序通过Session创建Query后,直接多次调用setXxx()方法为HQL语句的参数赋值。
Query最后调用list()方法返回查询到的全部结果。
Query还包含如下两个方法。
》setFirstResult(int firstResult):设置返回结果从第几条记录开始。
》setMaxResult(int maxResults): 设置本次查询返回的结果数目。
这两个方法用于HQL查询实现分页控制。
HQL语句本身是不区分大小写的。也就是说HQL语句的关键字,函数都不是区别大小写的。但HQL语句中所使用的包名,类名,实例名,属性名都区分大小写。