什麼時候會遇到1+N的問題?
前提:Hibernate默認表與表的關聯方法是fetch="select",不是fetch="join",這都是爲了懶加載而準備的。
1)一對多(<set><list>) ,在1的這方,通過1條sql查找得到了1個對象,由於關聯的存在 ,那麼又需要將這個對象關聯的集合取出,所以合集數量是n還要發出n條sql,於是本來的1條sql查詢變成了1 +n條 。
3)iterator 查詢時,一定先去緩存中找(1條sql查集合,只查出ID),在沒命中時,會再按ID到庫中逐一查找, 產生1+n條SQL
怎麼解決1+N 問題?
1 )lazy=true, hibernate3開始已經默認是lazy=true了;lazy=true時不會立刻查詢關聯對象,只有當需要關聯對象(訪問其屬性,非id字段)時纔會發生查詢動作。
2)使用二級緩存, 二級緩存的應用將不怕1+N 問題,因爲即使第一次查詢很慢(未命中),以後查詢直接緩存命中也是很快的。剛好又利用了1+N 。
3) 當然你也可以設定fetch="join",一次關聯表全查出來,但失去了懶加載的特性。
List和Iterator
a. list--從數據庫中查詢出所有的對象列表;只能利用查詢緩存(但在交易系統中查詢緩存作用不大),無法利用二級緩存中的單個實體,但list查出的對象會寫入二級緩存,但它一般只生成較少的執行SQL語句,很多情況就是一條(無關聯)。
load和get
Hibernate中有兩個極爲相似的方法get()與load(),他們都可以通過指定的實體類與ID從數據庫中讀取數據,並返回對應的實例,但Hibernate不會搞兩個完全一樣的方法的,它們間的不同在於:
- 如果找不到符合條件的紀錄,get()方法將返回null.而load()將會報出ObjectNotFoundEcception.
- load()方法可以返回實體的代理類實例,而get()永遠只返回實體類.
- load()方法可以充分利用二級緩存和內部緩存的現有數據,而get()方法只在內部緩存中進行查找,如沒有發現對應數據將跳過二級緩存,直接調用SQL完成查找.
對於get方法,hibernate會確認一下該id對應的數據是否存在,首先在session緩存中查找,然後在二級緩存中查找,還沒有就查數據庫,數據庫中沒有就返回null。
對於第2點,雖然好多書中都這麼說:“get()永遠只返回實體類”,但實際上這是不正確的,get方法如果在session緩存中找到了該id對應的對象,如果剛好該對象前面是被代理過的,如被load方法使用過,或者被其他關聯對象延遲加載過,那麼返回的還是原先的代理對象,而不是實體類對象,如果該代理對象還沒有加載實體數據(就是id以外的其他屬性數據),那麼它會查詢二級緩存或者數據庫來加載數據,但是返回的還是代理對象,只不過已經加載了實體數據。
3。胡說八道,前面已經講了,get方法首先查詢session緩存,沒有的話查詢二級緩存,最後查詢數據庫;反而load方法創建時首先查詢session緩存,沒有就創建代理,實際使用數據時才查詢二級緩存和數據庫。