這段時間本人利用空閒時間解讀了一下Hibernate3的源碼,饒有收穫,願與你們共享。 sql
廢話很少說,首先咱們先對Hibernate有一個大體的印象 數據庫
l 設計模式Hibernate=監聽器,其實是回調 編程
l Hibernate3支持攔截器 設計模式
Hibernate配置方面的大原則: 數組
l bhn.xml文件全部配置都是描述本實體,除了cascade描述級聯,即如何將本實體的操做(增刪查改)傳遞給關聯方。 緩存
l inverse屬性表示本實體是否擁有主動權,在一條cascade鏈路傳遞過程當中,當出現inverse=false表示再也不返回原cascade鏈路,而是今後處從新開始鏈路。inverse只有在非many方纔有,也就是many-to-many或者one-to-many的set,List等。
下面是註明inverse=true與inverse=false的cascade鏈路的區別: session
說明:若關聯屬性inverse=true,操做的結果將是校對A的屬性所生成的sql;若關聯屬性inverse=false,結果將是丟棄先前A的操做,而轉向對B的屬性的校驗所生成的sql;若是B中的屬性也關聯着inverse=false,則仍丟棄B繼續新開啓鏈路,直至沒有關聯方爲inervse=false。沒必要擔憂,關聯着的雙方只有一方擁有inverse屬性,因此不會一直傳遞下去。還有,丟棄了先前的操做不等於以前的對象操做無效,其效果至關於,原先的session.save(A),變成了session(A.B)而在B校對屬性時總會找回A對象的。 測試
測試用例:(暫不考慮inverse=false) ui
測試1:save()一個實體對象操做,預計insert發生在擁有外鍵方的表,擁有外鍵方的表是一對多中的多方。 this
結論1:若是實體對象的外鍵屬性爲null,表示不會產生關聯,可直接生成sql;若是外鍵屬性不爲空,根據配置中的cascade去作關聯。若是cascade=all則生成此表的insert和關聯表update的sql,也就是說此時要求關聯屬性的主鍵id不能爲null;若是cascade=save-update則生成此表的insert和關聯表的insert/update的sql(關鍵屬性的主鍵爲null爲insert,不然爲update)。
見下圖:
舉例說明:
---------PO類:A中有B類型的關聯屬性
class A{
private int id;
private B b;
}
class B{
private int id;
private String str;
}
---------調用處關鍵代碼:
A a=new A();//待操做的實體對象
B b=new B();//關聯屬性
a.setB(b);//設置關聯屬性
//----
//a.setId(1);//save()操做不容許預約一個id,hibernate的Id必須使用配置中的方式生成
//a.setB(null);//關聯屬性爲null
//----
b.setId(1);/*關聯屬性的主鍵有值。只有cascade鏈在B對象校驗爲update操做纔有效,也就是說A.bhn.xml中B
*的級聯設爲cascade=save-update。*/
b.setId(null);/*關聯屬性的主鍵爲null。支持cascade=all與cascade=save-update的操做,最終在B生成的
* 是insert操做*/
//--------
b.setStr("當前用於測試");//------數據項
//-------操做
session.save(a);
源碼解讀:(粗略)
Hibernate主要是事件監聽模式(回調的一種實現),其核心類爲Session類,Session類承載了CRUS操做和Commit操做。
補充知識點:回調的好處在於事件源對象eventSource和數據對象Object,被集中在監聽器Listener裏完成業務,集中的好處在於新寫Listener就能夠達到功能的擴展。Listener的處理方法的參數爲,事件對象eventObject,事件對象包含事件源eventSource和數據對象,至關於Listener傳的是兩個參數,也就是說Listener獲得了此數據模型中的全部數據,天然能夠完成任何功能,其他部分在模型中可理解爲僅是爲了給Listener傳參作準備。一般的運行流程是事件源先被調用方法,因此事件源的方法裏完成了業務功能,所謂回調就是形式上仍是調用了事件源的方法,可是業務功能的代碼卻在第三方的Listener類中完成,而事件源的方法裏只是爲了實現如何傳參給Listener。這樣就像是與傳統編程相反由Listener去調用事件源。
案例1:Session的S查詢操做
過程略:
小結:Hibernate的Select操做直接生成sql,固然經過了內存緩存才生成的sql。
案例2:Session調用CRU操做(非S操做,增刪改)。
以Save()操做爲例
步驟1. SessionImpl.save(obj); SessionImpl.save(null,obj);--從save(Object,Object)統一調用
步驟2. new SaveOrUpdateEvent(entityName, object, this)—建立並組裝事件對象(用於Listener的參數)
步驟3. SessionImpl.fireSave(SaveOrUpdateEvent);--觸發事件,即調用Listener的處理方法,目的在於傳參步驟2中new出的SaveOrUpdateEvent事件對象。
代碼以下:
private Serializable fireSave(SaveOrUpdateEvent event) {
errorIfClosed();
checkTransactionSynchStatus();
SaveOrUpdateEventListener[] saveEventListener = listeners.getSaveEventListeners();
for ( int i = 0; i < saveEventListener.length; i++ ) {
saveEventListener[i].onSaveOrUpdate(event);
}
return event.getResultId();
}
紅色爲關鍵代碼,其中listeners爲Session的EventListeners屬性。
EventListeners包含有一系列的監聽器,而各類監聽器以數組的形式容許有多個而且按順序調用。本例中調用的監聽器種類爲saveOrUpdateEventListeners,處理方法爲onSaveOrUpdate()方法。實現onSaveOrUpdate(event)的類是DefaultSaveOrUpdateEventListener。因此業務實現代碼應該在DefaultSaveOrUpdateEventListener.onSaveOrUpdate()中
EventListeners類中的一系列Listener []屬性:
private LoadEventListener[] loadEventListeners = { new DefaultLoadEventListener() };
private SaveOrUpdateEventListener[] saveOrUpdateEventListeners = { new DefaultSaveOrUpdateEventListener() };
private MergeEventListener[] mergeEventListeners = { new DefaultMergeEventListener() };
private PersistEventListener[] persistEventListeners = { new DefaultPersistEventListener() };
private PersistEventListener[] persistOnFlushEventListeners = { new DefaultPersistOnFlushEventListener() };
private ReplicateEventListener[] replicateEventListeners = { new DefaultReplicateEventListener() };
private DeleteEventListener[] deleteEventListeners = { new DefaultDeleteEventListener() };
private AutoFlushEventListener[] autoFlushEventListeners = { new DefaultAutoFlushEventListener() };
private DirtyCheckEventListener[] dirtyCheckEventListeners = { new DefaultDirtyCheckEventListener() };
private FlushEventListener[] flushEventListeners = { new DefaultFlushEventListener() };
private EvictEventListener[] evictEventListeners = { new DefaultEvictEventListener() };
private LockEventListener[] lockEventListeners = { new DefaultLockEventListener() };
private RefreshEventListener[] refreshEventListeners = { new DefaultRefreshEventListener() };
private FlushEntityEventListener[] flushEntityEventListeners = { new DefaultFlushEntityEventListener() };
private InitializeCollectionEventListener[] initializeCollectionEventListeners =
{ new DefaultInitializeCollectionEventListener() };
步驟4. DefaultSaveOrUpdateEventListener.onSaveOrUpdate()----業務功能代碼。因爲方法的實現涉及內容比較多,此處暫不做詳細介紹。大體功能有爲了補充齊全SaveOrUpdateEvent事件對象的其餘屬性,可見事件對象是記錄Hibernate操做過程的容器。
步驟5.根據咱們提交給Hibernate的Session的CRU指令操做,重複步驟1到步驟4屢次直到最後到tran.commit()操做,tran是Session開啓的Transction對象,默認JDBCTransction實現,根據hibernate.cfg.xml中配置肯定了在new Configuration().configure()創立的,假定JDBCTransction.commit()的實現,具體代碼以下:
public void commit() throws HibernateException {
if (!begun) {
throw new TransactionException("Transaction not successfully started");
}
log.debug("commit");
if ( !transactionContext.isFlushModeNever() && callback ) {
transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
}
notifyLocalSynchsBeforeTransactionCompletion();
if ( callback ) {
jdbcContext.beforeTransactionCompletion( this );
}
try {
commitAndResetAutoCommit();
log.debug("committed JDBC Connection");
committed = true;
if ( callback ) {
jdbcContext.afterTransactionCompletion( true, this );
}
notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_COMMITTED );
}
catch (SQLException e) {
log.error("JDBC commit failed", e);
commitFailed = true;
if ( callback ) {
jdbcContext.afterTransactionCompletion( false, this );
}
notifyLocalSynchsAfterTransactionCompletion( Status.STATUS_UNKNOWN );
throw new TransactionException("JDBC commit failed", e);
}
finally {
closeIfRequired();
}
}
其中紅色部分是生成sql的方法,這裏暫不展開說明,生成sql依據的是上面步驟1-4所補充完整的事件對象。
綠色部分是Hibernate3對攔截器的支持,咱們都知道Hibernate3比較以前的版本的一個重要的新特性就是支持攔截器,而這一特性就體如今此處。
小結:Session的非查詢操做,只有到tran.commit()才生成sql,期間全部的CRU操做的結果都存放到對應的EventObject對象,對於保存C操做和更改U操做都存放在SaveOrUpdateEvent,刪除操做R存放在DeleteEvent,然後commit()完成全部EventObject生成sql的規則。
各類操做與相應的流程以下面:
操做/流程 |
入口 |
建立事件對象 |
觸發事件 |
事件處理方法 |
save |
SessionImpl.save() |
new SaveOrUpdateEvent() |
fireSave() |
DefaultSaveOrUpdateEventListener |
update |
SessionImpl.update() |
new SaveOrUpdateEvent() |
fireUpdate() |
DefaultSaveOrUpdateEventListener |
Delete |
SessionImpl.delete() |
new DeleteEvent() |
fireDelete() |
DefaultDeleteEventListener |
補充:全部業務處理監聽器都在org.hibernate.event.def包下
總結:
1.save操做:commit()時,數據庫執行,並增長緩存中的對象。
2.delete操做:要求含有主鍵,commit()時,數據庫執行,並刪除緩存中的對象。
若是刪除執行記錄數無影響,即沒有找到要刪除的記錄,報錯。
3.Select操做:直接查詢數據庫,更新緩存中的對象。
4.update操做:要求含有主鍵,commit()時,數據庫執行,並更新緩存中的對象。
若是更新執行記錄數無影響,即沒有找到要修改的記錄,報錯。
使用Hibernate時須要肯定表的結構,只有肯定了表的結構才能肯定表的執行順序,雖然Hibernate的目地是讓咱們編程只關心要操做對象,可是咱們要明白維護(cascade鏈路方向)的方向是單向的,即便咱們說Hibernate支持雙向關聯。
SessionImpl==EventSource 事件源
SaveOrUpdateEvent==Event事件對象