hibernate小结
一、PO的数据类型设置
int还是IntegerInteger允许为null
Hibernate既可以访问Field也可以访问Property,访问Property是只是调用getXXX()、setXXX()方法,因此在fromCustomerwherec.name=’Tom’HQL中,name属性不需要存在,只要getName()存在就可以了。
二、Hibernate映射
1、映射复合主键
Java代码
1.主键类
2.PublicclassCustomerIdimplementsSerializable{
3.PrivatefinalStringname;
4.PrivatefinalStringcompanyid;
5.}
6.映射文件
7.<classname=”test.Customer”table=”CUSTOMERS”>
8.<composite-idname=”customerId”class=”test.CustomerId”>
9.<key-propertyname=”name”column=”NAME”type=”string”/>
10.<key-propertyname=”companyId”column=”COMPANY_ID”type=”long”/>
11.</composite-id>
12.<versionname=”varsion”column=”VERSION”unsaved-value=”0”/>
13.<many-to-onename=”company”class=”test.Company”column=”COMPANY_ID”insert=”false”update=”false”/>
14.<setname=”orders”lazy=”true”inverse=”true”>
15.<key>
16.<column=”NAME”/>
17.<column=”COMPANY_ID”/>
18.</key>
19.</set>
20.</class>
21.<classname=”test.Order”table=”ORDERS”>
22.<many-to-onename=”customer”class=”test.Customer”>
23.<column=”NAME”/>
24.<column=”COMPANY_ID”/>
25.</many-to-one>
26.</class>
27.
28.或
29.
30.<classname=”test.Customer”table=”CUSTOMERS”>
31.<composite-idname=”customerId”class=”test.CustomerId”>
32.<key-propertyname=”name”column=”NAME”type=”string”/>
33.<key-many-to-onename=”company”class=”test.Company”column=”COMPANY_ID”/>
34.
35.</composite-id>
36.<versionname=”varsion”column=”VERSION”unsaved-value=”0”/>
37.<setname=”orders”lazy=”true”inverse=”true”>
38.<key>
39.<column=”NAME”/>
40.<column=”COMPANY_ID”/>
41.</key>
42.</set>
43.</class>
44.<classname=”test.Order”table=”ORDERS”>
45.<many-to-onename=”customer”class=”test.Customer”>
46.<column=”NAME”/>
47.<column=”COMPANY_ID”/>
48.</many-to-one>
49.</class>
2、映射组成关系
Java代码
1.<hibernate-mapping>
2.<classname=”Customer”table=”CUSTOMERS”>
3.<property/>
4.<componentname=”homeAddress”class=”Address”>
5.<parentname=”customer”/>
6.<property/>
7.</component>
8.<componentname=”comAddress”class=”Address”>
9.<parentname=”customer”/>
10.<property/>
11.</component>
12.</class>
13.</hibernate-mapping>
14.
15.PublicclassCustomerimplementsSerializable{
16.AddresshomeAddress;
17.AddresscomAddress;
18.}
19.PublicclassAddressimplementsSerializable{//是VO不是PO不能单独Save,也不能关联。
20.Customercustomer;
21.}
3、映射聚合关系
Java代码
1.<set/idbagname=”images”table=”IMAGES”lazy=”true”>
2.<keycolumn=”CUSTOMER_ID”/>
3.<composite-elementclass=”Image”>
4.<parentname=”customer”/>
5.<property/>
6.<property/>
7.</composite-element>
8.</set/idbag>
9.
10.<mapname=”images”table=”IMAGES”lazy=”true”>
11.<keycolumn=”CUSTOMER_ID”/>
12.<indextype=”string”column=”IMAGE_NAME”/>
13.<composite-elementclass=”Image”>
14.<parentname=”customer”/>
15.<property/>
16.<property/>
17.</composite-element>
18.</map>
4、映射继承关系
Java代码
1.DOClass{
2.id
3.}
4.ClassAextendsDOClass{
5.A1
6.}
7.
8.ClassCextendsClassA{
9.C1
10.}
11.
12.ClassDextendsClassA{
13.D1
14.}
15.
16.ClassGextendsClassD{
17.G1
18.}
19.
20.ClassHextendsClassD{
21.H1
22.}
23.
24.ClassBextendsDOClass{
25.B1
26.}
27.
28.ClassEextendsClassB{
29.E1,e2,e3,e4,e5,e6
30.}
31.
32.ClassFextendsClassB{
33.F1,f2,f3,f4,f5,f6,f7
34.}
35.
36.TABLE_A{ID(PK),A_TYPE(discriminator),A1,C1,D1,G1,H1}
37.TABLE_B{ID(PK),B1}
38.TABLE_E{B_ID(PK/FK),E1,E2,E3,E4,E5,E6}
39.TABLE_F{B_ID(PK/FK),F1,F2,F3,F4,F5,F6,F7}
40.
41.ClassA.hbm.xml
42.<hibernate-mapping>
43.<classname=”ClassA”table=”TABLE_A”discriminator-value=”A”>
44.<id/>
45.<discriminatorcolumn=”A_TYPE”type=”string”/>
46.<propertyname=”a1”column=”A1”/>
47.<sub-classname=”ClassC”discriminator-value=”C”>
48.<propertyname=”c1”column=”C1”/>
49.</sub-class>
50.<subclassname=”ClassD”discriminator-value=”D”>
51.<propertyname=”d1”column=”D1”/>
52.<subclassname=”ClassG”discriminator-value=”G”>
53.<propertyname=”g1”column=”G1”/>
54.</subclass>
55.<subclassname=”ClassH”discriminator-value=”H”>
56.<propertyname=”h1”column=”H1”/>
57.</subclasss>
58.</subclass>
59.</class>
60.</hibernate-mapping>
61.ClassB.hbm.xml
62.<hibernate-mapping>
63.<classname=”ClassB”table=”TABLE_B”>
64.<id/>
65.<propertyname=”b1”column=”B1”/>
66.<joined-subclassname=”ClassE”table=”TABLE_E”>
67.<keycolumn=”B_ID”/>
68.<propertyname=”e1”column=”E1”/>
69.<propertyname=”e2”column=”E2”/>
70.<propertyname=”e3”column=”E3”/>
71.<propertyname=”e4”column=”E4”/>
72.<propertyname=”e5”column=”E5”/>
73.<propertyname=”e6”column=”E6”/>
74.</joined-subclass>
75.<joined-subclassname=”ClassF”table=”TABLE_F”>
76.<keycolumn=”B_ID”/>
77.<propertyname=”f1”column=”F1”/>
78.<propertyname=”f2”column=”F2”/>
79.<propertyname=”f3”column=”F3”/>
80.<propertyname=”f4”column=”F4”/>
81.<propertyname=”f5”column=”F5”/>
82.<propertyname=”f6”column=”F6”/>
83.<propertyname=”f7”column=”F7”/>
84.</joined-subclass>
85.</class>
86.</hibernate-mapping>
5、映射Bag,List和Map
IDBag
Java代码
1.IMAGES{ID(PK),CUSTOMER_ID(FK),FILENAME}
2.Listimages=newArrayList();
3.Customer.hbm.xml
4.
5.<idbagname=”images”table=”IMAGES”lazy=”true”>
6.<collection-idtype=”long”column=”ID”>
7.<generatorclass=”increment”/>
8.</collection-id>
9.<keycolumn=”CUSTOMER_ID”/>
10.<elementcolumn=”FILENAME”type=”string”not-null=”true”/>
11.</idbag>
List
Java代码
1.IMAGES{CUSTOMER_ID(PK/FK),POSITION(PK),FILENAME}
2.Listimages=newArrayList();
3.Customer.hbm.xml
4.<listname=”images”table=”IMAGES”lazy=”true”>
5.<indexcolumn=”POSITION”/>
6.<keycolumn=”CUSTOMER_ID”/>
7.<elementcolumn=”FILENAME”type=”string”not-null=”true”/>
8.</list>
Map
Java代码
1.IMAGES{CUSTOMER_ID(PK/FK),IMAGE_NAME(PK),FILENAME}
2.Mapimages=newHashMap();
3.<mapname=”images”table=”IMAGES”lazy=”true”>
4.<keycolumn=”CUSTOMER_ID”/>
5.<indexcolumn=”IMAGE_NAME”type=”string”/>
6.<elementcolumn=”FILENAME”type=”string”not-null=”true”/>
7.</map>
8.
9.Setidbagmap支持数据库排序orderby=”ID”
10.Setmap支持内存排序sort=“MyComparator”
6、映射一对一关联关系特殊情况一
Java代码
1.PublicclassCustomer{
2.AddresshomeAddress;
3.AddresscomAddress;
4.}
5.
6.Customer.hbm.xml
7.<many-to-onename=”homeAddress”class=”Address”column=”HOME_ADDRESS_ID”cascade=”all”unique=”true”/>
8.<many-to-onename=”comAddress”class=”Address”column=”COM_ADDRESS_ID”cascade=”all”unique=”true”/>
9.
10.Address.hbm.xml
11.<one-to-onename=”address”class=”Customer”property-ref=”homeAddress”/>
映射一对一关联关系主键映射
Java代码
1.Customer.hbm.xml
2.<one-to-onename=”address”class=”Address”cascade=”all”/>
3.Address.hbm.xml
4.<classname=”address”>
5.<id>
6.<generatorclass=”foreign”>
7.<paramname=”property”>customer</param>
8.</generator>
9.</id>
10.<one-to-onename=”customer”class=”Customer”constrained=”true”/>
11.</class>
7、映射一对多关联
Java代码
1.<classname="Person">
2.<idname="id"column="personId">
3.<generatorclass="native"/>
4.</id>
5.<many-to-onename="address"column="addressId"not-null="true"/>
6.</class>
7.
8.<classname="Address">
9.<idname="id"column="addressId">
10.<generatorclass="native"/>
11.</id>
12.<setname="people"inverse="true">
13.<keycolumn="addressId"/>
14.<one-to-manyclass="Person"/>
15.</set>
16.</class>
8、映射多对多关联
Java代码
1.<setname=”items”table=”CATEGORY_ITEM”lazy=”true”cascade=”save-update”>
2.<keycolumn=”CATEGORY_ID”>
3.<many-to-manyclass=”Item”column=”ITEM_ID”/>
4.</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缓存
Selectc.ID,c.Name,c.age,o.ORDER_NUM,o.CUSTOMER_IDfromCustomerc,innerjoinc.ordersc除外。
SessionFactory缓存(二级缓存)
Java代码
1.<classname=”Category”table=”CATEGORYS”>
2.<cacheusage=”read-write”/>
3.<id/>
4.<setname=”items”inverse=”true”lazy=”true”>
5.<cacheusage=”read-write”/>
6.<key…/>
7.</set>
8.</class>
9.<classname=”Item”>
10.<cacheusage=”read-write”/>
11.<id/>
12.</class>
13.
14.Hibernate.cache.provider=…………EhCacheProvider
15.Hibernate.cache.user_query_cache=true
16.
17.Ehcache.xml
18.<ehcache>
19.<diskStorepath=”c:\\temp”/>
20.<defaultCache
21.maxElementsInMemory=”10000”
22.eternal=”false”
23.timeToIdleSeconds=”120”
24.timeToLiveSeconds=”120”
25.overflowToDisk=”true”/>
26.<cachename=”Category”
27.maxElementsInMemory=”10000”
28.eternal=”false”
29.timeToIdleSeconds=”120”
30.timeToLiveSeconds=”120”
31.overflowToDisk=”true”/>
32.
33.<cachename=”Category.Items”
34.maxElementsInMemory=”10000”
35.eternal=”false”
36.timeToIdleSeconds=”120”
37.timeToLiveSeconds=”120”
38.overflowToDisk=”true”/>
39.
40.<cachename=”Item”
41.maxElementsInMemory=”10000”
42.eternal=”false”
43.timeToIdleSeconds=”120”
44.timeToLiveSeconds=”120”
45.overflowToDisk=”true”/>
46.
47.<cachename=”customerQueries”…./><!—设置查询缓存
48.
49.</ehcache>
Queryq=session.createQuery();
q.setCacheable(true);
q.setCacheRegion(“customerQueries”);
SessionFactory.evict(),SessionFactory.evictCollection()清除二级缓存。
直接调用JDBCAPI不会使用任何缓存。
二级缓存适合查询较多但是很少更新的情况。
尽量对数据库的所有操作由Hibernate来完成,而不要用其它方式对数据库进行操作,否则可能与缓存冲突,当然如果对缓存有深入研究的除外。
五、临时对象(TransientObject)、持久对象(PersistentObject)和游离对象(DetachedObject)
临时对象:表示对象的主键不存在(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-onename=”customer”class=”Customer”constrained=”true”/>
HQL会忽略迫切左外连接检索和lazy(只有load才为代理对象)策略。
Session.find(“fromCustomercascleftjoinfetchc.orderswherec.id=1”)
Hibernate的检索方式
HQL、NativeSql和QBC
FromCustomercinnerjoinc.orderso查询结果保存到session缓存
Selectc.ID,c.Name,c.age,o.ORDER_NUM,o.CUSTOMER_IDfromCustomerc,innerjoinc.ordersc查询结果不存入Session缓存。
七、Hibernate并发控制
乐观锁:VERSION或者timestamp控制,session.lock()立刻进行版本检查,session.update(),update的时候执行版本检查。
悲观锁:selectforupload,session.get(Customer.class,newLong(1),LockMode.UPGRADE)
总结:本文绝大多数为摘录内容,有些地方加上自己的理解,有不对之处恳请批评指正。看了书,阅读了相关帖子后,感觉学习Hibernate的重点应该是Hibernate的缓存策、查询和如何提高性能方面。
另外说点自己的感受,本人做项目到现在都是在设计阶段先有关系模型后有对象模型(其实一个Table一个对象),在这种情况下Hibernate的优势大大降低了,其实是为了Hibernate而Hibernate了,个人感觉在先有关系模型的情况下用Hibernate的意义不大。
如果按照OOAD的开发流程先有对象模型,然后根据对象模型生成关系模型,那应该说用Hibernate用对了地方。毕竟Hibernate对继承、多态,各种复杂的关系都有很好的支持。