一、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