一、PO的數據類型設置
int 還是Integer Integer 允許為 null
Hibernate 既可以訪問Field也可以訪問Property,訪問Property是只是調用getXXX()、setXXX()方法,因此在from Customer where c.name=’Tom’ HQL中,name屬性不需要存在,只要getName()存在就可以了。
二、Hibernate映射
1、映射復合主鍵
- 主鍵類 ??
- Public?class?CustomerId?implements?Serializable{ ??
- ????Private?final?String?name; ??
- ????Private?final?String?companyid; ??
- } ??
- 映射文件 ??
- < class ? name =”test.Customer”? table =”CUSTOMERS” > ??
- ???? < composite-id ? name =”customerId”? class =”test.CustomerId” > ??
- ???????? < key-property ? name =”name”? column =”NAME”? type =”string” /> ??
- ???????? < key-property ? name =”companyId”? column =”COMPANY_ID”?? type =”long” /> ??
- ???? </ composite-id > ??
- ???? < version ? name =”varsion”? column =”VERSION”? unsaved-value =”0” /> ??
- ???? < many-to-one ? name =”company”? class =”test.Company”? column =”COMPANY_ID”? insert =”false”? update =”false” /> ??
- ???? < set ? name =”orders”? lazy =”true”? inverse =”true” > ??
- ???????? < key > ??
- ???????????? < column column =”NAME” /> ??
- ???????????? < column column =”COMPANY_ID” /> ??
- ???????? </ key > ??
- ???? </ set > ??
- </ class > ??
- < class ? name =”test.Order”? table =”ORDERS” > ??
- ???? < many-to-one ? name =”customer”? class =”test.Customer” > ??
- ???????????? < column column =”NAME” /> ??
- ???????????? < column column =”COMPANY_ID” /> ??
- ???? </ many-to-one > ??
- </ class > ??
- ??
- 或 ??
- ??
- < class ? name =”test.Customer”? table =”CUSTOMERS” > ??
- ???? < composite-id ? name =”customerId”? class =”test.CustomerId” > ??
- ???????? < key-property ? name =”name”? column =”NAME”? type =”string” /> ??
- < key-many-to-one ? name =”company”? class =”test.Company”? column =”COMPANY_ID” /> ??
- ??
- ???? </ composite-id > ??
- ???? < version ? name =”varsion”? column =”VERSION”? unsaved-value =”0” /> ??
- ???? < set ? name =”orders”? lazy =”true”? inverse =”true” > ??
- ???????? < key > ??
- ???????????? < column column =”NAME” /> ??
- ???????????? < column column =”COMPANY_ID” /> ??
- ???????? </ key > ??
- ???? </ set > ??
- </ class > ??
- < class ? name =”test.Order”? table =”ORDERS” > ??
- ???? < many-to-one ? name =”customer”? class =”test.Customer” > ??
- ???????????? < column column =”NAME” /> ??
- ???????????? < column column =”COMPANY_ID” /> ??
- ???? </ many-to-one > ??
- </ class > ??
2、映射組成關系
- < hibernate-mapping > ??
- ???? < class ? name =”Customer”? table =”CUSTOMERS” > ??
- < property ? /> ??
- ???????? < component ? name =”homeAddress”? class =”Address” > ??
- ???????????? < parent ? name =”customer” /> ??
- ???????????? < property /> ??
- ???????? </ component > ??
- ???????? < component ? name =”comAddress”? class =”Address” > ??
- ???????????? < parent ? name =”customer” /> ??
- ???????????? < property /> ??
- ???????? </ component > ??
- ???? </ class > ??
- </ hibernate-mapping > ??
- ??
- Public?class?Customer?implements?Serializable{ ??
- ????Address?homeAddress; ??
- ????Address?comAddress; ??
- } ??
- Public?class?Address?implements?Serializable{//是VO不是PO不能單獨Save,也不能關聯。 ??
- ????Customer?customer; ??
- }??
3、映射聚合關系
- < set /idbag? name =”images”? table =”IMAGES”? lazy =”true” > ??
- ???? < key ? column =”CUSTOMER_ID” /> ??
- ???? < composite-element ? class =”Image” > ??
- ???????? < parent ? name =”customer” /> ??
- ???????? < property /> ??
- < property /> ??
- ???? </ composite-element > ??
- </ set /idbag > ??
- ??
- < map ? name =”images”? table =”IMAGES”? lazy =”true” > ??
- ???? < key ? column =”CUSTOMER_ID” /> ??
- ???? < index ? type =”string”? column =”IMAGE_NAME” /> ??
- ???? < composite-element ? class =”Image” > ??
- ???????? < parent ? name =”customer” /> ??
- ???????? < property /> ??
- < property /> ??
- ???? </ composite-element > ??
- </ map ? > ??
4、映射繼承關系
- DOClass{ ??
- ???id ??
- } ??
- ClassA?extends?DOClass{ ??
- ????A1 ??
- } ??
- ??
- ClassC?extends?ClassA{ ??
- ????C1 ??
- } ??
- ??
- ClassD?extends?ClassA{ ??
- ????D1 ??
- } ??
- ??
- ClassG?extends?ClassD{ ??
- ????G1 ??
- } ??
- ??
- ClassH?extends?ClassD{ ??
- ????H1 ??
- } ??
- ??
- ClassB?extends?DOClass{ ??
- ????B1 ??
- } ??
- ??
- ClassE?extends?ClassB{ ??
- ????E1,e2,e3,e4,e5,e6 ??
- } ??
- ??
- ClassF?extends?ClassB{ ??
- ????F1,f2,f3,f4,f5,f6,f7 ??
- } ??
- ??
- TABLE_A?{ID(PK),A_TYPE(discriminator),A1,C1,D1,G1,H1} ??
- TABLE_B?{ID(PK),B1} ??
- TABLE_E?{B_ID(PK/FK),E1,E2,E3,E4,E5,E6} ??
- TABLE_F?{B_ID(PK/FK),F1,F2,F3,F4,F5,F6,F7} ??
- ??
- ClassA.hbm.xml ??
- < hibernate-mapping > ??
- ???? < class ? name =”ClassA”? table =”TABLE_A”? discriminator-value =”A” > ??
- ???????? < id /> ??
- ???????? < discriminator ? column =”A_TYPE”? type =”string” /> ??
- ???????? < property ? name =”a1”? column =”A1” /> ??
- ???????? < sub-class ? name =”ClassC”? discriminator-value =”C” > ??
- ???????????? < property ? name =”c1”? column =”C1” /> ??
- ???????? </ sub-class > ??
- < subclass ? name =”ClassD”? discriminator-value =”D” > ??
- ???????????? < property ? name =”d1”? column =”D1” /> ??
- ???????????? < subclass ? name =”ClassG”? discriminator-value =”G” > ??
- ???????????????? < property ? name =”g1”? column =”G1” /> ??
- ???????????? </ subclass > ??
- ???????????? < subclass ? name =”ClassH”? discriminator-value =”H” > ??
- ???????????????? < property ? name =”h1”? column =”H1” /> ??
- ???????????? </ subclasss > ??
- </ subclass > ??
- </ class > ??
- </ hibernate-mapping > ??
- ClassB.hbm.xml ??
- < hibernate-mapping > ??
- ???? < class ? name =”ClassB”? table =”TABLE_B” > ??
- ???????? < id /> ??
- ???????? < property ? name =”b1”? column =”B1” /> ??
- ???????? < joined-subclass ? name =”ClassE”? table =”TABLE_E” > ??
- ???????????? < key ? column =”B_ID” /> ??
- ???????????? < property ? name =”e1”? column =”E1” /> ??
- ???????????? < property ? name =”e2”? column =”E2” /> ??
- ???????????? < property ? name =”e3”? column =”E3” /> ??
- ???????????? < property ? name =”e4”? column =”E4” /> ??
- ???????????? < property ? name =”e5”? column =”E5” /> ??
- ???????????? < property ? name =”e6”? column =”E6” /> ??
- ???????? </ joined-subclass > ??
- ???????? < joined-subclass ? name =”ClassF”? table =”TABLE_F” > ??
- ???????????? < key ? column =”B_ID” /> ??
- ???????????? < property ? name =”f1”? column =”F1” /> ??
- ???????????? < property ? name =”f2”? column =”F2” /> ??
- ???????????? < property ? name =”f3”? column =”F3” /> ??
- ???????????? < property ? name =”f4”? column =”F4” /> ??
- ???????????? < property ? name =”f5”? column =”F5” /> ??
- ???????????? < property ? name =”f6”? column =”F6” /> ??
- ???????????? < property ? name =”f7”? column =”F7” /> ??
- ???????? </ joined-subclass > ??
- ???? </ class > ??
- </ hibernate-mapping > ??
5、映射Bag,List和Map
IDBag
- IMAGES{ID(PK),CUSTOMER_ID(FK),FILENAME} ??
- List? images ?=? new ?ArrayList(); ??
- Customer.hbm.xml ??
- ??
- < idbag ? name =”images”? table =”IMAGES”? lazy =”true” > ??
- ???? < collection-id ? type =”long”? column =”ID” > ??
- ???????? < generator ? class =”increment” /> ??
- ???? </ collection-id > ??
- ???? < key ? column =”CUSTOMER_ID” /> ??
- ???? < element ? column =”FILENAME”? type =”string”? not-null =”true” /> ??
- </ idbag > ??
List
- IMAGES{CUSTOMER_ID(PK/FK),POSITION(PK),FILENAME} ??
- List? images ?=? new ?ArrayList(); ??
- Customer.hbm.xml ??
- < list ? name =”images”? table =”IMAGES”? lazy =”true” > ??
- ???? < index ? column =”POSITION” /> ??
- ???? < key ? column =”CUSTOMER_ID” /> ??
- ???? < element ? column =”FILENAME”? type =”string”? not-null =”true” /> ??
- </ list > ??
Map
- IMAGES{CUSTOMER_ID(PK/FK),IMAGE_NAME(PK),FILENAME} ??
- Map? images ?=? new ?HashMap(); ??
- < map ? name =”images”? table =”IMAGES”? lazy =”true” > ??
- ???? < key ? column =”CUSTOMER_ID” /> ??
- < index ? column =”IMAGE_NAME”? type =”string” /> ??
- ???? < element ? column =”FILENAME”? type =”string”? not-null =”true” /> ??
- </ map > ??
- ??
- Set?idbag?map?支持數據庫排序??order? by ?=”ID” ??
- Set?map?支持內存排序?? sort ?=?“MyComparator”??
6、映射一對一關聯關系特殊情況一
- Public? class ?Customer{ ??
- ????Address?homeAddress; ??
- ????Address?comAddress; ??
- } ??
- ??
- Customer.hbm.xml ??
- <many-to-one?name=”homeAddress”? class =”Address”?column=”HOME_ADDRESS_ID”?cascade=”all”?unique=” true ”/> ??
- <many-to-one?name=”comAddress”? class =”Address”?column=”COM_ADDRESS_ID”?cascade=”all”?unique=” true ”/> ??
- ??
- Address.hbm.xml ??
- <one-to-one?name=”address”? class =”Customer”?property-ref=”homeAddress”/>??
映射一對一關聯關系主鍵映射
- Customer.hbm.xml ??
- < one-to-one ? name =”address”? class =”Address”? cascade =”all” /> ??
- Address.hbm.xml ??
- < class ? name =”address” > ??
- ???? < id > ??
- ???????? < generator ? class =”foreign” > ??
- ???????????? < param ? name =”property” > customer </ param > ??
- ???????? </ generator > ??
- ???? </ id > ??
- < one-to-one ? name =”customer”? class =”Customer”? constrained =”true” /> ??
- </ class > ??
7、映射一對多關聯
- < class ? name = "Person" > ??
- < id ? name = "id" ? column = "personId" > ??
- ???????? < generator ? class = "native" /> ??
- </ id > ??
- < many-to-one ? name = "address" ? column = "addressId" ? not-null = "true" /> ??
- </ class > ??
- ??
- < class ? name = "Address" > ??
- < id ? name = "id" ? column = "addressId" > ??
- < generator ? class = "native" /> ??
- </ id > ??
- < set ? name = "people" ? inverse = "true" > ??
- ?????? < key ? column = "addressId" /> ??
- < one-to-many ? class = "Person" /> ??
- </ set > ??
- </ class > ??
8、映射多對多關聯
- < set ? name =”items”? table =”CATEGORY_ITEM”? lazy =”true”? cascade =”save-update” > ??
- ???? < key ? column =”CATEGORY_ID” > ??
- ???? < many-to-many ? class =”Item”? column =”ITEM_ID” /> ??
- </ set > ??
三、Inverse與cascade
Inverse
應該將Set的inverse屬性設置為true,如果為many-to-many 需要將一方設置為true
如Customer:Order為1:N雙向關聯,將Customer的Set的inverse設置為true,表示Customer與Order之間的關聯關系由Order端來維護,如customer.getOrders().addOrder(o)不會更新Customer與Order之間的關聯關系,而order.setCustomer(o)才會更新Customer與Order之間的關聯關系。
Cascade
Save-update 保存、更新Customer會同步更新Order.
Delete 同步刪除
All 包含save-update和delete操作,另外調用當前對象的evice或者lock時,對關聯對象也調用相應方法。
Delete-orphan 刪除所有和當前對象解除關聯關系的對象。
All-delete-orphan 當關聯雙方為父子關系是(父親控制孩子的持久化生命周期),如果父方刪除,子方自動刪除(同delete),如果子方無父親,子方應刪除。包含Delete和all-orphan的行為。
四、Hibernate緩存
Session 緩存(一級緩存),每一session確保自己的緩存的所有的持久對象唯一
通過調用session.setFlushMode()可設定緩存的清理模式,緩存的清理模式有三種:
FlushMode.AUTO:query、commit和flush的時候清理緩存。
FlushMode.COMMIT:commit和flush的時候清理緩存。
FlushMode.NEVER:只有在調用session.flush()的時候才清理緩存。
Session 只有在清理緩存的時候才會執行相應的sql操作。
可以使用session.evict()和session.clear()清空緩存。
Save、update、query都加入Session緩存
Select c.ID,c.Name,c.age,o.ORDER_NUM,o.CUSTOMER_ID from Customer c,inner join c.orders c 除外。
SessionFactory緩存(二級緩存)
- < class ? name =”Category”? table =”CATEGORYS” > ??
- ???? < cache ? usage =”read-write” /> ??
- ???? < id /> ??
- ???? < set ? name =”items”? inverse =”true”? lazy =”true” > ??
- ???????? < cache ? usage =”read-write” /> ??
- ???????? < key … /> ??
- ???? </ set > ??
- </ class > ??
- < class ? name =”Item” > ??
- ???? < cache ? usage =”read-write” /> ??
- ???? < id /> ??
- </ class > ??
- ??
- Hibernate.cache.provider =…………EhCacheProvider ??
- Hibernate.cache.user_query_cache = true ??
- ??
- Ehcache.xml ??
- < ehcache > ??
- ???? < diskStore ? path =”c:\\temp” /> ??
- ???? < defaultCache ??
- ???????? maxElementsInMemory =”10000” ??
- ???????? eternal =”false” ??
- ???????? timeToIdleSeconds =”120” ??
- ???????? timeToLiveSeconds =”120” ??
- ???????? overflowToDisk =”true” /> ??
- ???? < cache ? name =”Category” ??
- ???????? maxElementsInMemory =”10000” ??
- ???????? eternal =”false” ??
- ???????? timeToIdleSeconds =”120” ??
- ???????? timeToLiveSeconds =”120” ??
- ???????? overflowToDisk =”true” /> ??
- ??
- ???? < cache ? name =”Category.Items” ??
- ???????? maxElementsInMemory =”10000” ??
- ???????? eternal =”false” ??
- ???????? timeToIdleSeconds =”120” ??
- ???????? timeToLiveSeconds =”120” ??
- ???????? overflowToDisk =”true” /> ??
- ??
- ???? < cache ? name =”Item” ??
- ???????? maxElementsInMemory =”10000” ??
- ???????? eternal =”false” ??
- ???????? timeToIdleSeconds =”120” ??
- ???????? timeToLiveSeconds =”120” ??
- ???????? overflowToDisk =”true” /> ??
- ??
- ???? < cache ? name =”customerQueries”…. /> ?<!—設置查詢緩存? ??
- ??
- </ ehcache > ??
Query q = session.createQuery();
q.setCacheable(true);
q.setCacheRegion(“customerQueries”);
SessionFactory.evict(),SessionFactory.evictCollection()清除二級緩存。
直接調用JDBC API不會使用任何緩存。
二級緩存適合查詢較多但是很少更新的情況。
盡量對數據庫的所有操作由Hibernate來完成,而不要用其它方式對數據庫進行操作,否則可能與緩存沖突,當然如果對緩存有深入研究的除外。
五、臨時對象(Transient Object)、持久對象(Persistent Object)和游離對象(Detached Object)
臨時對象:表示對象的主鍵不存在(OID不存在),Hibernate通過key的unsave-value或者version的unsaved-value來判斷是否為臨時對象。Session對臨時對象的唯一操作應該是save()。
持久對象:在session緩存中存在持久對象,數據庫中存在相應紀錄。
游離對象:數據庫中有相應紀錄,session中不存在持久對象,可通過session.evict()獲得。
Session緩存中存在,數據庫中不存在,這是什么類型的對象?實際這種情況不存在,因為所有的Session操作均在事務中進行,緩存中的數據是通過save、update或者query生成,而save或者update得到的是數據庫的獨占鎖,因此其它事務沒有可能刪除數據庫中的數據。而query獲得的是數據庫的共享鎖,因此其它事務也不可能獲得獨占鎖來更新數據。因此在一個事務內部session緩存才有意義,如果脫離事務,僅僅是只讀操作也可能導致session緩存中存在數據庫中根本不存在相應紀錄的持久性對象。
六、Hibernate 的檢索策略
設定批量檢索數量 batch-size
外連接深度控制hibernate.max_fetch_depth
類級別檢索 load、get和find。其中load可以設置延遲檢索(cglib生成代理類,可通過Hibernate.initialize()初始化),這也是load和get的區別之一。Get/find立即檢索,與是否設置延遲無關。
關聯檢索 立即檢索,延遲檢索,迫切左外連接檢索。Set/list/map等,無論是否延遲檢索得到的都是代理集合類。而非HashSet,ArrayList等。
Lazy與outer-joint
False,false 立即檢索
False,true 迫切左外連接,
True,false 延遲檢索
Many-to-one 的outer-join屬性
Auto:Customer的lazy為true則延遲加載,否則迫切左外連接
True:迫切左外連接
False:延遲加載或者立即加載由Customer的lazy決定。
One-to-one的延遲加載策略
<one-to-one name=”customer” class=”Customer” constrained=”true”/>
HQL會忽略迫切左外連接檢索和lazy(只有load才為代理對象)策略。
Session.find(“from Customer c as c left join fetch c.orders where c.id=1”)
Hibernate的檢索方式
HQL、NativeSql和QBC
From Customer c inner join c.orders o 查詢結果保存到session緩存
Select c.ID,c.Name,c.age,o.ORDER_NUM,o.CUSTOMER_ID from Customer c,inner join c.orders c查詢結果不存入Session緩存。
七、Hibernate并發控制
樂觀鎖:VERSION或者timestamp控制,session.lock()立刻進行版本檢查,session.update(),update的時候執行版本檢查。
悲觀鎖:select for upload,session.get(Customer.class,new Long(1),LockMode.UPGRADE)
總結:本文絕大多數為摘錄內容,有些地方加上自己的理解,有不對之處懇請批評指正。看了書,閱讀了相關帖子后,感覺學習Hibernate的重點應該是Hibernate的緩存策、查詢和如何提高性能方面。
另外說點自己的感受,本人做項目到現在都是在設計階段先有關系模型后有對象模型(其實一個Table一個對象),在這種情況下Hibernate的優勢大大降低了,其實是為了Hibernate而Hibernate了,個人感覺在先有關系模型的情況下用Hibernate的意義不大。
如果按照OOAD的開發流程先有對象模型,然后根據對象模型生成關系模型,那應該說用Hibernate用對了地方。畢竟Hibernate對繼承、多態,各種復雜的關系都有很好的支持。
http://www.javaeye.com/topic/42854