您的位置:首页 > 其它

传智播客--hibernate关系映射和性能优化(徐培成)

2009-12-31 22:11 183 查看
今天学习到了 hibernate 中的关键地方了,对象之间的关系和映射文件的配置和编写.Hibernate的学习主要就是学习映射文件.映射文件是
Java 对象和关系型数据库之间的桥梁.通过配置文件对 Java
对象进行配置就是要映射出表与表之间的关系.听懂很容易,要想用好就不是那么容易的事情了.好好总结一下今天学习到的知识吧.

1.一对多

<set name=“orders”

cascade=“save-update”>

<key
column=“CUSTOMER_ID” />

<one-to-many
class=“..Order” />

</set>

属性注释:

name:设定待映射持久化类的属性名。

cascade:设定级联操作的程度。

key 子属性:设定与所关联的持久化类对应的标的外键。

one-to-many子属性:设定所关联的持久化类。

总结:

在一对多的时候,属性声明成Set还是List呢?

Set是不容许有重复,插入元素无序.

List是容许有重复,插入元素有序.

用List有重复元素,在插入的时候有插入数据重复提示.所以,要声明成Set.

使用一对多的时候,要慎重,效率很低.

通常在定义集合属性时,直接初始化为一个实现类的实例。 private Set orders = new HashSet(); 可避免空指针异常.

在映射一对多的双向关联关系时,应该在one方把inverse属性设为true,这可以提高性能。

在建立两个对象的关联时,应该同时修改关联两端的相应属性:

Customer.getOrders().add(order);

Order.setCustomer(customer);

这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修
改关联两端的对象的相应属性:

Customer.getOrders().remove(order);

Order.setCustomer(null);

2.多对一

<class name="Order"
table="hib_orders" lazy="false">

<id name="id" column="id"
type="integer">

<generator
class="identity" />

</id>

<property name="orderNo"
column="orderno" type="string" length="15" />

<property name="price"
column="price" type="float" />

<!-- 映射多对一关联关系 -->

<many-to-one
name="customer" column="cid" class="Customer" cascade="save-update"
/>

</class>

总结:

就的一对多,从另外一个角度看. 这个关系是经常用到的.

属性中不用private Department depart;这个而用private int
pepartid;也是可以的,但这就不能发挥Hibernate的优势了

在维护关系上,常是用这个多的一端来维护,这样和数据库交换的少,可以大大的提高系统的性能.

这里会有一个问题,注意使用数据的位置,涉及到了懒加载的问题.

通过Hibernate.initialize(emp.getDepart());来解决这个问题.这里是强制它查询数据库,给对象进行初始化.

3.一对一

一对一分两种情况

1)外键:多对一的特例,将不能重复设置成真.

<!-- 影射一对一外键关联用many-to-one进行模拟,增加唯一性约束 -->

<many-to-one name="addr"
column="aid" class="AddrFk" unique="true" />

<one-to-one name="user"
property-ref="addr"/>

2)主键

<!-- 影射一对一主键关联 -->

<one-to-one name="addr"
class="AddrPk" />

<class name="AddrPk"
table="hib_addrpks" lazy="false">

<id name="id" column="id"
type="integer">

<generator
class="foreign">

<param
name="property">user</param>

</generator>

</id>

<property name="province"
column="province" type="string" length="20" />

<property name="city"
column="city" type="string" length="20" />

<one-to-one name="user"
class="UserPk" constrained="true"/>

</class>

4.多对多

<!-- 影射多对多关联 -->

<set name="teas"
table="hib_tea_stu_links" lazy="false" inverse="true">

<key column="sid" />

<many-to-many class="Tea"
column="tid" />

</set>

<!-- 影射多对多关联 -->

<set name="stus"
table="hib_tea_stu_links" lazy="false">

<key column="tid" />

<many-to-many class="Stu"
column="sid" />

</set>

总结:

多对多的时候,会产生一个中间表.用来维护表之间的关联关系.

并要明确的指定中间表的名字.

5.session

session的缓存:当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象
仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。

缓存的作用:

尽量减少访问数据库的次数,提高系统的效率.

保证缓存中的对象与数据库中的相关记录保持同步。

当session加载了customer对象后,会为customer对象的值类型的属性复制一份快照。当清理缓存时,通过比较对象的当前属性和快照,来
判断对象的那些属性发生了变化。

Session 清理缓存执行sql语句的顺序:

按照应用程序调用save()方法的先后顺序,执行所有的对实体进行插入的insert语句。

所有对实体进行更新的update语句。

所有对实体进行删除的delete语句。

所有对集合元素进行删除、更新或插入的sql语句。

执行所有对集合进行插入的insert语句。

按照应用程序调用delete()方法的先后执行。

6.inverse:

让一的一端, 集合端,放弃更新,放弃维护关系.默认是关闭的.

<set>元素的inverse属性

Hibernate会自动清理缓存中的所有持久化对象,按照持久化对象的改变来同步更新数据库,因此执行了上述的两条更新语句。重复执行多余的sql语句
会影响java性能,解决这也问题的办法是把<set>元素的inverse属性设为true,该属性的默认值是false。

在映射一对多的双向关联关系时,应该在one 方把inverse属性设为true,这可以提高性能。

在建立两个对象的关联时,应该同时修改关联两端的相应属性:

Customer.getOrders().add(order);

Order.setCustomer(customer);

这样才会使程序更加健壮,提高业务逻辑层的独立性,使业务逻辑层的程序代码不受Hibernate实现类的影响。同理,当删除双向关联的关系时,也应该修
改关联两端的对象的相应属性:

Customer.getOrders().remove(order);

Order.setCustomer(null);

7.cascade

这个属性要小心设置,否则因为错误的设置对系统数据的破换性很大,不容易恢复.

Customer customer = (Customer)
s.load(Customer.class,new Long(2));

Session.delete(customer);

tx.commit();

如果cascade属性取默认值none,不会自动删除和customer关联的其他持久化对象。如果希望删除customer时,自动删除和
customer关联的order对象,可把cascade属性设为delete。

<set name=“orders”
cascade=“delete” inverse=“true”>

<key
column=“CUSTOMER_ID” />

<one-to-many
class=“mypack.Order” />

</set>

再运行删除方法的时候,会自动删除order对象.

8.父子关系

就是父方来控制子方的持久化生命周期,子方对象必须和一个父方对象关联。

当customer.hbm.xml
的<set>元素的cascade属性取值为all-delete-orphan,Hibernate会按照如下方式处理customer对
象:

当保存或更新customer对象时,级联保存或更新所有关联的order对象,相当于save-update.

当删除 customer对象时,级联删除所有的order对象,相当于delete。

删除不再和customer对象关联的所有order对象。当关联双方存在父子关系时,就可以把父方的cascade属性设为
all-delete-orphan.

9.这几个方法的不同之处:

commit() 先调用flush方法,然后提交事务。提交事务意味着对数据库操作永久保存下来。

flush()清理,刷出;不提交,就能回滚 和 s.setFlushMode()的设置讲解

refresh()刷新缓存;数据库→缓存

clear()清空缓存内容.

10.hibernate
中java对象的状态

1)持久化对象

位于一个session缓存中,总是被一个session关联。持久化对象和数据库记录相对应。清理缓存时,会根据对象属性变化,同步更新数据库。
save把临时对象转变为持久化对象。load或find或get返回的对象总是持久化状态。find方法返回的list存放的都是持久化对象。
update、save、SaveOrUpdate和Lock方法使游离对象装变为持久化对象。在实际的应用程序中应该避免一个java对象被多个
session实例关联,会导致重复执行sql语句,并且极容易出现一些并发问题。

2)游离对象

不再位于
session的缓存中,游离对象不被session关联。游离对象由持久化转变过来的,因此在数据库中可能还存在与它对应的记录(前提条件是没有其他程
序删除了这条记录)。

3)临时对象
:

刚刚被new出来的对象,还没有和session有任何操作.

11.unsaved-
value 和 s.saveOrUpdate()

Hibernate是怎么区分是保存还是更新呢.unsaved-value就是用来区分是不是被保存过.Hibernate中用对象表示符(OID)来
区分对象.

12.s.load()和
s.get()的区别.

load()是在需要数据的时候才访问数据库.

get()是执行了就马上访问数据库.

13.检索策略 lazy的配置

这个很重点,对系统的性能优化和提升有很大的帮助.

一对多和多对多关联的检索策略有:立即检索,延迟检索,批量延迟检索,批量立即检索,迫切左外连接检索

总结:

联合主键不推荐使用,Hibernate中有联合主键,其官方的说法是为了适应已经存在的老系统.

debug 的使用,调试的表达式里不要有表达式.调试进程要有一个进程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: