連接查詢:
關系型數據庫之所以強大,其中一個原因就是可以統一使用表來管理同類數據信息,並且可以在相關數據之間建立關系。作為支持關系型數據庫的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進行集合填充操作。