`
tigers20010
  • 浏览: 47547 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

传智播客—hibernate关系映射 三(转载)

阅读更多

1).级联添加:

我们有设置order的映射文件的many-to-one,在此我们也必须设置customerset元素:

<set name="orders" cascade="save-update" lazy="false">

    <key><column name="cid"></column></key>

    <one-to-many class="cn.itcast.cc.hibernate.persistence.Order"/>

</set>

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

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

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

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

我们可以设置cascade的值为“delete”这样在删除一个客时,也可以自动删除与客户级联的orders

cascade属性值

描述

none

忽略关联对象,默认值

save-update

保存或更新当前对象时,级联保存关联的临时对象,更新关联的游离对象。

delete

删除对象时,级联删除关联的对象。

all

包含save-updatedelete的行为。

delete-orphan

删除所有和当前对象解除关联关系的对象。

all-delete-orphan

包含alldelete-orphan的行为。

 

添加代码:

customer.getOrders().add(order);

此时我们只保存customerorder对象,hibernate都可以将两个对象的数据保存到对应的表中。

注意:如果映射文件没有设置“cascade="save-update"”属性,则保存失败并抛异常!

 

2).级联删除:

         我们调用session.delete(customer);方法时会一同删除customer对象的orders吗?不会!如果我们希望能够删除,我们必须设置Set元素的属性:cascade="delete"

         那如果我删除一个order,能自动删除对应的customer吗?你想可以吗?这本身就不符合业务逻辑!

 

3).Set集合的inverse属性:

这个属性十分重要,涉及到hibernate缓存监控技术。(hibernate缓存监控技术在后面会有介绍)。Inverse属性使得,如果持久化对象一旦发生改变就自动更新数据表中的记录。(持久化对象后面会有介绍)通过loadsaveupdate返回或设置的对象都是持久化对象,这些对象一起发生改变,比如set了一个新值,hibernate就会自动将新值更新到数据库中。当调用了session.close方法是,这些持久化对象就不存在了!

 

结论:

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

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

   Customer.getOrders().add(order);

   Order.setCustomer(customer);

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

Customer.getOrders().remove(order);

Order.setCustomer(null);

 

一对一关联与多对多关联,我在此就不做总结了。把多对一和一对多搞明白了,这些就容易了!

 

四、操纵持久化对象

         hibernate中有三个缓存:一个是普通的SessionFactory的缓存,用来存储映射文件和SQL查询语句。一个是Session的缓存(一级缓存)用来存放持久化对象。一个是二级缓存(这个还没学)。

 

         操纵持久化对象,玩的就是一级缓存。Session接口提供saveupdatedeleteloadget方法,这些方法设置或读取的对象被保存在一级缓存中,这些对象被称为持久化对象。我们前边提到的所有持久化对象,必须是保存在缓存中的对象。

 

1.JAVA对象在JVM中的生命周期

         我们知道JAVA有自己的垃圾回收器机制,当一个对象不再被直接或间接的引用时,它就是垃圾对象。垃圾回收会将它释放掉。我们new出来的java对象被放在堆中,而对象的引用放在栈中。创建一个java对象JVM需要做三步,比如 String str = new String();

1.        new String()对象放在堆中。

2.        str放在栈中。

3.        str指向堆中的对象。

 

如:

1.        String str1 = new String();

2.        String str2 = str1;

3.        str1 = null;

4.        str2 = null;

请问放在堆中的对象何时被销毁?第三步吗?No!是第四步。这个对象从第1步“出生”,到第4步执行结束后“死亡”。

 

2.理解session的缓存

         持久化对象被保存在缓存里,这么做有什么好处?

1.        减少访问数据库的频率。

2.        保证缓存中的对象与数据库中的记录保存同步。(监控技术)

3.        当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循,还以及由死循环引起的JVM堆栈溢出异常。

监控技术是如何实现的?session保存在缓存中的持久化对象,实质上是保存了对象的引用。那么同时与这个引用对应一个持久化对象的clone对象。Session监控就是将持久化对象与在缓存中的clone对象进行对比,如果发生改变就自动对数据库进行相应的操作。这样就保持了持久化对象与数据库记录的同步。

 

Session在清理缓存时,按照以下顺序执行sql语句。

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

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

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

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

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

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

默认情况下:

1.当应用程序commit()方法的时候,先清理缓存,然后在向数据库提交事务。

2.当调用find()iterator()时,如果对象属性发生变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态。

3.显式调用flush()

 

3.操作Session缓存的重要方法:

Session的清理模式:“session.setFlushMode(FlushMode.AUTO);

清理缓存的模式

Session的查询方法

事务的commit()

SessionFlush()

FlushMode.AUTO

清理

清理

清理

FlushMode.COMMIT

不清理

清理

清理

FLushMode.NEVER

不清理

不清理

清理

FlushMode.NEVER 模式受主键影响,当主键为identity时,受底层数据库影响所以NEVER无效。如果为increment时,由于这个主键不受底层数据库的影响,所以NEVER有效!

 

清理方法:

Session.flush();//清理、刷出数据库与缓存同步,但不提交事务。

Session.refresh();//刷新。让缓存与数据库同步。

Session.clear();//清空。清空缓存中的引用。

 

4.hibernateJava对象的状态:

临时状态(transient):用new语句创建,没有被持久化(没有调用Session对方法),不处于session中,该对象成为临时对象。

持久化状态(persistent):已经被持久化,加入到session的缓存中。该状态的对象为持久化对象。

游离状态(detached):已经被持久化,但不处于session中(seesion清空或被delete)。该状态的对象为游离对象。

如:

程序代码

生命周期

状态

tx = session.beginTransaction();

Customer c = new Customer(“Tom”,new HashSet);

开始生命周期

临时状态

Session.save(c)

处于生命周期中

转变为持久化状态

Long id=c.getId();

c = null;

Customer c2 = (Customer)session.load(Customer.class,id);

tx.commit();

处于生命周期中

处于持久化状态

session.close();

处于生命周期中

转变为游离态

c2,getName();

处于生命周期中

处于游离态

c2 = null;

结束生命周期

结束生命周期

1).临时对象特征

l          不处于session中,不被任何session关联。

l          数据库中没有对应的记录。

l          以下情况,对象进入临时状态:

1.          new语句刚创建了一个对象。

2.          sessiondelete方法使持久化对象或游离对象转变为临时对象,对于游离对象,该方法从数据库中删除记录,对于持久化对象,该方法从数据库中删除记录,还要删除缓存中的对象。

 

临时对象判断法:

1.OIDnull

2.具有version属性并取值为null

3.在映射文件中为<id>元素设置了unsaved-value属性,并且OID属性取值与属性匹配。

4.在映射文件中为<version>元素设置了unsaved-value属性,并且version属性取值与属性匹配。

5.自定义了Interceptor实现类,并且isUnsaved方法返回Boolean.true。如果id的类型为long,则默认值为0,此时需要在配置文件中设置idunsaved-value0

 

 

2) . 持久化对象特征

l          位于一个session缓存中,总是被一个session关联。

l          持久化对象和数据库记录相对应。

l          清理缓存时,会根据对象属性变化,同步更新数据库。

l          save把临时对象转变为持久化对象。

l          loadfindget返回的对象总是持久化状态。

l          find方法返回的list存放的都是持久化对象。

l          updatesaveSaveOrUpdateLock方法使游离对象装变为持久化对象。

 

clip_image001          在实际的应用程序中应该避免一个java对象被多个session实例关联,会导致重复执行sql语句,并且极容易出现一些并发问题。

 

3).游离对象特征

l          不再位于session的缓存中,游离对象不被session关联。

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

l          close方法使缓存被清空,缓存中的所有的对象都变为游离对象。如果没有引用他们的话,他们就会结束生命周期。

l          evict方法从缓存中删除一个持久化对象,使他变为游离态对象。当缓存中保存了大量的持久      化对象时,会消耗许多内存空间,使用该方法删掉一些对象来节省空间。

 

5.操作持久化对象的方法

         1).save

l          对象加入缓存,成为持久化对象。

 

2). update

l          将游离对象转变为持久化对象。不论对象属性是否发生变化,该方法都会执行update操作。如果希望仅当属性变化时才执行update语句的话可进行如下配置:

                 <class name=“…”

            table=“…”

            select-before-update=“true”> 

        

3). saveOrUpdate

l          该方法同时包含saveupdate方法,如果参数是临时对象就用save方法,如果是游离对象就用update方法,如果是持久化对象就直接返回。

 

4) .loadget

l          从数据库加载指定的OID持久化对象。

l          如果数据库中不存在该记录时,load方法会抛出异常,而get方法返回null

 

5). delete

l          如果参数是持久化对象,就执行一个delete语句。若为游离对象,先使游离对象被session关联,使他变为持久化对象,然后计划执行一个delete语句。

 

6.与触发器协同工作

         触发器的行为导致缓存与数据库中的数据不一致。解决办法是执行完操作后,立即调用sessionflush方法和refresh方法,迫使缓存与数据库同步。

Sessionupdate操作方法盲目的激活触发器,如果游离状态的对象的属性和数据库一致,则更新操作是多余的。

<spa

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics