hibernate关系映射和性能优化(徐培成)

来源:互联网 发布:黑马程序员 java 编辑:程序博客网 时间:2024/05/16 09:20
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 的使用,调试的表达式里不要有表达式.调试进程要有一个进程
原创粉丝点击