Hibernate 源碼分析

這段時間本人利用空閒時間解讀了一下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-manyset,List等。
下面是註明inverse=trueinverse=falsecascade鏈路的區別: 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

測試1save()一個實體對象操做,預計insert發生在擁有外鍵方的表,擁有外鍵方的表是一對多中的多方。 this

結論1:若是實體對象的外鍵屬性爲null,表示不會產生關聯,可直接生成sql;若是外鍵屬性不爲空,根據配置中的cascade去作關聯。若是cascade=all則生成此表的insert和關聯表updatesql,也就是說此時要求關聯屬性的主鍵id不能爲null;若是cascade=save-update則生成此表的insert和關聯表的insert/updatesql(關鍵屬性的主鍵爲nullinsert,不然爲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去調用事件源。

案例1SessionS查詢操做

過程略:

小結:HibernateSelect操做直接生成sql,固然經過了內存緩存才生成的sql

案例2Session調用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的處理方法,目的在於傳參步驟2new出的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();

}
紅色爲關鍵代碼,其中listenersSessionEventListeners屬性。

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.根據咱們提交給HibernateSessionCRU指令操做,重複步驟1到步驟4屢次直到最後到tran.commit()操做,tranSession開啓的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支持雙向關聯。

  • 維護方向是cascade和inverse配置出來的,Hibernate會遵循配置,去生成sql;
  • 另外所謂的雙向關聯只不過是維護方向單向查詢出所關聯的對象然後在內存中進行回填。如,User:Address=1:1,雙向關聯的目標是查詢User對象,可獲得User=User.getAddress().getUser()的結果,Hibernate的實現是單向查詢獲得User即關聯屬性Address對象,然後User.getAddress().setUser(User)進行回填。

SessionImpl==EventSource 事件源

SaveOrUpdateEvent==Event事件對象

相關文章
相關標籤/搜索