注意:討論的前提是主鍵最好是不含有任何業(yè)務(wù)邏輯含義的。
Hibernate里再三推薦使用這種主鍵,因?yàn)橹麈I的選擇滿足以下幾點(diǎn):
1,不能為null
2,每行中只有唯一的值
3,特定行中的相應(yīng)值不能改變
既然誰也無法保證業(yè)務(wù)相關(guān)的屬性不會(huì)改變,那么選擇一個(gè)純粹意義上的功能單一的(唯一的功能就是做主鍵唯一標(biāo)識(shí)DB中的一行)主鍵省了很多麻煩。
hibernate中的對(duì)象有三種狀態(tài):transient,persisitent,detached
一,transient object
Hibernate中,用new創(chuàng)建的對(duì)象不會(huì)馬上持久,此時(shí)的狀態(tài)為transient,意味著,這些對(duì)象還沒有跟數(shù)據(jù)庫表中的某一行相關(guān)聯(lián),一旦它們不再被程序中的其他對(duì)象引用,它們的壽命到此為止,要被gc回收了。在hibernate中,transient對(duì)象都是非事務(wù)性的,它們狀態(tài)的改變不會(huì)影響任何事務(wù)的上下文環(huán)境,由此可知,hibernate不提供transient對(duì)象的回滾。實(shí)際上,hibernate不回滾任何對(duì)象的變化。transient對(duì)象只能被transient對(duì)象引用。
二,persisitent object
有一個(gè)主鍵集作為其在數(shù)據(jù)庫中的identifier(標(biāo)識(shí))的對(duì)象就是persisitent對(duì)象。產(chǎn)生persisitent對(duì)象有兩種方法:
1,對(duì)一個(gè)transient對(duì)象(即由應(yīng)用程序創(chuàng)建的對(duì)象)調(diào)用持續(xù)管理器(Persistence Manager)的API的Session的save()方法
2,由一個(gè)已經(jīng)存在的persistent對(duì)象創(chuàng)建的對(duì)象實(shí)例就是persisitent對(duì)象
persisitent對(duì)象總是跟Seesion相關(guān)聯(lián)的,并且是事務(wù)性的,它參與到事務(wù)中去,在事務(wù)結(jié)束時(shí),它們的狀態(tài)和數(shù)據(jù)庫相同步。
當(dāng)一個(gè)persisitent對(duì)象分配到了一個(gè)主鍵值,但沒有插入到數(shù)據(jù)庫中去,稱之為new persisitent instance,在與數(shù)據(jù)庫同步之前,它一直是new persisitent instance。
Automatic dirty checking:自動(dòng)檢查事務(wù)中的persisitent對(duì)象是否被應(yīng)用程序修改過。如果一個(gè)對(duì)象被修改過,但是這個(gè)修改并沒有提交到數(shù)據(jù)庫,此時(shí)就認(rèn)為這個(gè)對(duì)象是dirty。
從DB中remove一個(gè)persisitent對(duì)象所對(duì)應(yīng)的行,則該對(duì)象就變成transient對(duì)象了。
三,detached object
當(dāng)事務(wù)完成后,與Session相關(guān)聯(lián)的persisitent對(duì)象仍然存在,仍是persisitent的,直到調(diào)用Session 的close()方法關(guān)閉會(huì)話。會(huì)話關(guān)閉后,對(duì)象稱為detached,表明它們的狀態(tài)不再保證與數(shù)據(jù)庫同步,不在Persistence Manager的管理之下了。但此時(shí),detached的對(duì)象仍然包含persisitent數(shù)據(jù),應(yīng)用程序也可能可以獲取這個(gè)對(duì)象的實(shí)例。 Hibernate允許用一個(gè)新的Session與之相關(guān)聯(lián),在一個(gè)新的事務(wù)中重用這個(gè)對(duì)象。
Hibernate辨別一個(gè)對(duì)象是transient對(duì)象還是detached對(duì)象的方法:
1,如果存在identifier屬性的話,判斷是否為null,如果為null則為trasient對(duì)象
2,如果存在version屬性的話,判斷是否為null,如果為null則為trasient對(duì)象
3,在映射文件中為class或version提供一個(gè)"unsaved-value"的屬性,當(dāng)對(duì)象中相應(yīng)的屬性(類的是identifier屬性,version就是version屬性)的值等于文件中定義的"unsaved-value"的值,那么該對(duì)象就是transient對(duì)象。
4,在代碼中使用Interceptor.isUnsaved()方法,如果返回為Boolean.TRUE的話,則為trasient對(duì)象
其中還談到對(duì)象的辨別,即如何辨別persisitent對(duì)象對(duì)應(yīng)于DB中的同一行,這就涉及到persisitent類的equals()方法和hashcode()方法的實(shí)現(xiàn)問題,方法有多種,大多都有或多或少的隱患,有一種比較合適,就是使用business key equality(業(yè)務(wù)鍵相等),一個(gè)business key是一個(gè)或幾個(gè)屬性的聯(lián)合,唯一標(biāo)識(shí)每一個(gè)對(duì)象,并且對(duì)應(yīng)于DB中相同的identifier。每個(gè)實(shí)體都應(yīng)該有business key,用以唯一標(biāo)識(shí)一條特殊的記錄。
關(guān)于Session,創(chuàng)建一個(gè)Session的開銷很小,因?yàn)樗猾@取JDBC連接,不執(zhí)行任何SQL語句,直到需要的時(shí)候才獲取,需要與DB 同步時(shí),調(diào)用事務(wù)的commit()方法,此時(shí)Hibernate獲得了JDBC的一個(gè)連接,并執(zhí)行SQL語句,當(dāng)Session關(guān)閉時(shí),JDBC連接也被釋放了。從session.beginTransaction()到commit()方法之間發(fā)生的一系列操作,都認(rèn)為是在同一個(gè)事務(wù)中的操作。