淺談Hibernate里的Fetch的作用
現(xiàn)在越來越發(fā)現(xiàn)其實掌握Hibernate Fetch 并不容易,Spring用起來其實簡單多了,但是在用Hibernate的時候真的是需要一定的時間積累,對一個項目組來說如果采用Hibernate***有一個對Hibernate比較清楚的人否則碰到問題就會成為項目的風(fēng)險。
我想告訴各位的是,掌握Hibernate Fetch可能比你預(yù)期的難多了,當(dāng)你輕松的告訴我,Hibernate Fetch很簡單的時候該是你自己多反省了. (只有一種情況例外,你是一個牛人)
好了,一個引子廢話那么多,其實今天只是想先說一說Hibernate Fetch的作用.
大家都知道,在Hibernate里為了性能考慮,引進(jìn)了lazy的概念,這里我們以Parent和Child為模型來說明
- public class Parent implements Serializable {
- /** identifier field */
- private Long id;
- /** persistent field */
- private List childs;
- //skip all getter/setter method
- }
- public class Child implements Serializable {
- /** identifier field */
- private Long id;
- /** persistent field */
- private net.foxlog.model.Parent parent;
- //skip all getter/setter method
- }
在我們查詢Parent對象的時候,默認(rèn)只有Parent的內(nèi)容,并不包含childs的信息,如果在Parent.hbm.xml里設(shè)置lazy="false"的話才同時取出關(guān)聯(lián)的所有childs內(nèi)容.
問題是我既想要Hibernate默認(rèn)的性能又想要臨時的靈活性該怎么辦? 這就是Fetch的功能。我們可以把fetch與lazy="true"的關(guān)系類比為事務(wù)當(dāng)中的編程式事務(wù)與聲明式事務(wù),不太準(zhǔn)確,但是大概是這個意思。
總值,fetch就是在代碼這一層給你一個主動抓取得機會.
- Parent parent = (Parent)hibernateTemplate.execute(new HibernateCallback() {
- public Object doInHibernate(Session session) throws HibernateException, SQLException {
- Query q = session.createQuery(
- "from Parent as parent "+
- " left outer join fetch parent.childs " +
- " where parent.id = :id"
- );
- q.setParameter("id",new Long(15));
- return (Parent)q.uniqueResult();
- }
- });
- Assert.assertTrue(parent.getChilds().size() > 0);
你可以在lazy="true"的情況下把Fetch去掉,就會報異常. 當(dāng)然,如果lazy="false"就不需要fetch了有一個問題,使用Fetch會有重復(fù)記錄的現(xiàn)象發(fā)生,我們可以理解為Fetch實際上不是為Parent服務(wù)的,而是為Child服務(wù)的.所以直接取Parent會有不匹配的問題.
參考一下下面的這篇文章 Hibernate集合初始化
update:以上有些結(jié)論錯誤,實際上在Hibernate3.2.1版本下測試,可以不出現(xiàn)重復(fù)記錄,
- public void testNPlusOne() throws Exception{
- List list = (List)hibernateTemplate.execute(new HibernateCallback() {
- public Object doInHibernate(Session session) throws HibernateException, SQLException {
- Query q = session.createQuery(
- "select distinct p from net.foxlog.model.Parent p inner join fetch p.childs"
- );
- return q.list();
- }
- });
- //((Parent)(list.get(0))).getChilds();
- System.out.println("list size = " + list.size());
- for(int i=0;i<list.size();i++){
- Parent p = (Parent)list.get(i);
- System.out.println("===parent = " + p);
- System.out.println("===parent's child's length = " + p.getChilds().size());
- }
- }
打印結(jié)果如下:
- Hibernate: select distinct parent0_.id as id2_0_, childs1_.id as id0_1_, childs1_.parent_id as parent2_0_1_, childs1_.parent_id as parent2_0__, childs1_.id as id0__ from parent parent0_ inner join child childs1_ on parent0_.id=childs1_.parent_id
- list size = 3
- ===parent = net.foxlog.model.Parent@1401d28[id=14]
- ===parent's child's length = 1
- ===parent = net.foxlog.model.Parent@14e0e90[id=15]
- ===parent's child's length = 2
- ===parent = net.foxlog.model.Parent@62610b[id=17]
- ===parent's child's length = 3
另外,如果用open session in view模式的話一般不用Fetch,但首先推薦Fetch,如果非用的話因為有N+1的現(xiàn)象,所以可以結(jié)合batch模式來改善下性能.
【編輯推薦】