目錄
1. Hibernate的持久化類(lèi)狀態(tài)
- 1.1 三種持久化對(duì)象的狀態(tài)
- 1.2 區(qū)分三種持久化對(duì)象的狀態(tài)
- 1.3 三種狀態(tài)對(duì)象轉(zhuǎn)換
- 1.4 持久態(tài)對(duì)象有自動(dòng)更新數(shù)據(jù)庫(kù)的能力
2. Hibernate的一級(jí)緩存:(重要)
- 2.1 一級(jí)緩存快照區(qū)
- 2.2 Hibernate管理一級(jí)緩存
3. 操作持久化對(duì)象的方法
4. Hibernate關(guān)聯(lián)關(guān)系的映射
- 4.1 實(shí)體之間的關(guān)系
- 4.2 Hibernate中一對(duì)多的配置
- 4.3 Hibernate中級(jí)聯(lián)保存的效果
- 4.4 Hibernate中級(jí)聯(lián)刪除的效果
- 4.5 Hibernate中的級(jí)聯(lián)取值
- 4.6 雙向維護(hù)產(chǎn)生多余的SQL
- 4.7 Hibernate的多對(duì)多的配置
Hibernate的持久化類(lèi)狀態(tài)
持久化類(lèi):就是一個(gè)實(shí)體類(lèi)與數(shù)據(jù)庫(kù)表建立了映射.
Hibernate為了方便管理持久化類(lèi),將持久化類(lèi)分成了三種狀態(tài).
- 瞬時(shí)態(tài) transient
- 持久態(tài) persistent
- 脫管態(tài) detached
三種持久化對(duì)象的狀態(tài)
- Transient瞬時(shí)態(tài)
特點(diǎn):持久化對(duì)象沒(méi)有唯一標(biāo)識(shí)OID.沒(méi)有納入Session的管理. - Persistent持久態(tài):
特點(diǎn):持久化對(duì)象有唯一標(biāo)識(shí)OID.已經(jīng)納入到Session的管理.
結(jié)論:持久化持久態(tài)對(duì)象有自動(dòng)更新數(shù)據(jù)庫(kù)的能力. - Detached脫管態(tài):
特點(diǎn):持久化對(duì)象有唯一標(biāo)識(shí)OID,沒(méi)有納入到Session管理.
區(qū)分三種持久化對(duì)象的狀態(tài)
@Test
// 區(qū)分持久化對(duì)象的三種狀態(tài):
public void demo1(){
// 1.創(chuàng)建Session
Session session = HibernateUtils.openSession();
// 2.開(kāi)啟事務(wù)
Transaction tx = session.beginTransaction();
// 向數(shù)據(jù)庫(kù)中保存一本圖書(shū):
Book book = new Book(); // 瞬時(shí)態(tài):沒(méi)有唯一標(biāo)識(shí)OID,沒(méi)有與session關(guān)聯(lián).
book.setName("Hiernate開(kāi)發(fā)");
book.setAuthor("孫XX");
book.setPrice(65d);
session.save(book); // 持久態(tài):有唯一標(biāo)識(shí)OID,與session關(guān)聯(lián).
// 3.事務(wù)提交
tx.commit();
// 4.釋放資源
session.close();
book.setName("Struts2開(kāi)發(fā)"); // 脫管態(tài):有唯一的標(biāo)識(shí),沒(méi)有與session關(guān)聯(lián).
}
三種狀態(tài)對(duì)象轉(zhuǎn)換
瞬時(shí)態(tài)
獲得:Book book = new Book();
瞬時(shí)--->持久
save(book);
save()/saveOrUpdate();
瞬時(shí)--->脫管
book.setId(1);持久態(tài)
獲得:Book book = (Book)session.get(Book.class,1);get()/load()/find()/iterate();
持久--->瞬時(shí):
delete(book);
特殊狀態(tài):刪除態(tài).(被刪除的對(duì)象,不建議去使用.)
持久--->脫管:
session.close();
close()/clear()/evict();脫管態(tài)
獲得:Book book = new Book();book.setId(1);
脫管--->持久:
session.update();
update()/saveOrUpdate()/lock()
脫管--->瞬時(shí):
book.setId(null);
持久態(tài)對(duì)象有自動(dòng)更新數(shù)據(jù)庫(kù)的能力
@Test
// 測(cè)試持久態(tài)的對(duì)象自動(dòng)更新數(shù)據(jù)庫(kù)
public void demo2(){
// 1.創(chuàng)建Session
Session session = HibernateUtils.openSession();
// 2.開(kāi)啟事務(wù)
Transaction tx = session.beginTransaction();
// 獲得一個(gè)持久態(tài)的對(duì)象.
Book book = (Book) session.get(Book.class, 1);
book.setName("Struts2開(kāi)發(fā)");
// session.update(book); 不需要使用update方法更新
// 3.提交事務(wù)
tx.commit();
// 4.關(guān)閉資源
session.close();
}
自動(dòng)更新數(shù)據(jù)庫(kù)的能力依賴了Hibernate的一級(jí)緩存
Hibernate的一級(jí)緩存:(重要)
什么是緩存
緩存將數(shù)據(jù)庫(kù)/硬盤(pán)上文件中數(shù)據(jù),放入到緩存中(就是內(nèi)存中一塊空間).當(dāng)再次使用的使用,可以直接從內(nèi)存中獲取.
緩存的好處
提升程序運(yùn)行的效率.緩存技術(shù)是Hibernate的一個(gè)優(yōu)化的手段.
Hibernate分成兩個(gè)基本的緩存
- 一級(jí)緩存:Session級(jí)別的緩存.一級(jí)緩存與session的生命周期一致.自帶的.不可卸載.
- 二級(jí)緩存:SessionFactory級(jí)別的緩存.不是自帶的.
在 Session 接口的實(shí)現(xiàn)中包含一系列的 Java 集合, 這些 Java 集合構(gòu)成了 Session 緩存. 只要 Session 實(shí)例沒(méi)有結(jié)束生命周期, 存放在它緩存中的對(duì)象也不會(huì)結(jié)束生命周期
一級(jí)緩存快照區(qū)
@Test
// 深入理解一級(jí)緩存結(jié)構(gòu):快照區(qū):
public void demo4(){
// 1.創(chuàng)建Session
Session session = HibernateUtils.openSession();
// 2.開(kāi)啟事務(wù)
Transaction tx = session.beginTransaction();
// 獲得一個(gè)持久態(tài)的對(duì)象.
Book book = (Book) session.get(Book.class, 1);
book.setName("Spring3開(kāi)發(fā)");
// 3.提交事務(wù)
tx.commit();
// 4.關(guān)閉資源
session.close();
}
結(jié)論:向一級(jí)緩存存入數(shù)據(jù)的時(shí)候,放入一級(jí)緩存區(qū)和一級(jí)緩存快照區(qū),當(dāng)更新了一級(jí)緩存的數(shù)據(jù)的時(shí)候,事務(wù)一旦提交,比對(duì)一級(jí)緩存和快照區(qū),如果數(shù)據(jù)一致,不更新,如果數(shù)據(jù)不一致,自動(dòng)更新數(shù)據(jù)庫(kù).
Hibernate管理一級(jí)緩存
一級(jí)緩存是與session的生命周期相關(guān)的.session生命周期結(jié)束,一級(jí)緩存銷(xiāo)毀了.
- clear()/evict()/flush()/refresh()管理一級(jí)緩存.
- clear() :清空一級(jí)緩存中所有的對(duì)象.
- evict(Object obj) :清空一級(jí)緩存中某個(gè)對(duì)象.
- flush() :刷出緩存.
- refresh(Object obj):將快照區(qū)的數(shù)據(jù)重新覆蓋了一級(jí)緩存的數(shù)據(jù).
操作持久化對(duì)象的方法
- save():保存一條記錄:將瞬時(shí)態(tài)對(duì)象轉(zhuǎn)成持久態(tài)對(duì)象.
- update()更新一條記錄:將脫管態(tài)對(duì)象轉(zhuǎn)成持久態(tài)對(duì)象.
在<class>標(biāo)簽上設(shè)置select-before-update="true"在更新之前先去查詢 - saveOrUpdate():
根據(jù)對(duì)象狀態(tài)的不同執(zhí)行不同的save獲得update方法. - 如果對(duì)象是一個(gè)瞬時(shí)態(tài)對(duì)象:執(zhí)行save操作.
- 如果對(duì)象是一個(gè)脫管態(tài)對(duì)象:執(zhí)行update操作.
- 設(shè)置id不存在,就會(huì)報(bào)錯(cuò),可以在<id>上設(shè)置一個(gè)unsaved-value=”-1”,執(zhí)行保存的操作.
- delete():將持久態(tài)對(duì)象轉(zhuǎn)成瞬時(shí)態(tài).
- get()/load():獲得一個(gè)持久態(tài)對(duì)象.
Hibernate關(guān)聯(lián)關(guān)系的映射
實(shí)體之間的關(guān)系
實(shí)體之間有三種關(guān)系:
- 一對(duì)多:
一個(gè)用戶,生成多個(gè)訂單,每一個(gè)訂單只能屬于一個(gè)用戶.
建表原則:在多的一方創(chuàng)建一個(gè)字段,作為外鍵,指向一的一方的主鍵. - 多對(duì)多:
一個(gè)學(xué)生可以選擇多門(mén)課程,一個(gè)課程可以被多個(gè)學(xué)生選擇.
建表原則:創(chuàng)建第三張表,中間表至少有兩個(gè)字段,分別作為外鍵指向多對(duì)多雙方主鍵. - 一對(duì)一:(特殊.最少.)
一個(gè)公司只能有一個(gè)注冊(cè)地址,一個(gè)注冊(cè)地址,只能被一個(gè)公司使用.(否則將兩個(gè)表建到一個(gè)表.)
建表原則: - 唯一外鍵:一對(duì)一的雙方,假設(shè)一方是多的關(guān)系.需要在多的一方創(chuàng)建一個(gè)字段,作為外鍵.指向一的一方的主鍵.但是在外鍵添加一個(gè)unique.
- 主鍵對(duì)應(yīng):一對(duì)一的雙方,通過(guò)主鍵進(jìn)行關(guān)聯(lián).
Hibernate中一對(duì)多的配置
第一步:創(chuàng)建兩個(gè)實(shí)體:
- 客戶實(shí)體:
public class Customer {
private Integer cid;
private String cname;
// 一個(gè)客戶有多個(gè)訂單.
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;
}
}
- 訂單實(shí)體:
public class Order {
private Integer oid;
private String addr;
// 訂單屬于某一個(gè)客戶.放置一個(gè)客戶的對(duì)象.
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">
<!-- 配置唯一標(biāo)識(shí) -->
<id name="cid" column="cid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="cname" column="cname" length="20"/>
<!-- 建立映射 -->
<!-- 配置一個(gè)集合 <set>的name Customer對(duì)象中的關(guān)聯(lián)對(duì)象的屬性名稱. -->
<set name="orders">
<!-- <key>標(biāo)簽中column:用來(lái)描述一對(duì)多多的一方的外鍵的名稱. -->
<key column="cno"></key>
<!-- 配置一個(gè)<one-to-many>標(biāo)簽中class屬性:訂單的類(lèi)的全路徑 -->
<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">
<!-- 配置唯一標(biāo)識(shí) -->
<id name="oid" column="oid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="addr" column="addr" length="50"/>
<!-- 配置映射 -->
<!--
<many-to-one>標(biāo)簽
name :關(guān)聯(lián)對(duì)象的屬性的名稱.
column :表中的外鍵名稱.
class :關(guān)聯(lián)對(duì)象類(lèi)的全路徑
-->
<many-to-one name="customer" column="cno" class="cn.itcast.hibernate3.demo2.Customer"/>
</class>
</hibernate-mapping>
第三步:將映射放到核心配置文件中.
Hibernate中級(jí)聯(lián)保存的效果
級(jí)聯(lián):操作當(dāng)前對(duì)象的時(shí)候,關(guān)聯(lián)的對(duì)象如何處理.
cascade=”save-update”
級(jí)聯(lián)方向性
- 保存客戶的時(shí)候,選擇級(jí)聯(lián)訂單.
- 保存訂單的時(shí)候,選擇級(jí)聯(lián)客戶.
Hibernate中級(jí)聯(lián)刪除的效果
cascade=”delete”
Hibernate中的級(jí)聯(lián)取值
none :不使用級(jí)聯(lián)
dave-update :保存或更新的時(shí)候級(jí)聯(lián)
delete :刪除的時(shí)候級(jí)聯(lián)
all :除了孤兒刪除以外的所有級(jí)聯(lián).
delete-orphan :孤兒刪除(孤子刪除).
- 僅限于一對(duì)多.只有一對(duì)多時(shí)候,才有父子存在.認(rèn)為一的一方是父親,多的一方是子方.
- 當(dāng)一個(gè)客戶與某個(gè)訂單解除了關(guān)系.將外鍵置為null.訂單沒(méi)有了所屬客戶,相當(dāng)于一個(gè)孩子沒(méi)有了父親.將這種記錄就刪除了.
all-delete-orphan:包含了孤兒刪除的所有的級(jí)聯(lián).
雙向維護(hù)產(chǎn)生多余的SQL
配置inverse=”true”:在那一端配置.那么那一端放棄了外鍵的維護(hù)權(quán).一般情況下,一的一方去放棄.
cascade:操作關(guān)聯(lián)對(duì)象.
inverse:控制外鍵的維護(hù).
Hibernate的多對(duì)多的配置
第一步:創(chuàng)建實(shí)體類(lèi):
學(xué)生的實(shí)體:
public class Student {
private Integer sid;
private String sname;
// 一個(gè)學(xué)生選擇多門(mén)課程:
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;
}
}
課程的實(shí)體:
public class Course {
private Integer cid;
private String cname;
// 一個(gè)課程被多個(gè)學(xué)生選擇:
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">
<!-- 配置唯一標(biāo)識(shí) -->
<id name="sid" column="sid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="sname" column="sname" length="20"/>
<!-- 配置關(guān)聯(lián)映射 -->
<!-- <set>標(biāo)簽 name:對(duì)應(yīng)學(xué)生中的課程集合的名稱 table:中間表名稱. -->
<set name="courses" table="stu_cour">
<!-- <key>中column寫(xiě) 當(dāng)前類(lèi)在中間表的外鍵.-->
<key column="sno"></key>
<!-- <many-to-many>中class:另一方類(lèi)的全路徑. 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">
<!-- 配置唯一標(biāo)識(shí) -->
<id name="cid" column="cid">
<generator class="native"/>
</id>
<!-- 配置普通屬性 -->
<property name="cname" column="cname" length="20"/>
<!-- 配置與學(xué)生關(guān)聯(lián)映射 -->
<!-- <set>中name:對(duì)應(yīng)當(dāng)前類(lèi)中的學(xué)生的集合的名稱 table:中間表的名稱-->
<set name="students" table="stu_cour">
<!-- <key>中column:當(dāng)前類(lèi)在中間表中外鍵 -->
<key column="cno"></key>
<!-- <many-to-many>中class:另一方的類(lèi)全路徑. column:另一方在中間表中外鍵名稱 -->
<many-to-many class="cn.itcast.hibernate3.demo3.Student" column="sno"/>
</set>
</class>
</hibernate-mapping>
第三步:將映射文件加入到核心配置文件中: