1. 程式人生 > >Hibernate框架技術視頻課程——筆記(三)

Hibernate框架技術視頻課程——筆記(三)

html ble ima 一對一關聯 .html creat 持久 read 抓取

視頻課程鏈接:http://edu.51cto.com/course/10747.html

一、Hibernate關聯關系

1. 實體之間的關系

  • 泛化關系

    通過對象之間的繼承來實現

  • 關聯關系

    通過一個對象持有另一個對象的實例來實現

    類與類之間最常見的關系就是關聯關系

2. 關聯關系

  • 多對一
  • 一對多
  • 多對多
  • 一對一

二、 多對一關系

1. 數據庫表

create table t_dept(
    id int primary key auto_increment,
    name varchar(200)
)engine=Innodb default charset=utf8;

create table t_emp(
    id int primary key auto_increment,
    name varchar(200),
    dept_id int,
    foreign key(dept_id) references t_dept(id)
)engine=Innodb default charset=utf8;

多對一關系:多個員工在同一個部門

? 多方 ——> 員工

? 一方 ——> 部門

2. 配置方式

public class Emp implements Serializable {
    private Integer id;
    private String name;
    private Dept dept; // 在多方定義一方的引用 
    //...
}
<!-- 
   配置多對一關系
    name:屬性名
    column:列名,外鍵列
    class:屬性的類型
   -->
<many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> 

3. load/get查詢

3.1 默認不查詢關聯數據

調用load/get查詢對象時,默認只會查詢當前類對象的表,不會查詢關聯表數據,稱為關聯數據的延遲加載

只有當第一次訪問時才會進行數據的查詢

Session session = HibernateUtil.getSession();
TransactionManager.beginTransaction();

Emp emp=(Emp) session.get(Emp.class, 1);
System.out.println(emp.getName());
System.out.println("--------------------------");
System.out.println(emp.getDept().getName());

TransactionManager.commit();

3.2 關於no Session問題

? 當執行下面代碼時會出現no Session問題

Emp emp=null;
try {
  Session session = HibernateUtil.getSession();
  TransactionManager.beginTransaction();

  emp=(Emp) session.get(Emp.class, 1);
  System.out.println(emp.getName());
  System.out.println("--------------------------");

  TransactionManager.commit();
} catch (Exception e) {
  TransactionManager.rollback();
  e.printStackTrace();
} finally {
  HibernateUtil.close();
}
System.out.println(emp.getDept().getName());

? 如何解決:

  • 使用lazy="false"
  • 使用fetch="join"

3.3 lazy配置

<!--                
lazy:數據加載策略,可取值如下
     false:立即加載關聯數據
       使用的是:兩次查詢
     proxy:懶加載,以代理對象的方式進行延遲加載,默認值   
     no-proxy:懶加載,  該方式在編譯時需要進行 字節碼增強,否則和proxy沒區別,很少使用
   -->
<many-to-one name="dept" column="dept_id" class="Dept" lazy="no-proxy"></many-to-one> 

3.4 fetch配置

<!--
fetch:抓取數據,可取值如下
     join:立即加載,使用聯接查詢
       使用的是:一次查詢!!
       註:此時會lazy配置無效,總是會立即加載關聯數據,使用聯接查詢
     select:    懶加載,會再執行一次selecg查詢,默認值
   -->
<many-to-one name="dept" column="dept_id" class="Dept" lazy="false" fetch="join"></many-to-one> 

4. HQL單表查詢

Emp emp= null;
try {
  Session session = HibernateUtil.getSession();
  TransactionManager.beginTransaction();

  String hql="from Emp e where e.id=:id";
  emp=(Emp) session.createQuery(hql).setInteger("id", 1).uniqueResult();
  System.out.println(emp.getName());
  System.out.println("----------------------");

  TransactionManager.commit();
} catch (Exception e) {
  TransactionManager.rollback();
  e.printStackTrace();
} finally {
  HibernateUtil.close();
}
System.out.println(emp.getDept().getName());

結論:對於HQL查詢,lazy配置項有效,fetch配置項無效

5. HQL聯接查詢

5.1 left join

? left join 只做聯接操作,不查關聯數據

? 根據lazy配置項,擇機進行再次查詢

5.2 left join fetch

? left join fetch既做聯接操作,也查關聯數據

? lazy配置項無效,總是使用聯接查詢,一次性將數據都查詢出來

6. 增刪改操作

6.1 基本操作

? 添加操作:

  • 多方對象中的一方為null持久態遊離態

    ? 正常保存

    ?

  • 多方對象中的一方為臨時態

    ? 報錯:

    org.hibernate.TransientObjectException: object references an unsaved transient instanc

    解決方法:

    • 轉換為持久態
    • 配置cascade

6.2 cascade配置

<!--    
    cascade:級聯操作
     none:不進行級聯操作,默認值
     all:對所有操作進行級聯操作(insert/delete/update)  
     save-update:執行保存和更新時進行級聯操作
     delete:執行刪除時進行級聯操作,主要用於一對多操作
   -->
<many-to-one name="dept" column="dept_id" class="Dept" lazy="false" fetch="select" cascade="delete"></many-to-one> 

三、一對多關系

1. 數據庫表

create table t_class(
    id int primary key auto_increment,
    name varchar(200)
)engine=Innodb default charset=utf8;

create table t_student(
    id int primary key auto_increment,
    name varchar(200),
    class_id int,
    foreign key(class_id) references t_class(id)
)engine=Innodb default charset=utf8;

一對多關聯:一個班級包含多名學生

? 一方 —— > 班級

? 多方 —— > 學生

2. 配置方式

<!-- 
   配置一對多關系
    name:屬性名
    table:屬性關聯的表

    cascade:級聯操作
     none
     all
     save-update
     delete:級聯刪除,刪除的過程:
      1.將所有引用一方數據的外鍵全部設置為null
       將clazz對象對應的所有student的class_id都設置為null
      2.刪除對應set集合中的數據
       將clazz中的set集合中的student刪除
      3.刪除自己對應的數據
       將clazz對象刪除           
   -->
<set name="students" table="t_student" lazy="false" fetch="join" cascade="delete">
  <!-- 關聯的列,外鍵列,即關聯表t_student中的哪個字段關聯到t_class表 -->
  <key column="class_id"></key>
  <!-- 關聯的類,屬性的類型 -->
  <one-to-many class="Student"/>
</set> 

3. inverse配置

? inverse 反轉,一般指控制權的反轉

<!--
inverse:反轉
     false:一方維護關聯關系,默認值
     true:由對方維護關聯關系,即由多方維護,一方放棄對set集合的維護                
   -->
<set name="students" table="t_student" lazy="true" fetch="select" inverse="true">

4. 雙向關聯關系

4.1 雙向一對多

? 前面我們配置的都是單向的關系:

  • 單向多對一
  • 單向一對多

    ?如果同時配置了單向多對一和單向一對多,則就是雙向一對多雙向多對一

    ?inverse屬性只能在<set>中配置,一般都會配置,因為關聯關系由多方維護更合適

4.2 關於棧溢出的問題

? 重寫實體類的toString()的方法

Exception in thread "main" java.lang.StackOverflowError

原因:因為重寫了關聯實體的toString()方法,並且包含關聯屬性,當調用toString()方法時會導航查詢關聯對象,關聯對象雙會導航查詢對方,最終導致棧溢出。

解決:不要重寫toString()方法,或者 重寫toString()時不要包含關聯屬性

四、多對多關系

1. 數據庫表

關系型數據庫中如何實現多對多關系?

  • 使用中間表,將多對多轉換為兩個一對多
  • 用中間表來維護多對多關系和數據
create table t_stu(
    id int primary key auto_increment,
    name varchar(200)
)engine=Innodb default charset=utf8;

create table t_course(
    id int primary key auto_increment,
    name varchar(200)
)engine=Innodb default charset=utf8;

create table t_stu_course(
    id int primary key auto_increment,
    stu_id int,
    course_id int,
    foreign key(stu_id) references t_stu(id),
    foreign key(course_id) references t_course(id)
)engine=Innodb default charset=utf8;

多對多關系:一個學生可以選擇多門課程,一個課程也可以被多個學生選擇

  • 多方 ——> 學生
  • 多方 ——> 課程

2. 配置方式

<!-- 配置多對多關系 -->
<set name="courses" table="t_stu_course">
  <!-- 關聯到當前類Stu的外鍵列 -->
  <key column="stu_id"></key>
  <!-- class指定屬性的類型,column指定關系的列,外鍵列 -->
  <many-to-many class="Course" column="course_id"></many-to-many>
</set>

3. 基本操作

五、一對一關系

1. 兩種方式

  • 基於外鍵的一對一映射
  • 基於主鍵的一對一映射

2. 基於外鍵的一對一

2.1 數據庫表

create table t_card(    
    id int primary key auto_increment,
    name varchar(200)
)engine=Innodb default charset=utf8;

create table t_person(  
    id int primary key auto_increment,
    name varchar(200),
    card_id int unique, -- 通過指定unique將多對一關系變成一對一關系
    foreign key(card_id) references t_card(id)
)engine=Innodb default charset=utf8;

2.2 配置方式

<!-- 
   使用many-to-one配置一對一關聯關系,通過unique變為一對關聯關系
    name:屬性名
    column:外鍵列
    class:屬性類型
    unique:將多對一變成一對一
   -->
<many-to-one name="card" column="card_id" class="Card" unique="true"></many-to-one>
<!-- 
   使用one-to-one配置一對一關聯關系
    property-ref:引用的關聯類的屬性,使用外鍵關聯
   -->
<one-to-one name="person" class="Person" property-ref="card"></one-to-one>

2.3 基本操作

3. 基於主鍵的一對一

? 通過主鍵來指定一對一的關系

六、組件映射

1. 簡介

? 將一個對象的多個屬性封裝成單獨的另一個對象,這個封裝的對象稱為組件Component,組件不需要單獨的映射文件

? 對象關系:一個對象是另一個對象的一部分

2. 數據庫表

create table t_consumer(    
    id int primary key auto_increment,
    age int,
    first_name varchar(200),
    last_name varchar(200)
)engine=Innodb default charset=utf8;

3. 配置方式

<!-- 
   配置組件映射關系
    name:屬性名
    class:屬性類型
   -->
<component name="name" class="Name">
  <property name="firstName" column="first_name"></property>
  <property name="lastName" column="last_name"></property>
</component>

Hibernate框架技術視頻課程——筆記(三)