Hibernate_day02總結
今日內容
l Hibernate持久化對象的狀態
l Hibernate的一級緩存
l Hibernate操作持久化對象的方法
l Hibernate 關聯關係映射
1.1 上次課內容回顧
Hibernate:
* 第一天環境搭建,開發流程,配置和API
* 第二天Hibernate持久化對象的狀態,一級緩存,關聯關係映射.
* 第三天Hibernate的檢索方式 抓取策略 二級緩存.
* 第四天Hibernate練習:
1.Hibernate框架的概述:
* 就是一個持久層的ORM框架.
* ORM:對象關係映射.將Java中實體對象與關係型數據庫中表建立一種關係.Hibernate中可以通過操作對象的方式,從而操作數據庫的表.
* 常見的持久層框架:
* Hibernate
* MyBatis
* JPA
* DBUtils
* Hibernate3.x和Hibernate4.x
2.Hibernate快速入門:
2.1下載Hibernate開發包.
2.2Hibernate開發包目錄結構:
* 文檔:
* 開發包:
* 操作字節碼:
* 必須的
* 可選的
* jpa
* 項目:
2.3創建一個java項目 導入相應jar包.
2.4創建數據庫表:
2.5創建一個實體類:
2.6建立映射:
2.7創建Hibernate核心配置文件:
2.8編寫一個測試類:
3.Hibenrate的CRUD的操作:
* save();
* update();
* delete();
* get()/load();
* 區別:
* get:採用是立即檢索,馬上發送SQL查詢.返回的是真實對象.檢索一個找不到的對象的時候NullPointException
* load:採用延遲加載技術,當真正使用這個對象的時候,纔會發送SQL.返回代理對象.檢索一個找不到的對象的時候ObjectNotFoundException
4.Hibernate的常見配置及API:
* 4.1核心配置:
* 兩種方式;
* 屬性文件的方式:
* 在src下創建一個hibernate.properties.
***** 手動加載映射文件.
* XML格式的配置:
* 在src下創建一個hibernate.cfg.xml
* 必須的配置:
* 數據庫連接信息.
* Hibernate的方言.
* 可選配置:
* 顯示SQL
* 格式化SQL
* hbm2ddl.auto
* create/create-drop/update/validate
* 映射文件:
* <mapping resource=””/>
* 4.2映射配置:
* <class>建立類與表映射
* name:類的全路徑
* table:表名稱
* <id>
* name
* column
* type
* length
* <property>
* name
* column
* type
* length
5.Hibernate的API
* Configuration:管理配置信息.
* 屬性文件:
* 直接創建.
* XML
* new Configuration().configure();
* SessionFactory:
* 維護二級緩存,線程安全的對象.
* 抽取工具類.
* Session:
* 維護一級緩存,線程不安全的對象.
* Transaction:
***** 事務是默認不自動提交,手動提交事務.
* Query:
* Criteria:
6.持久化類編寫:
* 持久化類:就是一個實體類 + XML映射.
* 編寫原則:
* 無參數構造:
* 屬性提供set/get方法
* 提供爲一個標識:
* 儘量使用包裝類型:
* 這個類儘量不要使用final修飾.
* 自然主鍵和代理主鍵:
* Hibernate提供主鍵生成策略:
* increment:
* identity:
* sequence:
* uuid:
* native:
* assgined:
1.2 Hibernate的持久化類狀態:
1.2.1 Hibernate的持久化類狀態
持久化類:就是一個實體類 與 數據庫表建立了映射.
* Hibernate爲了方便管理持久化類,將持久化類分成了三種狀態.
瞬時態 transient:(臨時態)
持久態 persistent:
脫管態 detached:(離線態)
1.2.2 三種持久化對象的狀態:
Transient瞬時態:
特點:持久化對象沒有唯一標識OID.沒有納入Session的管理.
Persistent持久態:
特點:持久化對象有唯一標識OID.已經納入到Session的管理.
***** 結論:持久化持久態對象有自動更新數據庫的能力.
Detached脫管態:
特點:持久化對象有唯一標識OID,沒有納入到Session管理.
1.2.3 區分三種持久化對象的狀態:
@Test
// 區分持久化對象的三種狀態:
public void demo1(){
// 1.創建Session
Session session = HibernateUtils.openSession();
// 2.開啓事務
Transaction tx = session.beginTransaction();
// 向數據庫中保存一本圖書:
Book book = new Book();// 瞬時態:沒有唯一標識OID,沒有與session關聯.
book.setName("Hiernate開發");
book.setAuthor("孫XX");
book.setPrice(65d);
session.save(book); // 持久態:有唯一標識OID,與session關聯.
// 3.事務提交
tx.commit();
// 4.釋放資源
session.close();
book.setName("Struts2開發"); // 脫管態:有唯一的標識,沒有與session關聯.
}
1.2.4 三種狀態對象轉換:
瞬時態:
獲得:
Book book = new Book();
瞬時--->持久
* save(book);
* save()/saveOrUpdate();
瞬時--->脫管
* book.setId(1);
持久態:
獲得:
Book book = (Book)session.get(Book.class,1);
* get()/load()/find()/iterate();
持久--->瞬時:
* delete(book);
* 特殊狀態:刪除態.(被刪除的對象,不建議去使用.)
持久--->脫管:
* session.close();
* close()/clear()/evict();
脫管態:
獲得:
Book book = new Book();
book.setId(1);
脫管--->持久:
* session.update();
* update()/saveOrUpdate()/lock()
脫管--->瞬時:
* book.setId(null);
1.2.5 持久態對象有自動更新數據庫的能力;
@Test
// 測試持久態的對象自動更新數據庫
public void demo2(){
// 1.創建Session
Session session = HibernateUtils.openSession();
// 2.開啓事務
Transaction tx = session.beginTransaction();
// 獲得一個持久態的對象.
Book book = (Book) session.get(Book.class, 1);
book.setName("Struts2開發");
// session.update(book);
// 3.提交事務
tx.commit();
// 4.關閉資源
session.close();
}
****** 自動更新數據庫的能力依賴了Hibernate的一級緩存.
1.3 Hibernate的一級緩存:(重要)
1.3.1 Hibernate的一級緩存:
什麼是緩存:
* 緩存將數據庫/硬盤上文件中數據,放入到緩存中(就是內存中一塊空間).當再次使用的使用,可以直接從內存中獲取.
緩存的好處:
* 提升程序運行的效率.緩存技術是Hibernate的一個優化的手段.
Hibernate分成兩個基本的緩存:
* 一級緩存:Session級別的緩存.一級緩存與session的生命週期一致.自帶的.不可卸載.
* 二級緩存:SessionFactory級別的緩存.不是自帶的.
在 Session 接口的實現中包含一系列的 Java 集合, 這些 Java 集合構成了 Session 緩存. 只要 Session 實例沒有結束生命週期, 存放在它緩存中的對象也不會結束生命週期.
1.3.2 證明Hibernate的一級緩存的存在:
@Test
// 證明一級緩存的存在
public void demo3(){
// 1.創建Session
Session session = HibernateUtils.openSession();
// 2.開啓事務
Transaction tx = session.beginTransaction();
// save方法可以向一級緩存中存放數據的.
/*Book book = new Book();
book.setName("JQuery開發");
book.setAuthor("張XX");
book.setPrice(45d);
Integer id = (Integer) session.save(book);
Book book2 = (Book) session.get(Book.class, id);
System.out.println(book2);*/
// 分別用get執行兩次查詢.
Book book1 = (Book) session.get(Book.class, 1);// 馬上發生SQL去查詢
System.out.println(book1);
Book book2 = (Book) session.get(Book.class, 1);// 不發生SQL,因爲使用一級緩存的數據
System.out.println(book2);
// 3.提交事務
tx.commit();
// 4.關閉資源
session.close();
}
1.3.3 深入理解一級緩存中快照區:
@Test
// 深入理解一級緩存結構:快照區:
public void demo4(){
// 1.創建Session
Session session = HibernateUtils.openSession();
// 2.開啓事務
Transaction tx = session.beginTransaction();
// 獲得一個持久態的對象.
Book book = (Book) session.get(Book.class, 1);
book.setName("Spring3開發");
// 3.提交事務
tx.commit();
// 4.關閉資源
session.close();
}
結論:向一級緩存存入數據的時候,放入一級緩存區和一級緩存快照區,當更新了一級緩存的數據的時候,事務一旦提交,比對一級緩存和快照區,如果數據一致,不更新,如果數據不一致,自動更新數據庫.
1.3.4 Hibernate管理一級緩存:
一級緩存是與session的生命週期相關的.session生命週期結束,一級緩存銷燬了.
* clear()/evict()/flush()/refresh()管理一級緩存.
* clear():清空一級緩存中所有的對象.
* evict(Object obj):清空一級緩存中某個對象.
* flush():刷出緩存.
* refresh(Object obj):將快照區的數據重新覆蓋了一級緩存的數據.
1.3.5 Hibernate一級緩存的刷出時機:(瞭解.)
FlushMode:
* 常量:
* ALWAYS:每次查詢的時候都會刷出.手動調用flush.事務提交的時候.
* AUTO:默認值.有些查詢會刷出.手動調用flush.事務提交的時候.
* COMMIT:在事務提交的時候,手動調用flush的時候.
* MANUAL:只有在手動調用flush纔會刷出.
嚴格程度:MANUAL > COMMIT > AUTO > ALWAYS
1.4 操作持久化對象的方法:
save():
保存一條記錄:將瞬時態對象轉成持久態對象.
update()
更新一條記錄:將脫管態對象轉成持久態對象.
在<class>標籤上設置select-before-update="true"在更新之前先去查詢
saveOrUpdate():
根據對象狀態的不同執行不同的save獲得update方法.
* 如果對象是一個瞬時態對象:執行save操作.
* 如果對象是一個脫管態對象:執行update操作.
* 設置id不存在,就會報錯,可以在<id>上設置一個unsaved-value=”-1”,執行保存的操作.
delete():
將持久態對象轉成瞬時態.
get()/load():
獲得一個持久態對象.
1.5 Hibernate關聯關係的映射:
1.5.1 實體之間的關係:
實體之間有三種關係:
* 一對多:
* 一個用戶,生成多個訂單,每一個訂單隻能屬於一個用戶.
* 建表原則:
* 在多的一方創建一個字段,作爲外鍵,指向一的一方的主鍵.
* 多對多:
* 一個學生可以選擇多門課程,一個課程可以被多個學生選擇.
* 建表原則:
* 創建第三張表,中間表至少有兩個字段,分別作爲外鍵指向多對多雙方主鍵.
* 一對一:(特殊.最少.)
* 一個公司只能有一個註冊地址,一個註冊地址,只能被一個公司使用.(否則將兩個表建到一個表.)
* 建表原則:
* 唯一外鍵:
* 一對一的雙方,假設一方是多的關係.需要在多的一方創建一個字段,作爲外鍵.指向一的一方的主鍵.但是在外鍵添加一個unique.
* 主鍵對應:
* 一對一的雙方,通過主鍵進行關聯.
1.5.2 Hibernate中一對多的配置:(*****)
第一步:
* 創建兩個實體:
* 客戶實體:
public class Customer {
private Integer cid;
private String cname;
// 一個客戶有多個訂單.
private Set<Order> orders = new HashSet<Order>();
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
* 訂單實體:
public class Order {
private Integer oid;
private String addr;
// 訂單屬於某一個客戶.放置一個客戶的對象.
private Customer customer;
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
第二步:建立映射:
Customer.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.hibernate3.demo2.Customer" table="customer">
<!-- 配置唯一標識 -->
<id name="cid" column="cid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="cname" column="cname" length="20"/>
<!-- 建立映射 -->
<!-- 配置一個集合 <set>的name Customer對象中的關聯對象的屬性名稱. -->
<set name="orders">
<!-- <key>標籤中column:用來描述一對多多的一方的外鍵的名稱. -->
<key column="cno"></key>
<!-- 配置一個<one-to-many>標籤中class屬性:訂單的類的全路徑 -->
<one-to-many class="cn.itcast.hibernate3.demo2.Order"/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.hibernate3.demo2.Order" table="orders">
<!-- 配置唯一標識 -->
<id name="oid" column="oid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="addr" column="addr" length="50"/>
<!-- 配置映射 -->
<!--
<many-to-one>標籤
name :關聯對象的屬性的名稱.
column:表中的外鍵名稱.
class:關聯對象類的全路徑
-->
<many-to-one name="customer" column="cno" class="cn.itcast.hibernate3.demo2.Customer"/>
</class>
</hibernate-mapping>
第三步:將映射放到核心配置文件中.
1.5.3 Hibernate中級聯保存的效果:
級聯:操作當前對象的時候,關聯的對象如何處理.
cascade=”save-update”
級聯方向性:
* 保存客戶的時候,選擇級聯訂單.
* 保存訂單的時候,選擇級聯客戶.
1.5.4 Hibernate中級聯刪除的效果:
cascade=”delete”
1.5.5 Hibernate中的級聯取值:
none:不使用級聯
dave-update:保存或更新的時候級聯
delete:刪除的時候級聯
all:除了孤兒刪除以外的所有級聯.
delete-orphan:孤兒刪除(孤子刪除).
* 僅限於一對多.只有一對多時候,纔有父子存在.認爲一的一方是父親,多的一方是子方.
* 當一個客戶與某個訂單解除了關係.將外鍵置爲null.訂單沒有了所屬客戶,相當於一個孩子沒有了父親.將這種記錄就刪除了.
all-delete-orphan:包含了孤兒刪除的所有的級聯.
1.5.6 雙向維護產生多餘的SQL:
配置inverse=”true”:在那一端配置.那麼那一端放棄了外鍵的維護權.
* 一般情況下,一的一方去放棄.
cascade:操作關聯對象.
inverse:控制外鍵的維護.
1.5.7 Hibernate的多對多的配置:
第一步:創建實體類:
學生的實體:
public class Student {
private Integer sid;
private String sname;
// 一個學生選擇多門課程:
private Set<Course> courses = new HashSet<Course>();
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
}
課程的實體:
public class Course {
private Integer cid;
private String cname;
// 一個課程被多個學生選擇:
private Set<Student> students = new HashSet<Student>();
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
第二步建立映射:
Student.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.hibernate3.demo3.Student" table="student">
<!-- 配置唯一標識 -->
<id name="sid" column="sid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="sname" column="sname" length="20"/>
<!-- 配置關聯映射 -->
<!-- <set>標籤 name:對應學生中的課程集合的名稱 table:中間表名稱. -->
<set name="courses" table="stu_cour">
<!-- <key>中column寫 當前類在中間表的外鍵.-->
<key column="sno"></key>
<!-- <many-to-many>中class:另一方類的全路徑. column:另一方在中間表中外鍵名稱-->
<many-to-many class="cn.itcast.hibernate3.demo3.Course" column="cno"/>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.hibernate3.demo3.Course" table="course">
<!-- 配置唯一標識 -->
<id name="cid" column="cid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="cname" column="cname" length="20"/>
<!-- 配置與學生關聯映射 -->
<!-- <set>中name:對應當前類中的學生的集合的名稱 table:中間表的名稱-->
<set name="students" table="stu_cour">
<!-- <key>中column:當前類在中間表中外鍵 -->
<key column="cno"></key>
<!-- <many-to-many>中class:另一方的類全路徑. column:另一方在中間表中外鍵名稱 -->
<many-to-many class="cn.itcast.hibernate3.demo3.Student" column="sno"/>
</set>
</class>
</hibernate-mapping>
第三步:將映射文件加入到核心配置文件中:
今天的內容總結:
Hibernate持久化對象的狀態:
* 瞬時態:
* 持久態:
* 脫管態:
* 狀態之間的轉換:
Hibernate一級緩存:
* Hibernate的一級緩存的存在.
* get/load/save
* Hibernate的一級緩存的結構:
* 快照區.
* Hibernate一級緩存的管理:
* clear()/evict()/flush()/refresh();
* 刷出時機(瞭解)
Hibernate操作持久化對象常用方法:
* save();
* update();
* saveOrUpdate();
* 瞬時:執行save
* 脫管:執行update
* delete();
* get()/load();直接獲得持久對象.
Hibernate的關聯關係:(*****)
* 一對多的配置:(手動配置)
* 級聯.
* 多對多的配置:(手動配置)
* 級聯:
***********************************************************************************************************************************************************************
Hibernate的一級緩存的快照區
實體之間的關係
Hibernate的雙向維護產生多餘的SQL語句