`
ghsea
  • 浏览: 112524 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

级联策略

阅读更多
    Session的文档中将一个对象的状态分为三种:
transient: never persistent, not associated with any Session(临时态)
persistent: associated with a unique Session(持久态)
detached(分开的,分离的): previously persistent, not associated with any Session
下面给出了一个对象的从一个临时态到数据库的过程:
     临时态(一块单独的内存)——>持久态(Session的内存)——>永久性数据(数据库)
    
    对于第一种,通常是我们通过new得到的对象,它与任何Session均无关系,对于第二种,是与一个Session相关联的对象,如被Session执行save()后的对象(但是还没有被commit()到数据库中),第三种,是以前曾被持久化的,但是与
Session解除关系了的。
看这样一个实例,其映射文件如下
  1. <hibernate-mapping>  
  2.     <class name="hello.Message" table="message">  
  3.        <id name="id" column="id">  
  4.          <generator class="native"/>  
  5.        </id>  
  6.          
  7.        <property name="text" column="text"/>  
  8.        <many-to-one name="nextMessage"   column="next_id" />  
  9.          
  10.     </class>  
  11. </hibernate-mapping>  
   
 在进行实验时,数据库的表中有样的记录:
  1.    +------+---------------------------+------------
       |id    |        text               |next_id    |
       +------+---------------------------+-----------+
       |2     |      Greeting             |  4        |
       |4     |   take me to your leader  |  null     |
       +------+---------------------------+-----------+


1.级联保存和更新:
  代码A
  1. Message ms=(Message)session.load(Message.classnew Long(2));  
  2. ms.setText("Greeting");  
  3. Message m=new Message("take me to your leader");  
  4. ms.setNextMessage(m);  
  5. //session.save(m);  
  6. tx.commit();  
  7. session.close();  
      
       我们已经知道,Session执行save(),delete()等方法只是改变与从Session中删除或向Session中保存对象,而commit()是根据Session的状态执行向数据库的持久化工作。为证明这一点,我们执行以下操作:
代码B
  1. Message ms=(Message)session.load(Message.classnew Long(4));     
  2.  session.delete(ms);      
  3. //tx.commit();     
  4.  session.close();   

其结果为:
  1. Hibernate: select message0_.id as id0_0_, message0_.text as text0_0_,
  2. message0_.next_id as next3_0_0_ from message message0_ where message0_.id=?  
把注释取消,结果打印出异常
  1. Cannot delete or update a parent row: a foreign key constraint fails (`test/message`,
  2.  CONSTRAINT `FK_message_1` FOREIGN KEY (`next_id`) REFERENCES `message` (`id`))  
      可见,在未
commit()时,Hibernate并未执行数据库操作。
      那么现在我们知道了,对于代码A,由于未执行
session.save(m),对象m还只是一个临时对象,它还不能被保存到数据库中因此执行代码A后会抛出异常:org.hibernate.TransientObjectException,它表示tx在执行将ms保存到数据库时,需要同时保存m到数据库中,但是m是一个临时对象,这时我们有两种解决方法:
A.在配置文件中将cascade设为save-update,那么tx在保存ms时会级联保存临时对象
m
B.取消注释,显式地持久化
m

2.、级联删除:
   映射如下
  1. <many-to-one name="nextMessage"  cascade="delete"  column="next_id" />    
执行以下操作:
  1. Message ms=(Message)session.load(Message.classnew Long(2));     session.delete(ms);      
  2. //tx.commit();     
  3. session.close();   
执行结果为:
  1. Hibernate: select message0_.id as id0_0_, message0_.text as text0_0_,
  2.          message0_.next_id as next3_0_0_ from message message0_ where message0_.id=?  
  3. Hibernate: delete from message where id=?  
  4. Hibernate: delete from message where id=?  
      注意到了级联的方向吗?代码B在取消注释后即使不用级联,都会抛出异常,这是由外键约束决定的。考虑Customer和Order的实例,当删除
Customer时,我们可以而且应该级联删除Order,这是合理的,但是如果想删除一个作为Customer外键的Order是当然不行的。
  
    最后Hibernate默认不产生级联行为。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics