Hibernate的查询语言之HQL(一)——快速入门

时间:2023-03-09 18:00:06
Hibernate的查询语言之HQL(一)——快速入门

  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两个类的代码及映射文件:

 import java.util.HashSet;
import java.util.Set; public class Person {
// 定义标识属性
private Integer id;
// 定义Person实例的name属性
private String name;
// 定义Person实例的age属性
private Integer age;
// 定义Person和MyEvent之间的关联关系
private Set<MyEvent> myEvents = new HashSet<MyEvent>();
// 定义一个集合属性
private Set<String> emails = new HashSet<String>(); // 无参数的构造器
public Person() {
} // 初始化全部属性的构造器
public Person(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
} // id属性的setter和getter方法
public void setId(Integer id) {
this.id = id;
} public Integer getId() {
return this.id;
} // name属性的setter和getter方法
public void setName(String name) {
this.name = name;
} public String getName() {
return this.name;
} // age属性的setter和getter方法
public void setAge(int age) {
this.age = age;
} public Integer getAge() {
return this.age;
} // myEvents属性的setter和getter方法
public void setMyEvents(Set<MyEvent> myEvents) {
this.myEvents = myEvents;
} public Set<MyEvent> getMyEvents() {
return this.myEvents;
} // emails属性的setter和getter方法
public void setEmails(Set<String> emails) {
this.emails = emails;
} public Set<String> getEmails() {
return this.emails;
}
 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example.hql.pojo">
<class name="Person" table="person">
<id name="id" column="person_id">
<generator class="native" />
</id>
<property name="name" />
<property name="age" />
<!-- 映射和MyEvent实体的关联关系 -->
<set name="myEvents" table="person_event">
<!-- 映射连接表中参照此表主键的外键列的列名 -->
<key column="person_id" />
<many-to-many class="MyEvent" column="event_id" />
</set>
<!-- 映射集合属性 -->
<set name="emails" table="person_email">
<!-- 映射集合属性表中的外键列 -->
<key column="person_id" />
<!-- 映射集合元素,集合元素是字符串 -->
<element type="string" column="email" />
</set>
</class>
</hibernate-mapping>
 import java.util.Date;
import java.util.HashSet;
import java.util.Set; public class MyEvent {
// 定义标识属性
private Integer id;
// 定义MyEvent对象的名称
private String title;
// 定义MyEvent对象的发生时间
private Date happenDate;
// 定义MyEvent对象和Person对象的关联
private Set<Person> actors = new HashSet<Person>(); // 无参数的构造器
public MyEvent() {
} // 初始化全部属性的构造器
public MyEvent(Integer id, String title, Date happenDate) {
this.id = id;
this.title = title;
this.happenDate = happenDate;
} // id属性的setter和getter方法
public void setId(Integer id) {
this.id = id;
} public Integer getId() {
return this.id;
} // title属性的setter和getter方法
public void setTitle(String title) {
this.title = title;
} public String getTitle() {
return this.title;
} // happenDate属性的setter和getter方法
public void setHappenDate(Date happenDate) {
this.happenDate = happenDate;
}
 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.example.hql.pojo">
<class name="MyEvent" table="event">
<id name="id" column="event_id">
<generator class="native" />
</id>
<property name="title" />
<property name="happenDate" type="date" />
<set name="actors" table="person_event">
<key column="event_id" />
<many-to-many class="Person" column="person_id" />
</set>
</class>
</hibernate-mapping>

下面是查询代码

 import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List; import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test; import com.example.hql.pojo.Person;
import com.example.util.HibernateSessionFactory; @SuppressWarnings("unchecked")
public class HqlQuery {
@Test
public void findPerson() {
// 开启Session
Session session = HibernateSessionFactory.getSession();
// 开始事务
Transaction tx = session.beginTransaction();
// 以HQL语句创建Query对象
// 执行setString方法为HQL语句的参数赋值 List<Person> persons = (List<Person>) session
.createQuery(
"select distinct p from Person p join p.myEvents where title = :eventTitle")
.setString("eventTitle", "很普通的事情").list();
// 遍历查询结果
for (Iterator<Person> pit = persons.iterator(); pit.hasNext();) {
Person p = pit.next();
System.out.println(p.getName());
}
tx.commit();
session.close();
} @Test
public void findPersonByHappenDate() throws Exception {
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
// 解析出Date对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-DD");
Date start = sdf.parse("2012-10-10");
System.out.println("系统开始通过日期查找人:" + start);
List<Person> persons = session
.createQuery(
"select distinct p from Person p inner join p.myEvents event where event.happenDate between :firstDate and :endDate")
.setDate("firstDate", start).setDate("endDate", new Date())
.list();
// 遍历查询结果
for (Person p : persons) {
System.out.println(p);
}
tx.commit();
session.close();
} @Test
public void findPersonProperty(){
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
List<Object[]> datas = session.createQuery("select distinct p.id, p.name, p.age from Person p join p.myEvents").list();
for(Object[] data:datas){
System.out.println(Arrays.toString(data));
}
tx.commit();
session.close();
}
}

  由上面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语句中所使用的包名,类名,实例名,属性名都区分大小写。