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