hibernate 检索方式[通俗易懂]

hibernate 检索方式

大家好,又见面了,我是全栈君。

概述

  • Hibernate 提供了下面几种检索对象的方式
    • 导航对象图检索方式: 依据已经载入的对象导航到其它对象
    • OID 检索方式: 依照对象的 OID 来检索对象
    • HQL 检索方式: 使用面向对象的 HQL 查询语言
    • QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这样的 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口. 
    • 本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句

HQL 检索方式

HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有例如以下功能:

  • 在查询语句中设定各种查询条件
  • 支持投影查询, 即仅检索出对象的部分属性
  • 支持分页查询
  • 支持连接查询
  • 支持分组查询, 同意使用 HAVING 和 GROUP BY keyword
  • 提供内置聚集函数, 如 sum(), min() 和 max()
  • 支持子查询
  • 支持动态绑定參数

HQL 检索方式包含下面步骤:

  • 通过 Session 的 createQuery() 方法创建一个 Query 对象, 它包括一个 HQL 查询语句. HQL 查询语句中能够包括命名參数
  • 动态绑定參数
  • 调用 Query 相关方法运行查询语句


Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例, 而不是 void 类型

HQL vs SQL:

  • HQL 查询语句是面向对象的, Hibernate 负责解析 HQL 查询语句, 然后依据对象-关系映射文件里的映射信息, 把 HQL 查询语句翻译成对应的 SQL 语句. HQL 查询语句中的主体是域模型中的类及类的属性
  • SQL 查询语句是与关系数据库绑定在一起的. SQL 查询语句中的主体是数据库表及表的字段. 

绑定參数:

  • Hibernate 的參数绑定机制依赖于 JDBC API 中的 PreparedStatement 的提前定义 SQL 语句功能.
  • HQL 的參数绑定由两种形式:
    • 按參数名字绑定: 在 HQL 查询语句中定义命名參数, 命名參数以 “:” 开头.
    • 按參数位置绑定: 在 HQL 查询语句中用 “?

      ” 来定义參数位置

  • 相关方法:
    • setEntity(): 把參数与一个持久化类绑定
    • setParameter(): 绑定随意类型的參数. 该方法的第三个參数显式指定 Hibernate 映射类型

HQL 採用 ORDER BY keyword对查询结果排序

分页查询:

  • setFirstResult(int firstResult): 设定从哪一个对象開始检索, 參数 firstResult 表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象開始检索
  • setMaxResults(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中全部的对象

在映射文件里定义命名查询语句

  • Hibernate 同意在映射文件里定义字符串形式的查询语句.
  • <query> 元素用于定义一个 HQL 查询语句, 它和 <class> 元素并列. 
  • hibernate 检索方式[通俗易懂]
  • 在程序中通过 Session 的 getNamedQuery() 方法获取查询语句相应的 Query 对象. 

投影查询

  • 投影查询: 查询结果仅包括实体的部分属性.通过 SELECT keyword实现.
  • Query

    list()
    方法返回的集合中包括的是数组类型的元素
    ,
    每一个对象数组代表查询结果的一条记录
  • 能够在持久化类中定义一个对象的构造器来包装投影查询返回的记录,使程序代码能全然运用面向对象的语义来訪问查询结果集. 

  • 能够通过 DISTINCT keyword来保证查询结果不会返回反复元素

报表查询

  • 报表查询用于对数据分组和统计, 与 SQL 一样, HQL 利用 GROUP BYkeyword对数据分组, 用 HAVING keyword对分组数据设定约束条件.
  • 在 HQL 查询语句中能够调用下面聚集函数
    count()
    min()
    max()
    sum()
    avg()

HQL (迫切)左外连接

  • 迫切左外连接:
    • LEFT JOIN FETCH keyword表示迫切左外连接检索策略
    • list() 方法返回的集合中存放实体对象的引用, 每一个 Department 对象关联的 Employee 集合都被初始化, 存放全部关联的 Employee 的实体对象.
    • 查询结果中可能会包括反复元素, 能够通过一个 HashSet 来过滤反复元素

  • 左外连接:
    • LEFT JOIN keyword表示左外连接查询. 
    • list()
      方法返回的集合中存放的是对象数组类型

    • 依据配置文件来决定 Employee集合的检索策略

    • 假设希望 list() 方法返回的集合中仅包括 Department 对象, 能够在HQL 查询语句中使用 SELECT keyword


HQL (迫切)内连接

  • 迫切内连接:
    • INNER JOIN FETCH keyword表示迫切内连接, 也能够省略 INNER keyword
    • list() 方法返回的集合中存放 Department 对象的引用, 每一个 Department 对象的 Employee 集合都被初始化, 存放全部关联的 Employee 对象
  • 内连接:
    • INNER JOIN keyword表示内连接, 也能够省略 INNER keyword
    • list() 方法的集合中存放的每一个元素相应查询结果的一条记录, 每一个元素都是对象数组类型
    • 假设希望 list() 方法的返回的集合仅包括 Department 对象, 能够在 HQL 查询语句中使用 SELECT keyword


关联级别执行时的检索策略

  • 假设在 HQL 中没有显式指定检索策略, 将使用映射文件配置的检索策略.
  • HQL 会忽略映射文件里设置的迫切左外连接检索策略, 假设希望 HQL 採用迫切左外连接策略, 就必须在 HQL 查询语句中显式的指定它
  • 若在 HQL 代码中显式指定了检索策略, 就会覆盖映射文件里配置的检索策略


QBC 检索和本地 SQL 检索

  • QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这样的 API 封装了 SQL 语句的动态拼装。对查询提供了更加面向对象的功能接口
  • 本地SQL查询来完好HQL不能涵盖全部的查询特性

实例具体解释:

Department.java

package com.atguigu.hibernate.entities;

import java.util.HashSet;
import java.util.Set;

public class Department {

	private Integer id;
	private String name;
	
	private Set<Employee> emps = new HashSet<>();

	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 + "]";
	}
	
}

Department.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>

    <class name="com.atguigu.hibernate.entities.Department" table="GG_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="GG_EMPLOYEE" inverse="true" lazy="true">
            <key>
                <column name="DEPT_ID" />
            </key>
            <one-to-many class="com.atguigu.hibernate.entities.Employee" />
        </set>
        
    </class>
</hibernate-mapping>

Employee.java

package com.atguigu.hibernate.entities;

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;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + "]";
	}

	public Employee(String email, float salary, Department dept) {
		super();
		this.salary = salary;
		this.email = email;
		this.dept = dept;
	}
	
	public Employee() {
		// TODO Auto-generated constructor stub
	}
	
}

Employee.hbm.xml

<?

xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping> <class name="com.atguigu.hibernate.entities.Employee" table="GG_EMPLOYEE"> <!-- <cache usage="read-write"/> --> <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="com.atguigu.hibernate.entities.Department"> <column name="DEPT_ID" /> </many-to-one> </class> <query name="salaryEmps"><![CDATA[FROM Employee e WHERE e.salary > :minSal AND e.salary < :maxSal]]></query> </hibernate-mapping>


package com.atguigu.hibernate.test;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.jdbc.Work;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.atguigu.hibernate.dao.DepartmentDao;
import com.atguigu.hibernate.entities.Department;
import com.atguigu.hibernate.entities.Employee;
import com.atguigu.hibernate.hibernate.HibernateUtils;
public class HibernateTest {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init(){
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = 
new ServiceRegistryBuilder().applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void destroy(){
transaction.commit();
session.close();
sessionFactory.close();
}
@Test
public void testBatch(){
session.doWork(new Work() {			
@Override
public void execute(Connection connection) throws SQLException {
//通过 JDBC 原生的 API 进行操作, 效率最高, 速度最快!
}
});
}
@Test
public void testHQLUpdate(){
String hql = "DELETE FROM Department d WHERE d.id = :id";
session.createQuery(hql).setInteger("id", 280)
.executeUpdate();
}
@Test
public void testNativeSQL(){
String sql = "INSERT INTO gg_department VALUES(?

, ?)"; Query query = session.createSQLQuery(sql); query.setInteger(0, 280) .setString(1, "ATGUIGU") .executeUpdate(); } @Test public void testQBC4(){ Criteria criteria = session.createCriteria(Employee.class); //1. 加入排序 criteria.addOrder(Order.asc("salary")); criteria.addOrder(Order.desc("email")); //2. 加入翻页方法 int pageSize = 5; int pageNo = 3; criteria.setFirstResult((pageNo - 1) * pageSize) .setMaxResults(pageSize) .list(); } @Test public void testQBC3(){ Criteria criteria = session.createCriteria(Employee.class); //统计查询: 使用 Projection 来表示: 能够由 Projections 的静态方法得到 criteria.setProjection(Projections.max("salary")); System.out.println(criteria.uniqueResult()); } @Test public void testQBC2(){ Criteria criteria = session.createCriteria(Employee.class); //1. AND: 使用 Conjunction 表示 //Conjunction 本身就是一个 Criterion 对象 //且当中还能够加入 Criterion 对象 Conjunction conjunction = Restrictions.conjunction(); conjunction.add(Restrictions.like("name", "a", MatchMode.ANYWHERE)); Department dept = new Department(); dept.setId(80); conjunction.add(Restrictions.eq("dept", dept)); System.out.println(conjunction); //2. OR Disjunction disjunction = Restrictions.disjunction(); disjunction.add(Restrictions.ge("salary", 6000F)); disjunction.add(Restrictions.isNull("email")); criteria.add(disjunction); criteria.add(conjunction); criteria.list(); } @Test public void testQBC(){ //1. 创建一个 Criteria 对象 Criteria criteria = session.createCriteria(Employee.class); //2. 加入查询条件: 在 QBC 中查询条件使用 Criterion 来表示 //Criterion 能够通过 Restrictions 的静态方法得到 criteria.add(Restrictions.eq("email", "SKUMAR")); criteria.add(Restrictions.gt("salary", 5000F)); //3. 运行查询 Employee employee = (Employee) criteria.uniqueResult(); System.out.println(employee); } @Test public void testLeftJoinFetch2(){ String hql = "SELECT e FROM Employee e INNER JOIN e.dept"; Query query = session.createQuery(hql); List<Employee> emps = query.list(); System.out.println(emps.size()); for(Employee emp: emps){ System.out.println(emp.getName() + ", " + emp.getDept().getName()); } } @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(); System.out.println(depts.size()); for(Department dept: depts){ System.out.println(dept.getName() + ", " + dept.getEmps().size()); } // List<Object []> result = query.list(); // result = new ArrayList<>(new LinkedHashSet<>(result));// System.out.println(result); // // for(Object [] objs: result){// System.out.println(Arrays.asList(objs));// } } @Test public void testLeftJoinFetch(){// String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps"; String hql = "FROM Department d INNER JOIN FETCH d.emps"; Query query = session.createQuery(hql); List<Department> depts = query.list(); depts = new ArrayList<>(new LinkedHashSet(depts)); System.out.println(depts.size()); for(Department dept: depts){ System.out.println(dept.getName() + "-" + dept.getEmps().size()); } } @Test public void testGroupBy(){ String hql = "SELECT min(e.salary), max(e.salary) " + "FROM Employee e " + "GROUP BY e.dept " + "HAVING min(salary) > :minSal"; Query query = session.createQuery(hql) .setFloat("minSal", 8000); List<Object []> result = query.list(); for(Object [] objs: result){ System.out.println(Arrays.asList(objs)); } } @Test public void testFieldQuery2(){ String hql = "SELECT new Employee(e.email, e.salary, e.dept) " + "FROM Employee e " + "WHERE e.dept = :dept"; Query query = session.createQuery(hql); Department dept = new Department(); dept.setId(80); List<Employee> result = query.setEntity("dept", dept) .list(); for(Employee emp: result){ System.out.println(emp.getId() + ", " + emp.getEmail() + ", " + emp.getSalary() + ", " + emp.getDept()); } } @Test public void testFieldQuery(){ String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept"; Query query = session.createQuery(hql); Department dept = new Department(); dept.setId(80); List<Object[]> result = query.setEntity("dept", dept) .list(); for(Object [] objs: result){ System.out.println(Arrays.asList(objs)); } } @Test public void testNamedQuery(){ Query query = session.getNamedQuery("salaryEmps"); List<Employee> emps = query.setFloat("minSal", 5000) .setFloat("maxSal", 10000) .list(); System.out.println(emps.size()); } @Test public void testPageQuery(){ String hql = "FROM Employee"; Query query = session.createQuery(hql); int pageNo = 22; int pageSize = 5; List<Employee> emps = query.setFirstResult((pageNo - 1) * pageSize) .setMaxResults(pageSize) .list(); System.out.println(emps); } @Test public void testHQLNamedParameter(){ //1. 创建 Query 对象 //基于命名參数. String hql = "FROM Employee e WHERE e.salary > :sal AND e.email LIKE :email"; Query query = session.createQuery(hql); //2. 绑定參数 query.setFloat("sal", 7000) .setString("email", "%A%"); //3. 运行查询 List<Employee> emps = query.list(); System.out.println(emps.size()); } @Test public void testHQL(){ //1. 创建 Query 对象 //基于位置的參数. String hql = "FROM Employee e WHERE e.salary > ? AND e.email LIKE ?

AND e.dept = ?

" + "ORDER BY e.salary"; Query query = session.createQuery(hql); //2. 绑定參数 //Query 对象调用 setXxx 方法支持方法链的编程风格. Department dept = new Department(); dept.setId(80); query.setFloat(0, 6000) .setString(1, "%A%") .setEntity(2, dept); //3. 运行查询 List<Employee> emps = query.list(); System.out.println(emps.size()); }}







版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/115846.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 插头DP小结_dp插头接线标准

    插头DP小结_dp插头接线标准插头DP一般都是棋盘模型,找路径或者环路最值或者方案数。插头:说白了就是两个联通的格子,一个走向另一个,那么这里就有一个插头。轮廓线:DP逐格DP,那么轮廓线可以分开DP过的格子和未DP的格子。轮廓线的长度明显是m+1。插头垂直于轮廓线。转移:轮廓线在换行的时候要位移,这个画画图就出来了。然后具体问题具体讨论。比如任意多个环路,不考虑方向,那么就是eatthetrees,用最

    2022年10月28日
  • 2022考研数学二考试大纲最新_数学二线性代数考研大纲

    2022考研数学二考试大纲最新_数学二线性代数考研大纲2022年数学二考试大纲考试形式和试卷结构一、试卷满分及考试时间二、答题方式三、试卷内容结构四、试卷题型结构高等数学一、函数、极限、连续二、一元函数微分学三、一元函数积分学四、多元函数微积分学五、常微分方程线性代数一、行列式二、矩阵三、向量四、线性方程组五、矩阵的特征值及特征向量六、二次型考试科目:高等数学、线性代数考试形式和试卷结构一、试卷满分及考试时间试卷满分为150分,考试时间为180分钟.二、答题方式答题方式为闭卷、笔试.三、试卷内容结构高等教学 约80%线性代数 约20%四、试

  • android:ListView排序[通俗易懂]

    android:ListView排序[通俗易懂]
    Android:ListView排序

    ListView通过适配器得到内容数据,可以对数据list先排序再提供给ListView:
    privateList>getData(){
    List>list=newArrayList>();
    //addData…
    //对list进行排序

  • cstring头文件是什么_class可以作为标识符吗

    cstring头文件是什么_class可以作为标识符吗关于在VC++中对CString进行引用时,需要按使用情况添加不同的头文件(1)atlstr.h——————————-非MFC工程中.(2)afx.h———————————-MFC工程中.

  • 兼容addEventListener事件

    兼容addEventListener事件window.onload=function(){ varp=document.getElementById("content"); if(document.addEventListener) p.addEventListener("click",function(){ alert("p点击了"); },false); else p.attachEvent(…

    2022年10月23日
  • 2012年计算机工作总结,计算机教师工作总结2011-2012

    2012年计算机工作总结,计算机教师工作总结2011-2012计算机教师工作总结2011-20122010-2011第一学期计算机教学工作总结郑龙勤本学期,我任教24,25,26,27班的计算机应用基础教学,同时兼任学校的中职资助、机房维护等工作。在各位领导和老师的热心支持和帮助下,我认真做好教学工作,积极完成学校布置的各项任务。下面我把2010-2011年第一学期的工作做简要的汇报。一、学校制度执行情况平时积极参加全校教职工会议,认真学习学校下达的文件,关…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号