注意:HQL語言,是基于對象進行查詢的,不是基于數(shù)據(jù)庫的表。
一、Hibernate 提供了以下幾種檢索對象的方式:
導航對象圖檢索方式: 根據(jù)已經(jīng)加載的對象導航到其他對象 OID 檢索方式: 按照對象的 OID 來檢索對象
HQL 檢索方式:使用面向?qū)ο蟮?HQL 查詢語言
QBC 檢索方式: 使用 QBC(Query By Criteria) API 來檢索對象. 這種
API 封裝了基于字符串形式的查詢語句, 提供了更加面向?qū)ο蟮牟樵兘涌?
本地 SQL 檢索方式: 使用本地數(shù)據(jù)庫的 SQL 查詢語句
二、HIbernate的HQL查詢
- HQL(Hibernate Query Language) 是面向?qū)ο蟮牟樵冋Z言, 它和 SQL 查詢語言有些相似. 在 Hibernate 提供的各種檢索方式中, HQL 是使用最廣的一種檢索方式. 它有如下功能:
在查詢語句中設定各種查詢條件
- 支持投影查詢, 即僅檢索出對象的部分屬性
- 支持分頁查詢
- 支持連接查詢
- 支持分組查詢, 允許使用 HAVING 和 GROUP BY 關鍵字
- 提供內(nèi)置聚集函數(shù), 如 sum(), min() 和 max()
- 支持子查詢
- 支持動態(tài)綁定參數(shù)
- 能夠調(diào)用 用戶定義的 SQL 函數(shù)或標準的 SQL 函數(shù)
- HQL 檢索方式包括以下步驟:
a、通過 Session 的 createQuery() 方法創(chuàng)建一個 Query 對象, 它包括一個 HQL 查詢語句. HQL 查詢語句中可以包含命名參數(shù)
b、動態(tài)綁定參數(shù)
c、調(diào)用 Query 相關方法執(zhí)行查詢語句.
三、各種查詢示例代碼:
1、首先搭建測試環(huán)境:
兩個測試實體類:
Employee類:
public class Employee {
private Integer id;
private String name;
private float salary;
private String email;
private Department dept;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
public Employee(float salary, String email, Department dept) {
super();
this.salary = salary;
this.email = email;
this.dept = dept;
}
public Employee() {
}
@Override
public String toString() {
return "Employee [id=" + id + "]";
}
}
Department類:
public class Department {
private Integer id;
private String name;
private Set<Employee> emps=new HashSet<Employee>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Employee> getEmps() {
return emps;
}
public void setEmps(Set<Employee> emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
2個實體類對應的hbm配置文件:
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-6-10 23:07:48 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.elgin.hibernate.entity">
<class name="Employee" table="EMPLOYEE">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="salary" type="float">
<column name="SALARY" />
</property>
<property name="email" type="java.lang.String">
<column name="EMAIL" />
</property>
<many-to-one name="dept" class="Department" >
<column name="DEPT_ID" />
</many-to-one>
</class>
<query name="salaryEmp">
<![CDATA[
from Employee e where e.salary> :minSal and e.salary < :maxSal
]]>
</query>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-6-10 23:07:48 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.elgin.hibernate.entity">
<class name="Department" table="DEPARTMENT">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<set name="emps" table="EMPLOYEE" inverse="true" lazy="true">
<key>
<column name="DEPT_ID" />
</key>
<one-to-many class="Employee" />
</set>
</class>
</hibernate-mapping>
Hibernate配置文件:hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- hibernate數(shù)據(jù)庫連接信息配置 -->
<property name="connection.username">root</property>
<property name="connection.password">root123</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- hibernate基本配置 -->
<!-- hibernate的數(shù)據(jù)庫方言 -->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!--設置hibernate事務的隔離級別 -->
<property name="connection.isolation">2</property>
<!-- 需要關聯(lián)的hibernate映射文件 hbm.xml文件 -->
<mapping resource="com/elgin/hibernate/entity/Department.hbm.xml"/>
<mapping resource="com/elgin/hibernate/entity/Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Hibernate查詢單元測試類:
public class HibernateTest2 {
//如此聲明只為方便測試,生產(chǎn)環(huán)境不能這么用
private SessionFactory sessionFactory;
private Session session;
private Transaction transcation;
@Before
public void init(){
Configuration cfg=new Configuration().configure();
ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
sessionFactory=cfg.buildSessionFactory(serviceRegistry);
session=sessionFactory.openSession();
transcation=session.beginTransaction();
}
public void insert(int i){
Employee employee=new Employee();
employee.setName("name"+i);
employee.setEmail("name"+i+"@qq.com");
employee.setSalary(1000*i);
session.save(employee);
}
@Test
//初始化2個表中的數(shù)據(jù),方便查詢
public void test(){
for (int i = 14; i < 21; i++) {
insert(i);
}
}
@After
public void destory(){
transcation.commit();
session.close();
sessionFactory.close();
}
}
上述類為基礎測試類,如下的測試代碼均需加入到上述類中運行。至此,測試環(huán)境搭建完成,下面逐一進行測試:
2 綁定參數(shù):
- Hibernate 的參數(shù)綁定機制依賴于 JDBC API 中的 PreparedStatement 的預定義 SQL 語句功能.
- HQL 的參數(shù)綁定由兩種形式:
按參數(shù)名字綁定: 在 HQL 查詢語句中定義命名參數(shù), 命名參數(shù)以 “:” 開頭.
按參數(shù)位置綁定: 在 HQL 查詢語句中用 “?”來定義參數(shù)位置 - 相關方法:
setEntity(): 把參數(shù)與一個持久化類綁定。
setParameter(): 綁定任意類型的參數(shù). 該方法的第三個參數(shù)顯式指定 Hibernate 映射類型。
測試代碼:
@Test
public void testHQLNamedParameters(){
//1.創(chuàng)建 Query 對象
// 基于命名參數(shù)
String HQL="FROM Employee e WHERE e.salary> :salary AND e.email LIKE :email";
Query query=session.createQuery(HQL);
//2. 動態(tài)綁定參數(shù)
query.setFloat("salary", 6000).setString("email", "%a%");
//3. 執(zhí)行查詢
List<Employee> emps = query.list();
System.out.println(emps.size());
}
@Test
public void testHQL(){
//1.創(chuàng)建 Query 對象
// 基于位置的參數(shù)
String HQL="FROM Employee e WHERE e.salary> ? AND e.email LIKE ?";
Query query=session.createQuery(HQL);
//2. 動態(tài)綁定參數(shù)
// Query對象調(diào)用setXxx方法,支持方法鏈的編程
query.setFloat(0, 6000).setString(1, "%a%");
//3. 執(zhí)行查詢
List<Employee> emps = query.list();
System.out.println(emps.size());
}
3 分頁查詢:
- setFirstResult(int firstResult): 設定從哪一個對象開始檢索, 參數(shù) firstResult表示這個對象在查詢結果中的索引位置, 索引位置的起始值為 0. 默認情況下, Query 從查詢結果中的第一個對象開始檢索
- setMaxResults(int maxResults): 設定一次最多檢索出的對象的數(shù)目. 在默認情況下, Query 和 Criteria 接口檢索出查詢結果中所有的對象
/**
* HQL分頁查詢
*
*/
@Test
public void testPageQuery(){
String HQL="from Employee";
int pageNo=2;
int pageSize=5;
List<Employee> emps= session.createQuery(HQL)
.setFirstResult((pageNo-1)*pageSize)
.setMaxResults(pageSize)
.list();
System.out.println(emps);
}
4.在映射文件中定義命名查詢語句
Hibernate 允許在映射文件中定義字符串形式的查詢語句.
元素用于定義一個 HQL 查詢語句, 它和 元素并列.
在程序中通過 Session 的 getNamedQuery() 方法獲取查詢語句對應的 Query 對象.
本例在Employee.hbm.xml映射文件中定義了如下:
<query name="salaryEmp">
<![CDATA[
from Employee e where e.salary> :minSal and e.salary < :maxSal
]]>
</query>
之后就可以使用如下代碼來使用次查詢語句:
/**
* HQL命名查詢(HQL語句配置在hbm文件中的query標簽中,使用CDATA包裹)
*
*/
@Test
public void testNamedQuery(){
Query query=session.getNamedQuery("salaryEmp");
List<Employee> emps=query.setFloat("minSal", 2000)
.setFloat("maxSal", 5000)
.list();
System.out.println(emps);
}
5.HQL 左外連接:
- LEFT JOIN 關鍵字表示左外連接查詢.
- list() 方法返回的集合中存放的是對象數(shù)組類型
- 根據(jù)配置文件來決定 Employee 集合的檢索策略(是否延遲加載)
- 如果希望 list() 方法返回的集合中僅包含 Department 對象, 可以在HQL 查詢語句中使用 SELECT 關鍵字
/**
* HQL 左外連接
*/
@Test
public void testLeftJoin(){
String hql="select distinct d from Department d left join d.emps";
Query query=session.createQuery(hql);
List<Department> depts=query.list();
for (Department dept : depts) {
System.out.println(dept.getName()+"-"+dept.getEmps().size());
}
}
綜上迫切左外連接和左外連接:
- 如果在 HQL 中沒有顯式指定檢索策略, 將使用映射文件配置的檢索策略.
- HQL 會忽略映射文件中設置的迫切左外連接檢索策略, 如果希望 HQL 采用迫切左外連接策略, 就必須在 HQL 查詢語句中顯式的指定它
- 若在 HQL 代碼中顯式指定了檢索策略, 就會覆蓋映射文件中配置的檢索策略