一,。 inverse = ?
inverse=false(default)
用于單向one-to-many關(guān)聯(lián)
parent.getChildren().add(child) // insert child
parent.getChildren().delete(child) // delete child
inverse=true
用于雙向one-to-many關(guān)聯(lián)
child.setParent(parent); session.save(child) // insert child
session.delete(child)
在分層結(jié)構(gòu)的體系中
parentDao, childDao對(duì)于CRUD的封裝導(dǎo)致往往直接通過(guò)session接口持久化對(duì)象,,而很少通過(guò)關(guān)聯(lián)對(duì)象可達(dá)性
二。 one-to-many關(guān)系
單向關(guān)系還是雙向關(guān)系,?
parent.getChildren().add(child)對(duì)集合的觸及操作會(huì)導(dǎo)致lazy的集合初始化,,在沒(méi)有對(duì)集合配置二級(jí)緩存的情況下,應(yīng)避免此類操作
select * from child where parent_id = xxx;
性能口訣:
1. 一般情況下避免使用單向關(guān)聯(lián),,盡量使用雙向關(guān)聯(lián)
2. 使用雙向關(guān)聯(lián),,inverse=“true”
3. 在分層結(jié)構(gòu)中通過(guò)DAO接口用session直接持久化對(duì)象,避免通過(guò)關(guān)聯(lián)關(guān)系進(jìn)行可達(dá)性持久化
三,。many-to-one關(guān)系
單向many-to-one表達(dá)了外鍵存儲(chǔ)方
靈活運(yùn)用many-to-one可以避免一些不必要的性能問(wèn)題
many-to-one表達(dá)的含義是:0..n : 1,,many可以是0,可以是1,,也可以是n,,也就是說(shuō)many-to-one可以表達(dá)一對(duì)多,一對(duì)一,,多對(duì)一關(guān)系
因此可以配置雙向many-to-one關(guān)系,,例如:
1. 一桌四人打麻將,麻將席位和打麻將的人是什么關(guān)系,?是雙向many-to-one的關(guān)系
四,。one-to-one
通過(guò)主鍵進(jìn)行關(guān)聯(lián)
相當(dāng)于把大表拆分為多個(gè)小表
例如把大字段單獨(dú)拆分出來(lái),以提高數(shù)據(jù)庫(kù)操作的性能
Hibernate的one-to-one似乎無(wú)法lazy,,必須通過(guò)bytecode enhancement
五,。集合List/Bag/Set
one-to-many
1. List需要維護(hù)index column,不能被用于雙向關(guān)聯(lián),,必須inverse=“false”,,被謹(jǐn)慎的使用在某些稀有的場(chǎng)合
2. Bag/Set語(yǔ)義上沒(méi)有區(qū)別
3. 我個(gè)人比較喜歡使用Bag
many-to-many
1. Bag和Set語(yǔ)義有區(qū)別
2。 建議使用Set
六,。集合的過(guò)濾
1. children = session.createFilter(parent.getChildren(), “where this.age > 5 and this.age < 10”).list()
針對(duì)一對(duì)多關(guān)聯(lián)當(dāng)中的集合元素非常龐大的情況,,特別適合于龐大集合的分頁(yè):
session.createFilter(parent.getChildren(),“”).setFirstResult(0).setMaxResults(10).list();
七,。繼承關(guān)系當(dāng)中的隱式多態(tài)
HQL: from Object
1. 把所有數(shù)據(jù)庫(kù)表全部查詢出來(lái)
2. polymorphism=“implicit”(default)將當(dāng)前對(duì)象,,和對(duì)象所有繼承子類全部一次性取出
3. polymorphism=“explicit”,只取出當(dāng)前查詢對(duì)象
八,。Hibernate二級(jí)緩存
著名的n+1問(wèn)題:from Child,,然后在頁(yè)面上面顯示每個(gè)子類的父類信息,就會(huì)導(dǎo)致n條對(duì)parent表的查詢:
select * from parent where id = ?
.......................
select * from parent where id = ?
解決方案
1. eager fetch
2. 二級(jí)緩存
九,。inverse和二級(jí)緩存的關(guān)系
當(dāng)使用集合緩存的情況下:
1. inverse=“false”,,通過(guò)parent.getChildren()來(lái)操作,,Hibernate維護(hù)集合緩存
2. inverse=“true”,直接對(duì)child進(jìn)行操作,,未能維護(hù)集合緩存,!導(dǎo)致緩存臟數(shù)據(jù)
3. 雙向關(guān)聯(lián),inverse=“true”的情況下應(yīng)避免使用集合緩存
十,。Hibernate二級(jí)緩存是提升web應(yīng)用性能的法寶
OLTP類型的web應(yīng)用,,由于應(yīng)用服務(wù)器端可以進(jìn)行群集水平擴(kuò)展,最終的系統(tǒng)瓶頸總是逃不開數(shù)據(jù)庫(kù)訪問(wèn),;
哪個(gè)框架能夠最大限度減少數(shù)據(jù)庫(kù)訪問(wèn),,降低數(shù)據(jù)庫(kù)訪問(wèn)壓力, 哪個(gè)框架提供的性能就更高,;針對(duì)數(shù)據(jù)庫(kù)的緩存策略:
1. 對(duì)象緩存:細(xì)顆粒度,,針對(duì)表的記錄級(jí)別,透明化訪問(wèn),,在不改變程序代碼的情況下可以極大提升web應(yīng)用的性能,。對(duì)象緩存是ORM的制勝法寶。
2. 對(duì)象緩存的優(yōu)劣取決于框架實(shí)現(xiàn)的水平,,Hibernate是目前已知對(duì)象緩存最強(qiáng)大的開源ORM
3. 查詢緩存:粗顆粒度,,針對(duì)查詢結(jié)果集,應(yīng)用于數(shù)據(jù)實(shí)時(shí)化要求不高的場(chǎng)合
十一,。應(yīng)用場(chǎng)合決定了系統(tǒng)架構(gòu)
一,、是否需要ORM
Hibernate or iBATIS?
二,、采用ORM決定了數(shù)據(jù)庫(kù)設(shè)計(jì)
Hibernate:
傾向于細(xì)顆粒度的設(shè)計(jì),,面向?qū)ο螅瑢⒋蟊聿鸱譃槎鄠€(gè)關(guān)聯(lián)關(guān)系的小表,,消除冗余column,,通過(guò)二級(jí)緩存提升性能(DBA比較忌諱關(guān)聯(lián)關(guān)系的出現(xiàn),但是ORM的緩存將突破關(guān)聯(lián)關(guān)系的性能瓶頸),;Hibernate的性能瓶頸不在于關(guān)聯(lián)關(guān)系,,而在于大表的操作
iBATIS:
傾向于粗顆粒度設(shè)計(jì),面向關(guān)系,,盡量把表合并,,通過(guò)表column冗余,消除關(guān)聯(lián)關(guān)系,。無(wú)有效緩存手段,。iBATIS的性能瓶頸不在于大表操作,而在于關(guān)聯(lián)關(guān)系。
總結(jié):
性能口訣
1,、使用雙向一對(duì)多關(guān)聯(lián),,不使用單向一對(duì)多
2、靈活使用單向多對(duì)一關(guān)聯(lián)
3,、不用一對(duì)一,,用多對(duì)一取代
4、配置對(duì)象緩存,,不使用集合緩存
5,、一對(duì)多集合使用Bag,多對(duì)多集合使用Set
6,、繼承類使用顯式多態(tài)
7,、表字段要少,表關(guān)聯(lián)不要怕多,,有二級(jí)緩存撐腰