Session.get/load的區(qū)別:
1.如果未能發(fā)現(xiàn)符合條件的記錄,get方法返回null,而load方法會(huì)拋出一個(gè)ObejctNotFoundException。
2.Load方法可返回實(shí)體的代理類類型,而get方法永遠(yuǎn)直接返回實(shí)體類。
3.Load方法可以充分利用內(nèi)部緩存和二級(jí)緩存中現(xiàn)有數(shù)據(jù),而get方法則僅僅在內(nèi)部緩存中進(jìn)行數(shù)據(jù)查找,如沒有發(fā)現(xiàn)對(duì)應(yīng)數(shù)據(jù),將越過二級(jí)緩存,直接調(diào)用SQL完成數(shù)據(jù)讀取。
Session.find/iterate的區(qū)別:
find方法將執(zhí)行Select SQL從數(shù)據(jù)庫(kù)中獲得所有符合條件的記錄并構(gòu)造相應(yīng)的實(shí)體對(duì)象,實(shí)體對(duì)象構(gòu)建完畢之后,就將其納入緩存。它對(duì)緩存只寫不讀,因此無法利用緩存。
iterate方法首先執(zhí)行一條Select SQL以獲得所有符合查詢條件的數(shù)據(jù)id,隨即,iterate方法首先在本地緩存中根據(jù)id查找對(duì)應(yīng)的實(shí)體對(duì)象是否存在,如果緩存中已經(jīng)存在對(duì)應(yīng)的數(shù)據(jù),則直接以此數(shù)據(jù)對(duì)象作為查詢結(jié)果,如果沒有找到,再執(zhí)行相應(yīng)的Select語(yǔ)句獲得對(duì)應(yīng)的庫(kù)表記錄(iterate方法如果執(zhí)行了數(shù)據(jù)庫(kù)讀取操作并構(gòu)建了完整的數(shù)據(jù)對(duì)象,也會(huì)將其查詢結(jié)果納入緩存)。
[實(shí)際的情況是,如果使用了iterate方法返回Iterator類型的查詢結(jié)果,那么你一旦關(guān)閉session,Iterator中的數(shù)據(jù)立即就會(huì)消失.而通過find得到的List則不會(huì)如此,我想大部分人的使用習(xí)慣都是操作完成后立即關(guān)閉session,很多公司也強(qiáng)制要求這樣做.
Iterator的另一個(gè)麻煩事是fail-fast,在多線程環(huán)境下,很容易產(chǎn)生.使用線程安全的List子類,則不會(huì)有這個(gè)問題]
Query Cache產(chǎn)生作用的情況:
1.完全相同的Select SQL重復(fù)執(zhí)行。
2.在兩次查詢之間,此Select SQL對(duì)應(yīng)的庫(kù)表沒有發(fā)生過改變。
Session.save方法的執(zhí)行步驟:
1.在Session內(nèi)部緩存中尋找待保存對(duì)象。內(nèi)部緩存命中,則認(rèn)為此數(shù)據(jù)已經(jīng)保存(執(zhí)行過insert操作),實(shí)體對(duì)象已經(jīng)處于Persistent狀態(tài),直接返回。
2.如果實(shí)體類實(shí)現(xiàn)了lifecycle接口,則調(diào)用待保存對(duì)象的onSave方法。
3.如果實(shí)體類實(shí)現(xiàn)了validatable接口,則調(diào)用其validate()方法。
4.調(diào)用對(duì)應(yīng)攔截器的Interceptor.onSave方法(如果有的話)。
5.構(gòu)造Insert SQL,并加以執(zhí)行。
6.記錄插入成功,user.id屬性被設(shè)定為insert操作返回的新記錄id值。
7.將user對(duì)象放入內(nèi)部緩存。
8.最后,如果存在級(jí)聯(lián)關(guān)系,對(duì)級(jí)聯(lián)關(guān)系進(jìn)行遞歸處理。
Session.update方法的執(zhí)行步驟:
1.根據(jù)待更新實(shí)體對(duì)象的Key,在當(dāng)前session的內(nèi)部緩存中進(jìn)行查找,如果發(fā)現(xiàn),則認(rèn)為當(dāng)前實(shí)體對(duì)象已經(jīng)處于Persistent狀態(tài),返回。
2.初始化實(shí)體對(duì)象的狀態(tài)信息(作為之后臟數(shù)據(jù)檢查的依據(jù)),并將其納入內(nèi)部緩存。注意這里Session.update方法本身并沒有發(fā)送Update SQL完成數(shù)據(jù)更新操作,Update SQL將在之后的Session.flush方法中執(zhí)行,根據(jù)id更新所有的字段,如update user set name=?, password=? where id=?。
Session.saveOrUpdate方法的執(zhí)行步驟:
1.首先在Session內(nèi)部緩存中進(jìn)行查找,如果發(fā)現(xiàn)則直接返回。
2.執(zhí)行實(shí)體類對(duì)應(yīng)的Interceptor.isUnsaved方法(如果有的話),判斷對(duì)象是否為未保存狀態(tài)。
3.根據(jù)unsaved-value判斷對(duì)象是否處于未保存狀態(tài)。
4.如果對(duì)象未保存(Transient狀態(tài)),則調(diào)用save方法保存對(duì)象。
5.如果對(duì)象為已保存(Detached狀態(tài)),調(diào)用update方法將對(duì)象與Session重新關(guān)聯(lián)。
Session.delete(E)
E 由持久狀態(tài)/游離狀態(tài) -->>自由狀態(tài)
Session.flush()
調(diào)用flush
1.直接調(diào)用Session.flush();
2.tx.commit();
//flush before commiting the transaction and closing the session
//Flushing is the process of synchronising the underlying persistent store with persistable state held in memory.
E1=Session.merge(E)
if E is transient instance,則insert數(shù)據(jù)庫(kù),E狀態(tài)不變化,E1是一個(gè)持久化對(duì)象;
if E is detached instance,則重新load,變成persistent instance;
if E is persistent instance,則從緩存中選擇;
// Copy the state of the given object onto the persistent object with the same identifier.
// If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance.
// If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session.
// This operation cascades to associated instances if the association is mapped with cascade="merge".
Session.persist(E)
persist() is well defined. It makes a transient instance persistent. However,
it doesn't guarantee that the identifier value will be assigned to the persistent
instance immediately, the assignment might happen at flush time. The spec doesn't say
that, which is the problem I have with persist().
persist() also guarantees that it will not execute an INSERT statement if it is
called outside of transaction boundaries. This is useful in long-running conversations
with an extended Session/persistence context.A method like persist() is required.
save() does not guarantee the same, it returns an identifier, and if an INSERT
has to be executed to get the identifier (e.g. "identity" generator, not "sequence"),
this INSERT happens immediately, no matter if you are inside or outside of a transaction. This is not good in a long-running conversation with an extended Session/persistence context."