cascade持久化 <o:p></o:p>
在Java程序中,对象与对象之间会透过某些关系互相参考,如果有一个对象已经是持久化对象,被它参考的对象直觉上也应该要持久化,以维持对象之间关联的完整性,这是藉由可达性完成持久化(Persistence by reachability)的基本概念。
如果将对象之间的关联想象为一个树形图,从某一个持久化物件为树根出发,父节点若是持久化对象,则被父节点参考到的子节点应自动持久化,而另一方面,如果有一子节点没办法藉由任何的父节点来参考至它,则它没有被持久化的需求,它应从数据库中加以删除。
Hibernate并没有完全实现以上的概念,它让使用者自行决定自动持久化的方式,当对象之间被指定关联(例如多对一、一对多等),您可以决定被持久化对象关联的暂存对象是否进行自动持久化与如何自动持久化。
以之前「多对一实体映像」主题为例,之前我们在设定好User类别中的Room属性之后,我们分别要对Room与User进行save(),在对象的关 系图上,基本上我们应实现的是储存User,而Room的持久化应自动完成,而不用我们再特地指定,为了达到这个目的,我们在映射多对一关系时可以使用 cascade来指定自动持久化的方式,例如修改User.hbm.xml为: <o:p></o:p>
User.hbm.xml<o:p></o:p>
<many-to-one name="room"></many-to-one>
column="ROOM_ID"<o:p></o:p>
class="onlyfun.caterpillar.Room"<o:p></o:p>
cascade="save-update"/><o:p></o:p>
预设上cascade是none,也就是不进行自动持久化,所以预设上我们必须对每一个要持久化的对象进行save(),在上面我们指定了cascade为save-update,这表示当我们储存或更新User时,自动对其所关联到的Room(暂时)对象进行持久化。
这边要注意的是,使用cascade自动持久化时,会先检查被关联对象的id属性,未被持久化的对象之id属性是由unsaved-value决定,预设 是null,如果您使用long这样的原生型态(primitive type)时,则必须自行指定默认值,所以在「多对一实体映像」的Room.hbm.xml的id映像上,我们必须改为: <o:p></o:p>
Room.hbm.xml<o:p></o:p>
<id name="id" unsaved-value="0" column="ROOM_ID"></id><o:p></o:p>
<generator class="increment"></generator><o:p></o:p>
<o:p></o:p>
修改映像文件之后,我们可以使用以下的方式来储存数据: <o:p></o:p>
HibernateTest.java<o:p></o:p>
import onlyfun.caterpillar.*;<o:p></o:p>
import net.sf.hibernate.*;<o:p></o:p>
import net.sf.hibernate.cfg.*;<o:p></o:p>
<o:p> </o:p>
public class HibernateTest {<o:p></o:p>
public static void main(String[] args) throws HibernateException {<o:p></o:p>
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();<o:p></o:p>
<o:p></o:p>
Room room1 = new Room();<o:p></o:p>
room1.setAddress("NTU-M8-419");<o:p></o:p>
<o:p></o:p>
User user1 = new User();<o:p></o:p>
user1.setName("bush");<o:p></o:p>
user1.setRoom(room1);<o:p></o:p>
<o:p></o:p>
User user2 = new User();<o:p></o:p>
user2.setName("caterpillar");<o:p></o:p>
user2.setRoom(room1);<o:p></o:p>
<o:p></o:p>
Session session = sessionFactory.openSession();<o:p></o:p>
Transaction tx= session.beginTransaction();<o:p></o:p>
<o:p></o:p>
session.save(user1);<o:p></o:p>
session.save(user2);<o:p></o:p>
<o:p> </o:p>
tx.commit();<o:p></o:p>
session.close();<o:p></o:p>
<o:p> </o:p>
sessionFactory.close();<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
这次我们不用特地储存room了,透过cascade设定为save-update,被User关联到的对象,在储存或更新时,都会自动持久化,之后我们甚至可以如下来进行对象储存: <o:p></o:p>
Transaction tx = session.beginTransaction();<o:p></o:p>
User user = (User) session.get(User.class, new Long(1));<o:p></o:p>
Room room = new Room();<o:p></o:p>
room.setAddress("NTU-M5-105");<o:p></o:p>
user.setRoom(room);<o:p></o:p>
tx.commit();<o:p></o:p>
session.close();<o:p></o:p>
cascade的指定除了save-update之外,还可以使用delete、all、all-delete- orphan、delete- orphan,各个设定的作用,建议您查看参考手册9.8Lifecyles and object graphs,当中有详细的说明,而有关于可达性完成持久化(Persistence by reachability)的说明,可以参考Hibernate in Action的4.3。 <o:p></o:p>