Re: [問題] hibernate 新手問題

看板java作者 (宅魔)時間12年前 (2013/02/25 00:48), 編輯推噓3(3011)
留言14則, 5人參與, 最新討論串2/3 (看更多)
※ 引述《cyclone350 (老子我最神)》之銘言: : 最近利用空檔在練習 hibernate (進度緩慢) : 因為這問題想了很久,在網路上也不知道關鍵字是甚麼,看了一些 document 也沒頭緒 : 所以就上來請教各位前輩 : 我使用的是 spring + hibernate : 首先 hibernate 是一個 ORM framework。 : 如果我們要 select,利用他提供的 libery 就可以直接存取。 : 要查詢物件也很簡單,例如: : String hql = "from people"; : List<people> peoplesss = this.getSessionTemplete().creatQuery(hql).list(); : 就可以得到這些Entity,相反的 insert 跟 delete 也類似 : 問題來啦,假設這是美食獵人世界的系統資料庫,如果只是用 from people, : 則這個 List 的 size 可能好幾百億,這下不得了。 : 不過 hibernate 可以設定 pageSize 跟 pageNum 之類的東西,可以設定一次只拿到 n 筆 : 問題是 spring 提供的 hibernateTemplete 並沒有這個功能‧‧‧ : 好家在 google 大神跟我說 hibernateTemplete 有一個 callbackHibernate 方法, : 所以此問題就解決了。 問題的解決方式很多,你用了比較曲折離奇的callbackHibernate 方法一:由hibernateTemplate中取得sessionFactory後再取得HibernatSession 方法二:直接使用HibernateDaoSupport,就有getSession : 接下來要設定關聯資料庫 : 假設美食世界的人有三種,美食獵人,廚師,一般人, : 我們可以增加一個 Table 名為 FOOD_TAG。 : 並且在 PEOPLE 的 table 增加一個 FK 名為 TAG,對應到 FOOD_TAG 的 PK, : 所以我們在 PEOPLE 的 Entity 要設定一個 @ManyToOne 對應到 FOOD_TAG : 而 FOOD_TAG 的 Entity 要設定一個 @OneToMany 對應到 PEOPLE。 : 這樣想要知道屬於美食獵人Tag的人有哪些,只需要從 FOOD_TAG 的 Entity 拿到 people : 的 list 就好了。 老實說,你這個例子讓我百思不得其解 這明明只是一個 Enum 的物件,為何要提出來變另一個table people 底下的一個或多個屬性就解決的問題,而且還做成雙向鏈節的關連 : 問題來了,如果我只需要拿到 Tag 的名稱,例如: : Tag tag = getHibernateTemplete(). : createQuery("from tag t where t.name = '一般人'"); : String tagName = tag.getName(); : 那這樣還需要抓取 people List 嗎? : 還好可以設定 fetch lazy 來解決這問題,我可以等到要 getPeopleList 時才 query : (不過 session 不能關啦,或是要設定其他的) : 不過又有問題了,假設我要 getPeopleList,他會一次給我全部的人, : 假設分類在 "一般人" 的 People 有 60 億人,那我的 memory 豈不就爆掉了。 : 於是我翻書,請 google 搜尋此類問題,皆找不到 OneToMany 的限制用法 : 我想要 OneToMany 可以想一般平常的 query 可以設定 maxSize 或是 page 的概念 : 不過 google 似乎也沒找到 ... 這是設計上嚴重的錯誤阿,你把巨量資料設計在屬性之下? 同上,這個問題,你把tag作為people的一個屬性就不會有這種問題 : 另外本來想用 FK 當 where 條件當 query,然後就用一開始的方法。 : 可是在 entity 的 FK 是隱藏的 (joinColumn)。 : 想請問有沒有此類方法可以解? Annotation 要怎麼設定才會有這樣的效果 : 看過很多網站都沒講這問題 當然,因為你正使用了一個不合理的方式在查詢資料,事實上沒這個問題的 你只要稍微改動一下你取得資料方式 方式一: select people from TAG as tag inner join tag.peopleList as people where tag.name = '一般人' 用PEOPLE 的List來接,並設定setFirstResult / setMaxResults 方式二:from PEOPLE as people inner join people.tag as tag where tag.name = '一般人' 兩者都用PEOPLE 的List來接,並設定setFirstResult / setMaxResults 這兒同時顯示,只要單向鏈結,就可以完成你的需求,雙向的設定應不需要 : 有看到一個網頁有用 @Size(max=30) 這樣,但是我的專案根本沒有 @Size : 另外還有一個問題,我還沒自己試過,請問 Entity 的 @oneToMany 之類的會有 : 連鎖效應嗎? : 例如 A -> B -> C -> D <- A : A 對 B , 一對多 : B 對 C , 一對多 : C 對 D , 一對多 : A 對 D , 一對多 : 假設我都是 fetch eager 的話 : 會在 query A 的時候,把 B 一起 query。 : 因為 B -> C,hibernate 會順便 query C 嗎? : 然後 C -> D 再 query D ? : 假設我要拿到D : 就直接 a.getB().get(0).getC().get(0).getD() ? : 這樣找一個資料,數量級大一點的話,hibernate 不就死掉了嗎? : 文有點長,看不董跟我說我再解釋一下,文筆有點不順。 這兒我要強調一下 Hibernate 是一個重視設計的 framework 任何關連的設計,都要考量著資料量,資料變動性,使用不同的策略 任何一個資料量過大的關連,都會立刻造成OOM,沒有例外 你這個問題,如果你採用Lazy的方式,慢慢的get.get.get自然是如此 而這問題我會採用 DAO的方式來解決 直接將取得 D的過程寫成一組 HQL,條件下去直接取出 DAO.getD() Lazy功能是給懶人用的,懶人是不能寫資料量太大,或是太難的系統 針對大量的資料,設計時就要考量負載了,在取資料時,更要一針見血 高變動,大量的資料,就是用StatelessSession + dao 做為取值策略 低變動,交易性的資料,才用StatefulSession + cache為策略 Hibernate 要學好,就要先自宮掉關連資料庫的設計方式 最好,在熟練前也不要摸Spring,在Spring下的Hibernate太容易了 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 118.168.111.216 ※ 編輯: abola921 來自: 118.168.111.216 (02/25 00:51)

02/25 12:07, , 1F
看來我還是乖乖地付錢給 GAE 用 BitTable 就好 [死]
02/25 12:07, 1F

02/25 12:43, , 2F
明白,當初已經用DAO寫HQL解決問題了!!
02/25 12:43, 2F

02/25 16:23, , 3F
第一次聽過lazy fetching是設計給懶人用的 = =
02/25 16:23, 3F
這點我得解釋一下原因,lazy不可否認,他真的很好用!! 一路用過來,隨著系統漸漸龐大,lazy的使用開始造成問題 首先,使用lazy的最大前提是『HibernateSession』不能close不能斷 光是這點,就讓維護的人很頭大了,接到issue的一方,要去抓斷在那 先不提是那一方的不成熟,解決問題方絕對是罵到翻過來 再來,lazy的方便,就是有如原文所提,要取得資料,寫程式你很容易 就會寫成 a.getB().getC().getD() (這很合理,也符合羅輯) 但這段程式碼的背後,隱含的就是hibernate不斷的在進行query 長久下來,其實也不用多久,一個半年的專案全使用lazy在寫的話, 你就會莫名奇秒,效能怎麼就是越來越差,把show_sql一打開來,沒幾 個動作就出現10M以上的SQL。 到這時才警覺到不可以太過依賴lazy時都為時已晚了。 我用這字眼並沒有其它意思,單單就對字面解釋,跟不建議對他依賴 ※ 編輯: abola921 來自: 118.168.111.216 (02/25 22:27)

02/26 00:32, , 4F
conversation 完就能關了,快慢沒有絕對,要依profiling為準
02/26 00:32, 4F

02/26 00:35, , 5F
過長的 method chaining 應該建議改寫,或提供直接的query
02/26 00:35, 5F

02/26 10:04, , 6F
lazy fetching在collection上可以減少不必要的join
02/26 10:04, 6F

02/26 10:06, , 7F
在LOB上可以減少不必要的資料傳輸
02/26 10:06, 7F

02/26 11:38, , 8F
hibernate 3中elementCollection, OneToMany, ManyToMany
02/26 11:38, 8F

02/26 11:40, , 9F
預設皆為lazy fetching, 目的就是避免一次撈太多資料
02/26 11:40, 9F

02/26 11:59, , 10F
lazy是沒有解答中的最佳解,而且能讓程式碼更易維護
02/26 11:59, 10F

02/26 12:07, , 11F
但在hibernate團隊管理中,lazy的使用一直是問題
02/26 12:07, 11F

02/26 12:10, , 12F
因太容易使用,沒人覺得自己的code有效能風險
02/26 12:10, 12F

02/26 12:12, , 13F
在tuning時,別人的code,很難一眼看是出proxy object
02/26 12:12, 13F
/* tuning點 */ public void processPeople(People p){ log.debug( p.getCLass() ); } People people = (People) hibernateSession.load( People.class, "who" ); processPeople( people ); /* 結果為 People的proxy class */ People people = new People(); processPeople( people ); /* 結果為 People.class */ ※ 編輯: abola921 來自: 140.109.20.106 (02/26 12:26) ※ 編輯: abola921 來自: 140.109.20.106 (02/26 12:27)

02/26 12:30, , 14F
以管理專案的立場,多人的專案lazy的使用必需有所控制
02/26 12:30, 14F
文章代碼(AID): #1HAaHpCr (java)
文章代碼(AID): #1HAaHpCr (java)