Hibernate 框架總結
Hibernate框架的總結
hibernate 簡介:
hibernate是一個開源框架,它是物件關聯關係對映的框架,它對JDBC做了輕量級的封裝,而我們java程式設計師可以使用面向物件的思想來操縱資料庫。
hibernate核心介面
session:負責被持久化物件CRUD操作
sessionFactory:負責初始化hibernate,建立session物件
configuration:負責配置並啟動hibernate,建立SessionFactory
Transaction:負責事物相關的操作
Query和Criteria介面:負責執行各種資料庫查詢
Hibernate 核心介面
Hibernate的核心介面一共有5個,分別為:Session、SessionFactory、Transaction、Query和Configuration。這5個核心介面在任何開發中都會用到。通過這些介面,不僅可以對持久化物件進行存取,還能夠進行事務控制。
·Session介面:Session介面負責執行被持久化物件的CRUD操作(CRUD的任務是完成與資料庫的交流,包含了很多常見的SQL語句。)。但需要注意的是Session物件是非執行緒安全的。
·SessionFactory介面:SessionFactroy介面負責初始化Hibernate。它充當資料儲存源的代理,並負責建立Session物件。
·Configuration介面:Configuration介面負責配置並啟動Hibernate,建立SessionFactory物件。在Hibernate的啟動的過程中,Configuration類的例項首先定位對映文件位置、讀取配置,然後建立SessionFactory物件。
·Transaction介面:Transaction介面負責事務相關的操作。它是可選的,可發人員也可以設計編寫自己的底層事務處理程式碼。
·Query和Criteria介面:Query和Criteria介面負責執行各種資料庫查詢。它可以使用HQL語言或SQL語句兩種表達方式。
hibernate工作原理:
1.通過Configuration config = new Configuration().configure();//讀取並解析hibernate.cfg.xml配置檔案
2.由hibernate.cfg.xml中的<mapping resource="com/xx/User.hbm.xml"/>讀取並解析對映資訊
3.通過SessionFactory sf = config.buildSessionFactory();//建立SessionFactory
4.Session session = sf.openSession();//開啟Sesssion
5.Transaction tx = session.beginTransaction();//建立並啟動事務Transation
6.persistent operate操作資料,持久化操作
7.tx.commit();//提交事務
8.關閉Session
9.關閉SesstionFactory
為什麼要用hibernate:
1. 對JDBC訪問資料庫的程式碼做了封裝,大大簡化了資料訪問層繁瑣的重複性程式碼。
2. Hibernate是一個基於JDBC的主流持久化框架,是一個優秀的ORM實現。他很大程度的簡化DAO層的編碼工作
3. hibernate使用Java反射機制,而不是位元組碼增強程式來實現透明性。
4. hibernate的效能非常好,因為它是個輕量級框架。對映的靈活性很出色。它支援各種關係資料庫,從一對一到多對多的各種複雜關係。
Hibernate是如何延遲載入?get與load的區別
1. 對於Hibernate get方法,Hibernate會確認一下該id對應的資料是否存在,首先在session快取中查詢,然後在二級快取中查詢,還沒有就查詢資料庫,資料 庫中沒有就返回null。
2. Hibernate load方法載入實體物件的時候,根據對映檔案上類級別的lazy屬性的配置(預設為true),分情況討論:
(1)若為true,則首先在Session快取中查詢,看看該id對應的物件是否存在,不存在則使用延遲載入,返回實體的代理類物件(該代理類為實體類的子類,由CGLIB動態生成)。等到具體使用該物件(除獲取OID以外)的時候,再查詢二級快取和資料庫,若仍沒發現符合條件的記錄,則會丟擲一個ObjectNotFoundException。
(2)若為false,就跟Hibernateget方法查詢順序一樣,只是最終若沒發現符合條件的記錄,則會丟擲一個ObjectNotFoundException。
get和load有兩個重要區別:
如果未能發現符合條件的記錄,Hibernate get方法返回null,而load方法會丟擲一個ObjectNotFoundException。
load方法可返回沒有載入實體資料的代 理類例項,而get方法永遠返回有實體資料的物件。
總之對於get和load的根本區別,一句話,hibernate對於 load方法認為該資料在資料庫中一定存在,可以放心的使用代理來延遲載入,如果在使用過程中發現了問題,只能拋異常;而對於get方 法,hibernate一定要獲取到真實的資料,否則返回null。
Hibernate中怎樣實現類之間的關係?(如:一對多、多對多的關係)
類與類之間的關係主要體現在表與表之間的關係進行操作,它們都是對物件進行操作,我們程式中把所有的表與類都對映在一起,它們通過配置檔案中的many-to-one、one-to-many、many-to-many、
陣列對映:<array /> 有序,通過下標訪問
<key /> 對映集合屬性資料表的外來鍵列
<list-index /> 用於對映陣列的下標列,用於儲存陣列的下標值
<element /> 對映儲存集合元素
List 集合對映:<list /> 有序,通過下標訪問
<key /> 對映集合屬性資料表的外來鍵列
<list-index /> 對映集合屬性資料表的集合索引列
<element /> 對映儲存集合元素的資料列,需要指定 type
Set 集合對映:<set /> 無序,唯一,不可重複
<key /> 對映集合屬性資料表的外來鍵列
<element /> 對映儲存集合元素的資料列,需要指定 type
Map 集合對映: <map /> key 是無序的,唯一的,value 是無序的,不唯一的
<key /> 對映集合屬性資料表的外來鍵列
<map-key /> 對映 Map 集合的 key 值,需要指定 type
<element /> 對映儲存集合元素的資料列,需要指定 type
Hibernate 中的關係對映
主鍵雙向一對一關聯: 兩個表中的主鍵共享一個值,從表中的主鍵是從主表中獲取得到
在主表對映檔案中配置:
設定主鍵生成策略:在<id>中配置
<generator class="foreign">
<param name="property>引用的主表中的從表自定義屬性名</param>
</generator>
<one-to-one name="主表中的從表自定義屬性名" constrained="true" />
在從表對映檔案中配置:
<one-to-one name="從表中的主表自定義屬性名">
外來鍵雙向一對一關聯: 通過外來鍵方式引用主表中的主鍵,並且設定外來鍵屬性為唯一屬性
在主表對映檔案中配置:
<one-to-one name="主表中的從表自定義屬性名" property-ref="從表中的主表自定義屬性名" cascade="all" />
在從表對映檔案中配置:
<many-to-one name="從表中主表自定義屬性名" column="外來鍵列名" unique="true" />
雙向一對多關聯:(以 set 為例,其餘集合同配置)
在主表對映檔案中配置:
<set name="主表中從表自定義屬性名" inverse="true">
<key column="外來鍵列名" />
<one-to-many class="從表屬性類路徑">
</set>
在從表對映檔案中配置:
<many-to-one name="從表中主表自定義屬性名" column="外來鍵列名" class="主表屬性類路徑" cascade="all" />
雙向多對多關聯:(以 set 為例)
在主表對映檔案中配置:
<set name="主表中從表自定義屬性名" table="中間表名" cascade="all">
<key column="主表在中間表的外來鍵名">
<many-to-many class="從表屬性類路徑" column="從表在中間表的外來鍵名" />
</set>
在從表對映檔案中配置:
<set name="從表中主表自定義屬性名" table="中間表名" inverse="true">
<key column="從表在中間表的外來鍵名">
<many-to-many class="主表屬性類路徑" column="主表在中間表的外來鍵名" />
</set>
Hibernate的查詢方式Sql、Criteria,object comptosition
Hql:
1、 屬性查詢
2、 引數查詢、命名引數查詢
3、 關聯查詢
4、 分頁查詢
5、 統計函式
過濾器與攔截器
使用過濾器的步驟:
① 定義過濾器,使用 <filter-def />定義過濾器(mapping的子元素)
② 使用過濾器,使用 <filter /> 應用過濾器(class的子元素)
③ 程式碼中通過 session 啟用過濾器
session.enableFilter("過濾器名").setParameter("過濾器屬性名","值");
過濾器類似於集合上的 where 屬性條件
當某個查詢條件使用的非常頻繁的時候,那麼就可以將條件設定為過濾器。
攔截器:① 實現 Interceptor 介面,重寫所有方法
② 繼承 EmptyInterceptor 類(推薦使用)
常用方法:
onLoad: 載入持久化實體時呼叫
onSave: 儲存資料的時候呼叫,資料還沒有儲存到資料庫
onFlushDirty: 更新資料時呼叫,但資料還沒有更新到資料庫
onDelete: 當刪除實體時呼叫
preFlush:持久化所做修改之前呼叫
postFlush: 持久化所做修改之後呼叫
攔截器的配置:
① 全域性攔截器配置
Configuration cfg = new Configuration().configure();
cfg.setInterceptor(配置的攔截器類);
② 區域性攔截器配置
session = factory.withOptions().interceptor(配置的攔截器類).openSession();
如何優化Hibernate?
1.使用雙向一對多關聯,不使用單向一對多
2.靈活使用單向一對多關聯
3.不用一對一,用多對一取代
4.配置物件快取,不使用集合快取
5.一對多集合使用Bag,多對多集合使用Set
6. 繼承類使用顯式多型
7. 表字段要少,表關聯不要怕多,有二級快取撐腰
hibernate的開發步驟:開發步驟
1)搭建好環境
引入hibernate最小的jar包
準備Hibernate.cfg.xml啟動配置檔案
2)寫實體類(pojo)
3)為實體類寫對映檔案"User.hbm.xml"
在hibernate.cfg.xml新增對映的實體
4)建立庫表
5)寫測試類
獲得Configuration
建立SessionFactory
開啟Session
開啟事務
使用session操作資料
提交事務
關閉資源
Hibernate 註解
注:GeneratedValue指定了識別符號的生成策略。jpa提供了4種標準用法。
01.AUTO:根據不同的資料庫選擇不同的策略
02.TABLE:使用表儲存id值
03.INDENITY:使用資料庫自動生成主鍵
04.SEQUENCE:使用序列建立主鍵(如Oracle)
雙向外來鍵一對一:@OneToOne
在主表類中 從表屬性上配置:
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="新增的外來鍵名",unique=true)
在從表類中 主表屬性上配置:
@OneToOne(mappedBy="主表中從表的自定義屬性名")
注:雙向關聯,必須設定 mappedBy 屬性 ,因為雙向關聯只能交給一方去維護,不能在兩邊都設定外來鍵關聯,否則雙方都無法儲存。
雙向主鍵一對一:
在主表類中
主表主鍵上配置:
@Id
@GeneratedValue(generator="策略名")
@GenericGenerator(name="策略名",strategy="assigned") //設定為手動輸入 方便測試
在主表中從表自定義屬性上配置:
@OneToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
在從表類中
從表主鍵上配置:
@Id
@GeneratedValue(generator="策略名")
@GenericGenerator(name="策略名",strategy="foreign",parameters={@Parameter(name="property",value="從表中主表自定義屬性名")})
在從表中主表自定義屬性上配置:
@OneToOne(mappedBy="主表中從表自定義屬性名")
雙向一對多:
在主表中從表自定義屬性上配置:
@ManyToOne
@JoinColumn(name="外來鍵名",referencedColumnName="從表中關聯的id")
在從表中主表自定義屬性上配置:
@OneToMany(mappedBy="主表中從表自定義屬性名",cascade=CascadeType.ALL)
雙向多對多:
在主表中從表自定義屬性上配置:
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable (
name="中間表名",
joinColumns={@JoinColumn(name="主表在中間表的id")},
inverseJoinColumns={@JoinColumn(name="從表在中間表的id")}
)
在從表中主表自定義屬性上配置:
@ManyToMany(mappedBy="主表中從表自定義屬性名")
注意:在判斷到底是誰維護關聯關係時,可以通過檢視外來鍵,哪個實體類定義了外來鍵,哪個類就負責維護關聯關係。
Hibernate快取的作用:
Hibernate是一個持久層框架,經常訪問物理資料庫,為了降低應用程式對物理資料來源訪問的頻次,從而提高應用程式的執行效能。快取內的資料是對物理資料來源中的資料的複製,應用程式在執行時從快取讀寫資料,在特定的時刻或事件會同步快取和物理資料來源的資料
Hibernate快取分類:
Hibernate快取包括兩大類:Hibernate一級快取和Hibernate二級快取
Hibernate一級快取又稱為“Session的快取”,它是內建的,意思就是說,只要你使用hibernate就必須使用session快取。由於Session物件的生命週期通常對應一個數據庫事務或者一個應用事務,因此它的快取是事務範圍的快取。在第一級快取中,持久化類的每個例項都具有唯一的OID。
Hibernate二級快取又稱為“SessionFactory的快取”,由於SessionFactory物件的生命週期和應用程式的整個過程對應,因此Hibernate二級快取是程序範圍或者叢集範圍的快取,有可能出現併發問題,因此需要採用適當的併發訪問策略,該策略為被快取的資料提供了事務隔離級別。第二級快取是可選的,是一個可配置的外掛,在預設情況下,SessionFactory不會啟用這個外掛。
什麼樣的資料適合存放到第二級快取中?
1 很少被修改的資料
2 不是很重要的資料,允許出現偶爾併發的資料
3 不會被併發訪問的資料
4 常量資料
不適合存放到第二級快取的資料?
1經常被修改的資料
2 .絕對不允許出現併發訪問的資料,如財務資料,絕對不允許出現併發
3 與其他應用共享的資料。
Hibernate查詢物件如何應用快取?
當Hibernate根據ID訪問資料物件的時候,首先從Session一級快取中查;查不到,如果配置了二級快取,那麼從二級快取中查;如果都查不到,再查詢資料庫,把結果按照ID放入到快取
刪除、更新、增加資料的時候,同時更新快取
Hibernate管理快取例項無論何時,我們在管理Hibernate快取(Managing the caches)時,當你給save()、update()或saveOrUpdate()方法傳遞一個物件時,或使用load()、 get()、list()、iterate() 或scroll()方法獲得一個物件時, 該物件都將被加入到Session的內部快取中。
當隨後flush()方法被呼叫時,物件的狀態會和資料庫取得同步。 如果你不希望此同步操作發生,或者你正處理大量物件、需要對有效管理記憶體時,你可以呼叫evict() 方法,從一級快取中去掉這些物件及其集合。