Without ejb中寫到,當(dāng)事務(wù)被標(biāo)識(shí)為只讀事務(wù)時(shí),某些可以針對(duì)只讀事務(wù)進(jìn)行優(yōu)化的資源就可以執(zhí)行相應(yīng)的優(yōu)化措施,比如說hibernate的session在只讀事務(wù)模式下不會(huì)嘗試檢測(cè)和同步持久對(duì)象的狀態(tài)的更新。另外還寫到j(luò)dbc的connection可以通過調(diào)用setReadOnly(true)來切換到只讀事務(wù)模式上來;但是大多數(shù)jdbc driver會(huì)忽略掉他。
從這里面我們可以看到 flush 實(shí)際上是由 DefaultFlushEventListener 來執(zhí)行的,而且 sessionimpl 默認(rèn)的只注冊(cè)了一個(gè) FlushEventListener 實(shí)例(為什么只有一個(gè)還要這樣做,我估計(jì)他是為了擴(kuò)展的需要,不知道 3.2 中是否就不止一個(gè)了呢?),這個(gè) DefaultFlushEventListener 最終執(zhí)行了 flush 的方法:
java 代碼
- public void onFlush(FlushEvent event) throws HibernateException {
- final EventSource source = event.getSession();
- if ( source.getPersistenceContext().hasNonReadOnlyEntities() ) {
-
- flushEverythingToExecutions(event);
-
-
- performExecutions(source);
-
- postFlush(source);
-
- if ( source.getFactory().getStatistics().isStatisticsEnabled() ) {
- source.getFactory().getStatisticsImplementor().flush();
- }
-
- }
- }
由此我們看到 hibernate 在執(zhí)行 flush 操作的時(shí)候還是做了不少事情的,它不但要把持久對(duì)象刷到數(shù)據(jù)庫(kù),而且還要把其管理的對(duì)象也都刷到數(shù)據(jù)庫(kù)中,這是一個(gè)很大的操作。同時(shí)如果你使用了二級(jí)緩存, flush 操作也會(huì)涉及到它,而且在 flush 時(shí)還要判斷哪些時(shí)插入的,哪些是更新的,哪些是刪除的等等, flush 完了還得更新一級(jí)緩存等。
其實(shí)我只是對(duì) flush 作了最簡(jiǎn)單的概括和描述,事實(shí)上從代碼上看來它遠(yuǎn)比我們想象的要來得復(fù)雜的多。
在對(duì) flush 簡(jiǎn)單得了解了之后,我們?cè)賮碛懻撘幌拢簽槭裁匆巡樵冊(cè)O(shè)置為只讀事務(wù)。因?yàn)橐粋€(gè)本來只是查詢的操作,卻要在事務(wù)提交時(shí)多做這么多事情,這顯然是不合理的,所以 hibernate 才給 session 的設(shè)置了這么一個(gè) flushmode ,那么只要這個(gè) mode 為 never ,就可以免去這些不必要的操作。而 spring 在對(duì) hibernate 的支持時(shí)也充分的考慮到了這一點(diǎn),所以就把只讀事務(wù)的 session 的 flush mode 設(shè)置為了 never 。這樣我們事務(wù)提交時(shí)就不會(huì)執(zhí)行 flush 操作了。
總結(jié):
所以說,我們?cè)谑褂?/span> spring 時(shí)一定要注意把查詢的操作定義成只讀事務(wù),這個(gè)可以給我們帶來不必要的開銷,比如看如下配置。
< property name = "transactionAttributes" >
< props >
< prop key = "do*" > PROPAGATION_REQUIRED prop >
< prop key = "get*" > PROPAGATION_REQUIRED,readOnly prop >
< prop key = "load*" > PROPAGATION_REQUIRED,readOnly prop >
< prop key = "find*" > PROPAGATION_REQUIRED,readOnly prop >
< prop key = "list*" > PROPAGATION_REQUIRED,readOnly prop >
props >
property >
或者事務(wù)的傳播途徑最好能設(shè)置為 supports (運(yùn)行在當(dāng)前的事務(wù)范圍內(nèi),如果當(dāng)前沒有啟動(dòng)事務(wù),那么就不在事務(wù)范圍內(nèi)運(yùn)行)或者 not supports (不在事務(wù)范圍內(nèi)執(zhí)行,如果當(dāng)前啟動(dòng)了事務(wù),那么掛起當(dāng)前事務(wù)),也就是說查詢操作其實(shí)可以不必要真正的開啟一個(gè)數(shù)據(jù)庫(kù)事務(wù),因?yàn)殚_啟一個(gè)真正的數(shù)據(jù)庫(kù)事務(wù)又會(huì)給我們帶來一點(diǎn)點(diǎn)可以忽略不計(jì)的開銷。下面是一個(gè)例子
< property name = "transactionAttributes" >
< props >
< prop key = "do*" > PROPAGATION_REQUIRED prop >
< prop key = "get*" > PROPAGATION_SUPPORTS,readOnly prop >
< prop key = "load*" > PROPAGATION_SUPPORTS,readOnly prop >
< prop key = "find*" > PROPAGATION_SUPPORTS,readOnly prop >
< prop key = "list*" > PROPAGATION_SUPPORTS,readOnly prop >
props >
property >
作者:張榮華,未經(jīng)作者同意不得隨意轉(zhuǎn)載!