Hibernate3 關聯關係映射

多表設計sql

l 在開發中,前期進行需求分析,需求分析提供E--R圖,根據ER圖編寫表結構。數據庫

l 表之間關係存在3種:一對多、多對多、一對一。(回顧)緩存

 

一對多:1表(主表)必須主鍵 和 多表(從表)必須外鍵,主表的主鍵 與 從表外鍵 造成主外鍵關係session

多對多:提供中間表(從表),提供2個字段(外鍵)分別對應兩個主表。app

一對一:???函數

 

 

 

l 面單對象描述 對象與對象 之間關係?【掌握】性能

一對多:客戶和訂單學習

private class Customer{fetch

//一對多:一個客戶 擁有 多個訂單優化

private Set<Order> orderSet;

}

private class Order{

//多對一:多個訂單 屬於 一個客戶

private Customer customer;

}

多對多:Student學生 和 Course課程

private class Student{

//多對多:多個學生(當前)學習 【不一樣課程】

private Set<Course> courseSet ...;

}

private class Course{

//多對多:多個課程 能夠被 【不一樣學生】學習

private Set<Student> student = ...;

}

一對一:公司company 和 地址address

private class Company{

private Address address;

}

private class Address{

private Company company;

}

 

關聯關係映射

2.1 一對多實現【掌握】

2.1.1 實現類

public class Customer {

 

private Integer cid;

private String cname;

 

//一對多:一個客戶(當前客戶) 擁有 【多個訂單】

// * 須要容器存放多個值,通常建議Set (不重複、無序)

// * 參考集合:ListMapArray等 

// ** 建議實例化--使用方便

private Set<Order> orderSet = new HashSet<Order>();

 

public class Order {

private Integer xid;

private String price;

 

//多對一:多個訂單屬於【一個客戶】

private Customer customer;

 

 

2.1.2 配置文件

l Customer.hbm.xml

<class name="com.hibernate.b_onetomany.Customer" table="t_customer">

<id name="cid">

<generator class="native"></generator>

</id>

<property name="cname"></property>

 

<!-- 一對多:一個客戶(當前客戶) 擁有 【多個訂單】

肯定容器  set <set>

2 name肯定對象屬性名

肯定從表外鍵的名稱

肯定關係,及另外一個對象的類型

注意:

hibernate中能夠只進行單向配置

每個配置項均可以完整的描述彼此關係。

通常狀況採用雙向配置,雙方均可以完成描述表與表之間關係。

 -->

<!-- 一對多:一個客戶(當前客戶) 擁有 【多個訂單】 -->

<set name="orderSet" cascade="delete-orphan">

<key column="customer_id"></key>

<one-to-many class="com.it.b_onetomany.Order"/>

</set>

</class>

 

l Order.hbm.xml

<class name="com.hibernate.b_onetomany.Order" table="t_order">

<id name="xid">

<generator class="native"></generator>

</id>

<property name="price"></property>

 

<!-- 多對一:多個訂單屬於【一個客戶】 

* name 肯定屬性名稱

* class 肯定自定義類型

* column 肯定從表的外鍵名稱

-->

<many-to-one name="customer" class="com.hibernate.b_onetomany.Customer" column="customer_id"></many-to-one>

 

</class>

 

 

 

 

2.2 一對多操做

2.2.1 保存客戶

@Test

public void demo01(){

// 1 建立客戶,並保存客戶--成功

Session session = factory.openSession();

session.beginTransaction();

 

Customer customer = new Customer();

customer.setCname("田志成");

 

session.save(customer);

 

session.getTransaction().commit();

session.close();

}

 

2.2.2 保存訂單

@Test

public void demo02(){

// 2 建立訂單,保存訂單--成功,外鍵爲null

Session session = factory.openSession();

session.beginTransaction();

 

Order order = new Order();

order.setPrice("998");

 

session.save(order);

 

session.getTransaction().commit();

session.close();

}

 

2.2.3 客戶關聯訂單,只保存客戶

@Test

public void demo03(){

// 3 建立客戶和訂單,客戶關聯訂單,保存客戶?

Session session = factory.openSession();

session.beginTransaction();

 

//1 客戶和訂單

Customer customer = new Customer();

customer.setCname("成成");

 

Order order = new Order();

order.setPrice("998");

 

//2 客戶關聯訂單

customer.getOrderSet().add(order);

 

//3 保存客戶

session.save(customer);

 

session.getTransaction().commit();

session.close();

}

 

 

 

2.2.4 雙向關聯,使用inverse映射

 

 

@Test

public void demo04(){

// 4  建立客戶和訂單,客戶關聯訂單,訂單也關聯客戶,保存客戶和訂單? 

// * 開發中優化程序 , n + 1 問題?

// ** 解決方案1:客戶不關聯訂單 ,不建議

// ** 解決方案2:客戶放棄對訂單表外鍵值的維護。

// **** Customer.hbm.xml <set name="orderSet" inverse="true">

// ** inverse 將維護外鍵值的權利交予對象。至關於本身放棄。(反轉)

Session session = factory.openSession();

session.beginTransaction();

 

//1 客戶和訂單

Customer customer = new Customer();

customer.setCname("成成");

 

Order order = new Order();

order.setPrice("998");

 

//2 客戶關聯訂單

customer.getOrderSet().add(order);

//3 訂單也關聯客戶

order.setCustomer(customer);

 

//4 保存客戶

// * 1 save(order) -- insert  --> 1,998 null

// * 2 訂單管理客戶,此時null --預留update --> 更新全部(正常設置)

// * 3 save(customer) -- insert --> 1,成成

// * 4 客戶關聯訂單  --> 預留update --> 更新訂單外鍵 (維護外鍵)

// * 5 提交commit --> 執行和 

session.save(order);

session.save(customer);

 

session.getTransaction().commit();

session.close();

}

 

l 在一對多開發中,一方通常都放棄對外鍵值的維護。及<set inverse="true

 

 

 

2.3 級聯操做(讀、理解)

2.3.1 save-update  級聯保存或更新

 

 

@Test

public void demo032(){

// 32 建立客戶和訂單,客戶關聯訂單,保存客戶? --拋異常

// ** 解決方案2:級聯操做--級聯保存或更新

// ** Customer.hbm.xml <set cascade="save-update">

// ** 在保存客戶的同時,一併保存訂單

Session session = factory.openSession();

session.beginTransaction();

 

//1 客戶和訂單

Customer customer = new Customer(); //瞬時態

customer.setCname("成成");

 

Order order = new Order(); //瞬時態

order.setPrice("998");

 

//2 客戶關聯訂單

customer.getOrderSet().add(order);

 

//3 保存客戶

session.save(customer); //持久態

// 關聯操做都是持久態的,此時 持久態Customer 引用 一個 瞬時態的Order 拋異常

 

session.getTransaction().commit();

session.close();

}

 

2.3.2 delete 級聯刪除

 

@Test

public void demo05(){

// 5 查詢客戶,並刪除(持久態)

// 默認:當刪除客戶,默認將訂單外鍵設置成null

// 級聯刪除:刪除客戶時,並將客戶的訂單刪除。

// ** Customer.hbm.xml <set name="orderSet" cascade="delete">

Session session = factory.openSession();

session.beginTransaction();

 

Customer customer = (Customer) session.get(Customer.class, 10);

 

session.delete(customer);

 

 

session.getTransaction().commit();

session.close();

}

 

2.3.3 孤兒刪除

l 一對多關係,存在父子關係。1表(主表)能夠成爲父表,多表(從表)也能夠子表。

 

 

總結:

主表不能刪除,從表已經引用(關聯)的數據

從表不能添加,主表不存在的數據。

 

 

@Test

public void demo06(){

// 6 查詢客戶,並查詢訂單,解除客戶和訂單訂單的關係

// * 默認:客戶和訂單解除關係後,外鍵被設置成null,此時訂單就是孤兒。客戶和訂單都存在。

// * 孤兒刪除(孤子刪除),當訂單稱爲孤兒,一併刪除。客戶仍存在。

Session session = factory.openSession();

session.beginTransaction();

 

//1 查詢客戶

Customer customer = (Customer) session.get(Customer.class, 9);

 

//2查詢訂單

Order order = (Order) session.get(Order.class, 8);

 

//3 解除關係

customer.getOrderSet().remove(order);

 

session.getTransaction().commit();

session.close();

}

 

2.3.4 總結

save-updateA保存,同時保存B

delete:刪除A,同時刪除BAB都不存在

delete-orphan:孤兒刪除,解除關係,同時將B刪除,A存在的。

若是須要配置多項,使用逗號分隔。<set cascade="save-update,delete">

 

all : save-update 和 delete 整合

all-delete-orphan : 三個整合

 

 

1.1.1 Hibernate的關聯關係映射:(多對多)

1.1.1.1 多對多的配置:

:

Student:

public class Student {

private Integer sid;

private String sname;

// 學生選擇多門課程.

private Set<Course> courses = new HashSet<Course>();

...

}

 

Course:

public class Course {

private Integer cid;

private String cname;

// 課程能夠被多個學生選擇:

private Set<Student> students = new HashSet<Student>();

...

}

 

Student.hbm.xml

<hibernate-mapping>

<class name="cn.itcast.demo3.Student" table="student">

<id name="sid" column="sid">

<generator class="native"/>

</id>

<property name="sname" column="sname"/>

<!-- 配置多對多關聯關係 -->

<set name="courses" table="stu_cour">

<key column="sno"/>

<many-to-many class="cn.itcast. demo3.Course" column="cno"/>

</set>

</class>

</hibernate-mapping>

 

Course.hbm.xml

<hibernate-mapping>

<class name="cn.itcast. demo3.Course" table="course">

<id name="cid" column="cid">

<generator class="native"/>

</id>

 

<property name="cname" column="cname"/>

 

<!-- 配置多對多關聯關係映射 -->

<set name="students" table="stu_cour">

<key column="cno"/>

<many-to-many class="cn.itcast. demo3.Student" column="sno"/>

</set>

</class>

</hibernate-mapping>

 

抓取策略(優化)

2.1 檢索方式

l 當即檢索:當即查詢,在執行查詢語句時,當即查詢全部的數據。

l 延遲檢索:延遲查詢,在執行查詢語句以後,在須要時在查詢。(懶加載)

 

2.2 檢查策略

l 類級別檢索:當前的類的屬性獲取是否須要延遲。

l 關聯級別的檢索:當前類 關聯 另外一個類是否須要延遲。

 

 

2.3 類級別檢索

l get:當即檢索。get方法一執行,當即查詢全部字段的數據。

l load:延遲檢索。默認狀況,load方法執行後,若是隻使用OID的值不進行查詢,若是要使用其餘屬性值將查詢 。 Customer.hbm.xml  <class  lazy="true | false">

lazy 默認值true,表示延遲檢索,若是設置false表示當即檢索。

 

 

@Test

public void demo02() {

//類級別

Session session = factory.openSession();

session.beginTransaction();

 

//1當即

// Customer customer = (Customer) session.get(Customer.class, 1);

//2延遲

Customer customer = (Customer) session.load(Customer.class, 1);

 

 

 

//打印

System.out.println(customer.getCid());

System.out.println(customer.getCname());

 

session.getTransaction().commit();

session.close();

}

 

 

 

2.4 關聯級別檢索

2.4.1 一對多或多對多

2.4.1.1 介紹

l 容器<set> 提供兩個屬性:fetchlazy

fetch:肯定使用sql格式

lazy:關聯對象是否延遲。

l fetchjoinselectsubselect

join:底層使用迫切左外鏈接

select:使用多個select語句(默認值)

subselect:使用子查詢

l lazyfalsetrueextra

false:當即

true:延遲(默認值)

extra:極其懶惰

 

 

2.4.1.2 fetch="join"

l fetch="join" lazy無效。底層使用迫切左外鏈接,使用一條select將全部內容所有查詢。

 

@Test

public void demo03() {

//關聯級別:一對多,

// * Customer.hbm.xml  <set fetch="join">

// *** select語句使用左外鏈接,一次性查詢全部

Session session = factory.openSession();

session.beginTransaction();

 

//1 查詢客戶

Customer customer = (Customer) session.get(Customer.class, 1);

System.out.println(customer.getCname());

 

//2 查詢客戶訂單數

Set<Order> orderSet = customer.getOrderSet();

System.out.println(orderSet.size());

 

//3 查詢客戶訂單詳情

for (Order order : orderSet) {

System.out.println(order);

}

 

 

session.getTransaction().commit();

session.close();

}

 

2.4.1.3 fetch="select"

l 當前對象 和 關聯對象 使用多條select語句查詢。

l lazy="false" , 當即,先查詢客戶select,當即查詢訂單select

l lazy="true",延遲,先查詢客戶select,須要訂單時,再查詢訂單select

l lazy="extra",極其懶惰(延遲),先查詢客戶select, 若是隻須要訂單數,使用聚合函數(不查詢詳情)

 

 

 

 

 

 

2.4.1.4 fetch="subselect"

l 將使用子查詢。注意:必須使用Query不然看不到效果。

l lazy= 同上

@Test

public void demo04() {

//關聯級別:一對多,

// 演示3* Customer.hbm.xml  <set fetch="subselect">

Session session = factory.openSession();

session.beginTransaction();

 

//1 查詢客戶

List<Customer> allCustomer = session.createQuery("from Customer").list();

Customer customer = allCustomer.get(0);

System.out.println(customer.getCname());

 

//2 查詢客戶訂單數

Set<Order> orderSet = customer.getOrderSet();

System.out.println(orderSet.size());

 

//3 查詢客戶訂單詳情

for (Order order : orderSet) {

System.out.println(order);

}

 

 

session.getTransaction().commit();

session.close();

}

 

 

 

 

 

 

2.4.2 多對一

2.4.2.1 介紹

l <many-to-one fetch="" lazy="">  (<one-to-one>)

l fetch取值:joinselect

join:底層使用迫切左外鏈接

select:多條select語句

l lazy取值:falseproxyno-proxy

false:當即

proxy:採用關聯對象 類級別檢索的策略。

訂單 關聯 客戶 (多對一)

訂單 當即得到 客戶,須要在客戶Customer.hbm.xml <class lazy="false"> 

訂單 延遲得到 客戶,須要在客戶Customer.hbm.xml <class lazy="true"> 

 

no-proxy 不研究

 

 

 

2.4.2.2 fetch="join"

l fecth="join" select語句使用左外鏈接,此時lazy無效。

 

 

 

@Test

public void demo05() {

//關聯級別:多對一,

// 演示1* Order.hbm.xml  <set fetch="join">  lazy無效

// * 注意:檢查Customer.hbm.xml 和 Order.hbm.xml 沒有額外的配置

Session session = factory.openSession();

session.beginTransaction();

 

//1 查詢訂單

Order order = (Order) session.get(Order.class, 1);

System.out.println(order.getPrice());

 

//2 查詢訂單客戶信息

Customer customer = order.getCustomer();

System.out.println(customer.getCname());

 

 

session.getTransaction().commit();

session.close();

}

2.4.2.3 fetch="select"

l 將採用多條select語句,lazy="proxy"是否延遲,取決關聯對象 類級別檢索策略。

 

l lazy="false"

 

l lazy="proxy"

 

 

 

2.5 批量查詢

l 當客戶 關聯查詢 訂單,給每個客戶生產一個select語句查詢訂單。批量查詢使用in語句減小查詢訂單語句個數。

默認:select * from t_order where customer_id = ?

批量:select * from t_order where customer_id in (?,?,?,?)

l <set batch-size="5"> 5表示括號中?個數。

 

 

@Test

public void demo06() {

//批量查詢

Session session = factory.openSession();

session.beginTransaction();

 

//1 查詢全部客戶

List<Customer> allCustomer = session.createQuery("from Customer").list();

 

//2遍歷

for (Customer customer : allCustomer) {

System.out.println(customer.getCname());

System.out.println(customer.getOrderSet().size());

}

 

 

session.getTransaction().commit();

session.close();

}

2.6 檢索總結

 

檢索策略

優勢

缺點

優先考慮使用的場合

當即檢索

對應用程序徹底透明,無論對象處於持久化狀態仍是遊離狀態,應用程序均可以從一個對象導航到關聯的對象

(1)select語句多

(2)可能會加載應用程序不須要訪問的對象,浪費許多內存空間。

(1)類級別

(2)應用程序須要當即訪問的對象

(3)使用了二級緩存

延遲檢索

由應用程序決定須要加載哪些對象,能夠避免執行多餘的select語句,以及避免加載應用程序不須要訪問的對象。所以能提升檢索性能,並節省內存空間。

應用程序若是但願訪問遊離狀態的代理類實例,必須保證她在持久化狀態時已經被初始化。

(1)一對多或者多對多關聯

(2)應用程序不須要當即訪問或者根本不會訪問的對象

 

錶鏈接檢索

(1)對應用程序徹底透明,無論對象處於持久化狀態仍是遊離狀態,均可從一個對象導航到另外一個對象。

(2)使用了外鏈接,select語句少

(1)可能會加載應用程序不須要訪問的對象,浪費內存。

(2)複雜的數據庫錶鏈接也會影響檢索性能。

(1)多對一或一對一關聯

(2)須要當即訪問的對象

(3)數據庫有良好的錶鏈接性能。

 

Customer  Get(int id)

Return Session.load(Customer.class,id);

  1. layz=false
  2. Service層得到在頁面要上要用到的屬性=> Service層中確保數據已經

查詢方式總結

1.經過OID檢索(查詢)

get()當即、若是沒有數據返回null

load()延遲,若是沒有數據拋異常。

2.導航對象圖檢索方式:關聯查詢

customer.getOrderSet()

user.getPost().getDepartment().getDepName();

3.原始sql語句

SQLQuery sqlQuery = session.createSQLQuery("sql 語句")   --->表,表字段(列)

sqlQuery.list() 查詢全部

sqlQuery.uniqueResult() 查詢一個

4.HQLhibernate query language hibernate 查詢語言【1

Query query = session.createQuery("hql語句")  --> 對象,對象屬性

5.QBCquery by criteria 純面對對象查詢語言【2

相關文章
相關標籤/搜索