程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Hibernate —— HQL、QBC檢索方式,hqlqbc

Hibernate —— HQL、QBC檢索方式,hqlqbc

編輯:JAVA綜合教程

Hibernate —— HQL、QBC檢索方式,hqlqbc


一、HQL 檢索方式

以雙向的一對多來測試 HQL 檢索方式。以 Department 和 Employee 為例。

建表語句:

CREATE TABLE department
(
    dept_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    dept_name VARCHAR(50)
);
CREATE INDEX FK_8hf3vewo7w3v9doungcc51wwy ON department (dept_id);
CREATE TABLE employee
(
    emp_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    emp_name VARCHAR(50),
    salary FLOAT,
    dept_id_fk INT(11),
    CONSTRAINT FK_miun1wlqp4ujpsgfshyfi7g9j FOREIGN KEY (dept_id_fk) REFERENCES department (dept_id)
);
CREATE INDEX FK_miun1wlqp4ujpsgfshyfi7g9j ON employee (dept_id_fk);

對應的實體和 hbm 文件

public class Department {
    private Integer deptId;
    private String deptName;
    private Set<Employee> emps = new HashSet<>();
}    
public class Employee {
    private Integer empId;
    private String empName;
    private Float salary;
    private Department dept;
}
<hibernate-mapping> <class name="com.solverpeng.hql.Department" table="department" schema="hibernate"> <id name="deptId" column="dept_id"> <generator class="native"/> </id> <property name="deptName" column="dept_name"/> <set name="emps" inverse="true"> <key> <column name="dept_id_fk"/> </key> <one-to-many not-found="ignore" class="com.solverpeng.hql.Employee"/> </set> </class> </hibernate-mapping> Department.hbm.xml <hibernate-mapping> <class name="com.solverpeng.hql.Employee" table="employee" schema="hibernate"> <id name="empId" column="emp_id"> <generator class="native"/> </id> <property name="empName" column="emp_name"/> <property name="salary" column="salary"/> <many-to-one name="dept" class="com.solverpeng.hql.Department"> <column name="dept_id_fk"/> </many-to-one> </class> <query name="findAllEmployees"> <![CDATA[ from Employee ]]> </query> </hibernate-mapping> Employee.hbm.xml

1.在查詢語句中設定各種查詢條件

@Test
public void testHql(){
    Department dept = new Department();
    dept.setDeptId(7);

    List<Employee> list = session.createQuery("FROM Employee e where e.empName like ? and e.empId > ? and dept = ? order by e.empId " +
            "desc ")
            .setString(0, "%b%").setInteger(1, 3).setEntity(2, dept).list();

    for(Employee employee : list) {
        System.out.println(employee);
    }

}

說明:

(1)通過 Session 的 createQuery(hql) 方法創建一個 Query 對象,hql 支持動態綁定參數。調用 Query 的相關方法執行查詢。

(2)Query 接口支持鏈式操作,它的 setXxx() 方法返回自身實例。

(3)方法 setEntity(obj),obj 只需要綁定一個 id 就可以。

(4)支持 order by 排序。

(5)參數的位置從 0 開始。

@Test
public void testHqlNamed() {
    List<Employee> list = session.createQuery("from Employee e where e.empName like :name and e.empId > :id and e.dept = ?")
            .setString("name", "%a%").setInteger("id", 1).list();
    for(Employee employee : list) {
        System.out.println(employee);
    }
}

說明:

(1)支持按照參數名字查詢,定義的參數名以 ":" 開頭。

2.查詢對象的部分屬性(查詢結果僅包含實體的部分屬性)

@Test
public void testPropertyQuery() {
    Department dept = new Department();
    dept.setDeptId(7);
    List<Object[]> list = session.createQuery("select empName, empId from Employee where dept = ?").setEntity(0, dept).list();
    for(Object[] objects : list) {
        System.out.println(Arrays.asList(objects));
    }
}

說明:

(1)這種情況下查詢出來的是一個 Object[] 數組類型。

@Test
public void testPropertyQuery2() {
    Department dept = new Department();
    dept.setDeptId(7);
    List<Employee> list = session.createQuery("select new Employee (empId, empName) from Employee where dept = ?").setEntity(0, dept)
            .list();
    for(Employee employee : list) {
        System.out.println(employee);
    }
}

(1)查詢出來的是 Employee 類型

(2)需要在 Employee 實體類中定義相應的構造器,注意順序。同時添加一個無參的構造器。

(3)可以通過 Distinct 關鍵字來去重。

3.分頁查詢

@Test
public void testHqlPage() {
    int pageNo = 2;
    int pageSize = 3;

    List<Employee> list = session.createQuery("from Employee").setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
    for(Employee employee : list) {
        System.out.println(employee);
    }

}

(1)setFirstResult(int firstResult):設定從哪一個對象開始檢索。

(2)setMaxResults(int maxResult) : 設定每次檢索多少條記錄。

4.命名查詢(很少用到)

@Test
public void testNamedQuery() {
    int pageNo = 3;
    int pageSize = 5;
    List<Employee> employees = session.getNamedQuery("findAllEmployees").setFirstResult((pageNo - 1) * pageSize).setMaxResults(
            pageSize).list();
    for(Employee employee : employees) {
        System.out.println(employee);
    }
}

說明:

(1)其中 findAllEmployees 定義在了 Employee.hbm.xml 文件中,用 <query>元素來定義,和 class 節點並列。

(2)通過 Session 的 getNamedQuery() 方法獲取對應的 Query 對象。

5.聚集函數和分組查詢

@Test
public void testFunction() {
    List<Object[]> salary =
            session.createQuery("select dept.deptName, min(salary), max(salary) from Employee group by dept HAVING min(salary) > :salary")
                    .setFloat("salary", 4000).list();
    for(Object[] objects : salary) {
        System.out.println(Arrays.asList(objects));
    }
}

說明:

(1)通過 GROUP BY 進行分組,通過 HAVING 對分組數據設定約束條件。

(2)可以調用的聚集函數:count() 、min()、max()、sum()、avg()

6.迫切左外鏈接和左外鏈接

(1)迫切左外鏈接

@Test
public void testHqlFetch() {
    List list = session.createQuery("from Department d left join fetch d.emps").list();
}

打印 SQL:

Hibernate: 
    select
        department0_.dept_id as dept1_0_0_,
        emps1_.emp_id as emp1_1_1_,
        department0_.dept_name as dept2_0_0_,
        emps1_.emp_name as emp2_1_1_,
        emps1_.salary as salary3_1_1_,
        emps1_.dept_id_fk as dept4_1_1_,
        emps1_.dept_id_fk as dept4_0_0__,
        emps1_.emp_id as emp1_1_0__
    from
        hibernate.department department0_
    left outer join
        hibernate.employee emps1_
            on department0_.dept_id=emps1_.dept_id_fk

說明:

  • 同時查詢了 Employee 對象
  • list() 方法返回的集合存放的實體對象的引用,每個 Department 關聯的 Employee 集合都被初始化。
  • 可以通過 distinct 關鍵字去重,也可以通過一個 HashSet() 去重(new ArrayList<>(new LinkedHashSet(depts)))。
  • 此種情況下,會忽略配置文件中檢索策略。

(2)左外鏈接

@Test
public void testHqlLeftJoin2() {
    List<Object[]> list = session.createQuery("from Department d left join d.emps").list();
    for(Object[] objects : list) {
        System.out.println(Arrays.asList(objects));
    }
}
Hibernate: 
    select
        department0_.dept_id as dept1_0_0_,
        emps1_.emp_id as emp1_1_1_,
        department0_.dept_name as dept2_0_0_,
        emps1_.emp_name as emp2_1_1_,
        emps1_.salary as salary3_1_1_,
        emps1_.dept_id_fk as dept4_1_1_ 
    from
        hibernate.department department0_ 
    left outer join
        hibernate.employee emps1_ 
            on department0_.dept_id=emps1_.dept_id_fk

說明:

  • list() 方法返回的集合中存放的是對象數組類型。
  • 根據配置文件來決定 Employee 集合的初始化時機。

7.迫切內連接和內連接

(1)迫切內連接(inner join fetch),與迫切左外鏈接類似,查詢的時候同時將關聯的另一端的對象進行了初始化。

(2)內連接(inner join),與左外鏈接類似,查詢的時候是根據配置文件中的檢索策略來決定另一端初始化的時機。

8.小結

(1)如果在 HQL 中沒有顯式的指定檢索策略,則使用配置文件中的檢索策略。

(2)HQL 會忽略配置文件中設置的迫切左外鏈接檢索策略,若想 HQL 采用迫切左外鏈接策略,就必須在 HQL 語句中顯式的指定它。

二、QBC 檢索方式

1.設定各種查詢條件

(1)like、gt、排序

@Test
public void testQBC() {
    Criteria criteria = session.createCriteria(Employee.class);

    criteria.add(Restrictions.like("empName", "a", MatchMode.ANYWHERE));
    criteria.add(Restrictions.gt("salary", 1000F));
    // 排序
    criteria.addOrder(Order.desc("salary"));

    List list = criteria.list();
    System.out.println(list);
}
Hibernate: 
    select
        this_.emp_id as emp1_1_0_,
        this_.emp_name as emp2_1_0_,
        this_.salary as salary3_1_0_,
        this_.dept_id_fk as dept4_1_0_ 
    from
        hibernate.employee this_ 
    where
        this_.emp_name like ? 
        and this_.salary>? 
    order by
        this_.salary desc

(2)and、or

public void testQbc2() {
    Criteria criteria = session.createCriteria(Employee.class);

    Conjunction conjunction = Restrictions.conjunction();
    conjunction.add(Restrictions.like("empName", "a", MatchMode.ANYWHERE));
    Department department = new Department();
    department.setDeptId(6);
    conjunction.add(Restrictions.eq("dept", department));


    Disjunction disjunction = Restrictions.disjunction();
    disjunction.add(Restrictions.gt("salary", 1000F));
    disjunction.add(Restrictions.lt("salary", 20000F));

    criteria.add(conjunction).add(disjunction);

    criteria.list();

}
Hibernate: 
    select
        this_.emp_id as emp1_1_0_,
        this_.emp_name as emp2_1_0_,
        this_.salary as salary3_1_0_,
        this_.dept_id_fk as dept4_1_0_ 
    from
        hibernate.employee this_ 
    where
        (
            this_.emp_name like ? 
            and this_.dept_id_fk=?
        ) 
        and (
            this_.salary>? 
            or this_.salary<?
        )

2.分頁查詢

@Test
public void testQbc4() {
    Criteria criteria = session.createCriteria(Employee.class);
    // 分頁
    int pageNo = 2;
    int pageSize = 4;
    List<Employee> list = criteria.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
}
Hibernate: 
    select
        this_.emp_id as emp1_1_0_,
        this_.emp_name as emp2_1_0_,
        this_.salary as salary3_1_0_,
        this_.dept_id_fk as dept4_1_0_ 
    from
        hibernate.employee this_ limit ?,
        ?

3.聚集函數查詢

@Test
public void testQbc3() {
    Criteria criteria = session.createCriteria(Employee.class);
    criteria.setProjection(Projections.max("salary"));

    String maxSalary = criteria.uniqueResult().toString();
    System.out.println(maxSalary);
}
Hibernate: 
    select
        max(this_.salary) as y0_ 
    from
        hibernate.employee this

4.小結

(1)創建 QBC 查詢:session.createCriteria()

(2)like 關鍵字:Restrictions.like(),MatchMode.ANYWHERE

(3)排序:criteria.addOrder(),Order.desc、Order.asc

(4)AND:Conjunction conjunction = Restrictions.conjunction()

(5)Or : Disjunction disjunction = Restrictions.disjunction()

(6)聚集函數:criteria.setProjection(Projections.max("salary"))

(7)查詢單個對象:criteria.uniqueResult()

(8)查詢對象列表:criteria.list()

三、本地 SQL

@Test
public void testNativeSql() {
    Employee employee = new Employee();
    employee.setEmpId(5);
    String empName = (String) session.createSQLQuery("SELECT emp_name FROM employee where emp_id = ?")
            .setEntity(0, employee).uniqueResult();
    System.out.println(empName);
}
Hibernate: 
    SELECT
        emp_name 
    FROM
        employee 
    where
        emp_id = ?
bb2

通過 session.createSQLQuery() 方法來創建本地 SQL 查詢對象。

四、HQL 的更新操作

@Test
public void testHqlUpdate() {
    session.createQuery("delete from Employee where empId = ?").setInteger(0, 13).executeUpdate();
}
Hibernate: 
    delete 
    from
        hibernate.employee 
    where
        emp_id=?

五、總結

介紹了 HQL、QBC、本地SQL查詢。查詢對象都是通過 Session 來創建的。依次為:session.createQuery()、session.createCriteria()、session.createSQLQuery()。

其中 QBC 提供了比 HQL 更為徹底的,更加面向 Java 編程風格的一種方式。在學習 HQL 的時候,需要重點關注迫切左外鏈接。本地化查詢作為對 HQL 的一種補充。

學習的時候,注意對比學習。

更多內容請參看:documentation/manual/en-US/html_single/index.html

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved