您的位置:首页 > 数据库

Hibernate深入理解----Hibernate 检索方式(HQL,QBC,本地SQL)

2016-09-20 22:47 671 查看
参考代码下载github:https://github.com/changwensir/java-ee/tree/master/hibernate4

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

一、HQL 检索方式HQL

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

•HQL 检索方式包括以下步骤:
    –通过 Session的createQuery()方法创建一个Query对象,它包括一个HQL查询语句.HQL
查询语句中可以包含命名参数
    –动态绑定参数
    –调用 Query相关方法执行查询语句.
•Qurey接口支持方法链编程风格,
它的setXxx()方法返回自身实例,而不是void类型
•HQL vsSQL:
    –HQL 查询语句是面向对象的, Hibernate
负责解析 HQL查询语句,
然后根据对象-关系映射文件中的映射信息,把HQL查询语句翻译成相应的
SQL语句.HQL
查询语句中的主体是域模型中的类及类的属性
    –SQL 查询语句是与关系数据库绑定在一起的.SQL
查询语句中的主体是数据库表及表的字段.
•绑定参数:
    –Hibernate 的参数绑定机制依赖于JDBCAPI
中的 PreparedStatement的预定义SQL语句功能.
    –HQL 的参数绑定由两种形式:
      •按参数名字绑定:
在HQL查询语句中定义命名参数,命名参数以“:”
开头.
      •按参数位置绑定:
在HQL查询语句中用“?”
来定义参数位置
    –相关方法:
      •setEntity():
把参数与一个持久化类绑定
      •setParameter():绑定任意类型的参数.该方法的第三个参数显式指定Hibernate映射类型
•HQL 采用 ORDER BY关键字对查询结果排序
测试用的是双向1对n

public class Department {

private Integer id;
private String name;

private Set<Employee> emps = new HashSet<Employee>();

//省去set,get方法
}
public class Employee {
private Integer id;
private String name;
private float salary;
private String email;

private Department dept;

public Employee(String email, float salary, Department dept) {
super();
this.salary = salary;
this.email = email;
this.dept = dept;
}

public Employee() {
}

//省去get,set方法
}
对应的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 package="com.changwen.hibernate4.query.entities">

<class name="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="Employee" />
</set>

</class>
</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">

<hibernate-mapping package="com.changwen.hibernate4.query.entities">

<class name="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="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>
测试

//基于位置的参数查询
@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());
}
/**
* 基于命名参数查询
*/
@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());
}

1-1.分页查询

    –setFirstResult(intfirstResult):设定从哪一个对象开始检索,参数firstResult表示这个对象在查询结果中的索引位置,索引位置的起始值为0.默认情况下,Query
从查询结果中的第一个对象开始检索
    –setMaxResults(intmaxResults):设定一次最多检索出的对象的数目.在默认情况下,Query
和 Criteria接口检索出查询结果中所有的对象
@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);
}


1-2.在映射文件中定义命名查询语句

    –Hibernate 允许在映射文件中定义字符串形式的查询语句.
    –<query>元素用于定义一个HQL查询语句,它和<class>元素并列.



    –在程序中通过 Session的getNamedQuery()方法获取查询语句对应的Query对象.
/**
* 命名查询:
* Hibernate 允许!!在映射文件!!中定义字符串形式的查询语句.<query> 元素用于定义一个 HQL 查询语句, 它和 <class> 元素并列.
*/
@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());
}


1-3.投影查询

    •投影查询:
查询结果仅包含实体的部分属性.通过SELECT关键字实现.
    •Query 的list()
方法返回的集合中包含的是数组类型的元素,
每个对象数组代表查询结果的一条记录
    •可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录,使程序代码能完全运用面向对象的语义来访问查询结果集.
    •可以通过 DISTINCT关键字来保证查询结果不会返回重复元素
@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));
}
}


1-4.报表查询

    •报表查询用于对数据分组和统计,与SQL一样,HQL
利用 GROUPBY关键字对数据分组,用HAVING关键字对分组数据设定约束条件.
    •在 HQL
查询语句中可以调用以下聚集函数
      –count(),min(),max(),sum(),avg()
@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());
}
}


1-5.HQL (迫切)左外连接

•迫切左外连接:
    –LEFT JOINFETCH关键字表示迫切左外连接检索策略.
    –list() 方法返回的集合中存放实体对象的引用,每个Department对象关联的Employee 
集合都被初始化,存放所有关联的Employee的实体对象.
    –查询结果中可能会包含重复元素,可以通过一个HashSet来过滤重复元素
•左外连接:
    –LEFT JOIN关键字表示左外连接查询.
    –list() 方法返回的集合中存放的是对象数组类型
    –根据配置文件来决定 Employee
集合的检索策略.
    –如果希望 list()方法返回的集合中仅包含Department对象,可以在HQL查询语句中使用SELECT关键字
/**
* 左外连接: LEFT JOIN 关键字表示左外连接查询.
*/
@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));
//		}
}

/**
* 迫切左外连接: LEFT JOIN FETCH 关键字表示迫切左外连接检索策略.
*/
@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<Department>(new LinkedHashSet(depts));
System.out.println(depts.size());

for(Department dept: depts){
System.out.println(dept.getName() + "-" + dept.getEmps().size());
}
}


1-6.HQL (迫切)内连接

•迫切内连接:
    –INNER JOIN FETCH关键字表示迫切内连接,也可以省略INNER关键字
    –list() 方法返回的集合中存放Department对象的引用,每个Department对象的Employee集合都被初始化,存放所有关联的Employee对象
•内连接:
    –INNER JOIN 关键字表示内连接,也可以省略INNER关键字
    –list() 方法的集合中存放的每个元素对应查询结果的一条记录,每个元素都是对象数组类型
    –如果希望 list()方法的返回的集合仅包含Department 
对象,可以在HQL查询语句中使用SELECT关键字
/**
* 内连接: INNER JOIN 关键字表示内连接, 也可以省略 INNER 关键字
*/
@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());
}
}


1-7.关联级别运行时的检索策略

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

二、QBC 检索和本地SQL检索

    •QBC 查询就是通过使用Hibernate提供的QueryByCriteria
API 来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口
    •本地SQL查询来完善HQL不能涵盖所有的查询特性
@Test
public void testHQLUpdate(){
String hql = "DELETE FROM Department d WHERE d.id = :id";

session.createQuery(hql).setInteger("id", 280)
.executeUpdate();
}

/**
* 本地SQL查询来完善HQL不能涵盖所有的查询特性
*/
@Test
public void testNativeSQL(){
String sql = "INSERT INTO gg_department VALUES(?, ?)";
Query query = session.createSQLQuery(sql);

query.setInteger(1, 280)
.setString(2, "ATGUIGU")
.executeUpdate();
}

/**
* QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,
* 这种 API 封装了 SQL 语句的动态拼装,对查询提供了更加面向对象的功能接口本地SQL查询来完善HQL不能涵盖所有的查询特性
*/
@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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息