连接查询:
关系型数据库之所以强大,其中一个原因就是可以统一使用表来管理同类数据信息,并且可以在相关数据之间建立关系。作为支持关系型数据库的SQL语句来说,自然要对全面发挥这种强大功能提供支持,这个支持就是连接查询。同样作为一种关系型数据库的持久层框架,Hibernate也对连接查询提供了丰富的支持,在Hibernate中通过HQL与QBC两种查询方式都可以支持连接查询。下面这一部分我们将通过这两种查询技术,来详细讨论有关 Hibernate对连接查询支持的各个细节。在讲解连接查询之前,我们先来回忆一下在第一部分中讲解的有关实体关联关系的映射,在实体的配置文件中可以通过配置集合元素来指定对关联实体的映射以及检索策略。因此我们可以在实体映射配置文件中,指定关联实体检索策略,对关联实体的检索策略可以指定为“延迟检索”,“立即检索”,“迫切左外连接检索”,如下所示
和SQL查询一样,HQL也支持各种各样的连接查询,如内连接、外连接。我们知道在SQL中可通过join字句实现多表之间的连接查询。HQL同样提供了连接查询机制,还允许显示指定迫切内连接和迫切左外连接。
创建实体类:
部门:
package cn.lex.entity;
import java.util.HashSet;
import java.util.Set;
/*
部门实体
*/
public class Dept {
private Integer deptNo;
private String deptName;
private Set<Emp> emps=new HashSet<Emp>();
public Dept(Integer deptNo, String deptName) {
this.deptNo = deptNo;
this.deptName = deptName;
}
public Dept() {
}
public Integer getDeptNo() {
return deptNo;
}
public void setDeptNo(Integer deptNo) {
this.deptNo = deptNo;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public Set<Emp> getEmps() {
return emps;
}
public void setEmps(Set<Emp> emps) {
this.emps = emps;
}
}
员工:
package cn.lex.entity;
/**
* 雇员实体
*/
public class Emp {
private Integer empId;
private String empName;
//植入部门对象
private Dept dept;
public Emp(Integer empId, String empName) {
this.empId = empId;
this.empName = empName;
}
public Emp() {
}
public Integer getEmpId() {
return empId;
}
public void setEmpId(Integer empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
创建hbm.xml
Dept.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="Dept" table="DEPT">
<id name="deptNo" column="DEPTNO">
<!-- 主键的生成策略 -->
<generator class="native" >
</generator>
</id>
<property name="deptName" type="string" column="DEPTNAME"/>
<!-- -维护一个员工的set集合
name:当前类的set集合名称
key:多的一方的外键名称
-->
<set name="emps">
<key column="deptNo"></key>
<one-to-many class="Emp"/>
</set>
</class>
</hibernate-mapping>
Emp.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.lex.entity">
<class name="Emp" table="EMP">
<id name="empId" type="int" column="EMPID">
<generator class="native">
</generator>
</id>
<property name="empName" column="EMPNAME"></property>
<!-- 多对一
name:多的一方,植入一的一方属性名
class:一的一方的类型
column:数据库端在Emp表产生的外键列
-->
<many-to-one name="dept" class="Dept" column="deptNo" ></many-to-one>
</class>
</hibernate-mapping>
hibernate.cfg.xml:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="connection.username">lex</property>
<property name="connection.password">lex</property>
<!-- SQL dialect Sql方言 -->
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<!-- 是否在控制台打印sql-->
<property name="show_sql">true</property>
<!--设置和当前线程绑定的Session配置-->
<property name="hibernate.current_session_context_class">thread</property>
<!--开启二级缓存-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!--指定二级缓存工厂-->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>
<!--开启查询缓存-->
<!-- <property name="hibernate.cache.use_query_cache">true</property>-->
<!--自动建表-->
<!-- <property name="hbm2ddl.auto">update</property>-->
<mapping resource="cn/lex/entity/Emp.hbm.xml"/>
<mapping resource="cn/lex/entity/Dept.hbm.xml"/>
<class-cache usage="read-write" class="cn.happy.entity.Dept"/>
<class-cache usage="read-write" class="cn.happy.entity.Emp"/>
<collection-cache collection="cn.happy.entity.Dept.emps" usage="read-write"></collection-cache>
</session-factory>
</hibernate-configuration>
书写测试类:
第一个案例:
Configuration cfg;
Session session;
Transaction tx;
@Before
public void myBefore(){
//创建配置对象
cfg=new Configuration().configure();
// 2.根据配置对象创建SessionFactory
SessionFactory factory=cfg.buildSessionFactory();
//3.根据SessionFactory去创建Session
session= factory.getCurrentSession();
//3.5在Session创建后开启事务 xxx0001 xxxxx003
tx= session.beginTransaction();
}
@After
public void myAfter(){
//5.提交事务
tx.commit();
//6.关闭session
//session.close();
}
内连接和迫切内连接:
内连接:
public void innerJoinTest(){
Query query = session.createQuery("select distinct d from Dept d inner join d.emps");
List<Dept> list = query.list();
for (Dept dept : list) {
System.out.println(dept.getDeptName());
for (Emp emp : dept.getEmps()) {
System.out.println(emp.getEmpName());
}
}
}
迫切内连接:
@Test
public void innerJoinTest(){
Query query = session.createQuery("select distinct d from Dept d inner join fetch d.emps");
List<Dept> list = query.list();
for (Dept dept : list) {
System.out.println(dept.getDeptName());
for (Emp emp : dept.getEmps()) {
System.out.println(emp.getEname());
}
}
}
第二个示例(隐式内连接)
@Test
//02.隐式内连接
public void testHideInnerJoin(){
Query query = session.createQuery("from Emp e where e.dept.deptName='开发部'");
List<Emp> list = query.list();
for (Emp emp : list) {
System.out.println(emp.getEname());
}
}
注意:
fetch关键字只对inner join和left join有效。对于right join而言,由于作为关联对象容器的”左边”对象可能为null,所以也就无法通过fetch关键字强制Hibernate进行集合填充操作。