Hibernate 级联关系说明 - 关于cascade和inverse的用法
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"><hibernate-mapping package="org.hibernate.auction"> <class name="TestA" table="TestA" dynamic-update="true" dynamic-insert="true" > <id name="id" column="id" type="int" unsaved-value="any" > <generator type="java.lang.String" update="true" insert="true" column="name" /> <set name="testBs" table="TestA_TestB" inverse="false" cascade="all"> <key column="testA"/> <many-to-many column="testB" /> </set> </class> <class name="TestB" table="TestB" dynamic-update="true" dynamic-insert="true" > <id name="id" column="id" type="int" unsaved-value="any" > <generator type="java.lang.String" update="true" insert="true" column="name" /> <set name="testAs" table="TestA_TestB" inverse="true" cascade="all"> <key column="testB"/> <many-to-many column="testA" /> </set> </class> </hibernate-mapping>
?
在对多对中,因为一端维护关系另一端不维护关系的原因,我们必须注意避免在应用中用不维护关系的类建立关系,因为这样建立的关系是不会在数据库中存储的。基于上面的映射文件代码给出一个例子:
package org.hibernate.auction;import java.util.*;/** * @author Administrator * * To change the template for this generated type comment go to * Window>Preferences>Java>Code Generation>Code and Comments */public class TestA { int id; String name; Set testBs=new HashSet(); public TestA(){ } public TestA(int id){ setId(id); } public int getId(){ return id; } public void setId(int id){ this.id=id; } public String getName(){ return name; } public void setName(String name){ this.name=name; } public Set getTestBs(){ return testBs; } public void setTestBs(Set s){ testBs=s; } public void addTestB(TestB tb){ testBs.add(tb); } public static void main(String[] args) { }}public class TestB { int id; String name; Set testAs=new HashSet(); public TestB(){ } public TestB(int id){ setId(id); } public int getId(){ return id; } public void setId(int id){ this.id=id; } public String getName(){ return name; } public void setName(String name){ this.name=name; } public Set getTestAs(){ return testAs; } public void setTestAs(Set s){ testAs=s; } public void addTestA(TestA ta){ testAs.add(ta); } public static void main(String[] args) { }}
?测试代码:
public void doTest() throws Exception{ TestA a1=new TestA(1); TestA a2=new TestA(2); TestA a3=new TestA(3); TestB b1=new TestB(1); TestB b2=new TestB(2); TestB b3=new TestB(3); a1.addTestB(b1); a1.addTestB(b2); a1.addTestB(b3); b2.addTestA(a1); b2.addTestA(a2); Session s = factory.openSession(); s = factory.openSession(); Session session = factory.openSession(); session.save(a1); session.flush(); session.close(); }
?测试后连接表的数据为:
testa????????????? testb
1????????????????? 1
1????????????????? 2
1????????????????? 3
根据inverse规则,对这些代码:b2.addTestA(a1);? b2.addTestA(a2); 建立的关系,数据库并没有存储下来,因为TestB没有责任维护这些关系,所以产生的sql语句自然不会有针对Testa_testB表的操作了。假设应 用中真的需要这些方法,那么我们可以修改TestB的方法,让他们注意在维护端类中执行相应的操作以使得关系能够在数据库中保存下来,更改TestB如 下:
/* * Created on 2004-7-25 * * To change the template for this generated file go to * Window>Preferences>Java>Code Generation>Code and Comments */package org.hibernate.auction;import java.util.*;/** * @author Administrator * * To change the template for this generated type comment go to * Window>Preferences>Java>Code Generation>Code and Comments */public class TestB { int id; String name; Set testAs=new HashSet(); public TestB(){ } public TestB(int id){ setId(id); } public int getId(){ return id; } public void setId(int id){ this.id=id; } public String getName(){ return name; } public void setName(String name){ this.name=name; } public Set getTestAs(){ return testAs; } public void setTestAs(Set s){ testAs=s; } public void addTestA(TestA ta){ testAs.add(ta); ta.addTestB(this); } public static void main(String[] args) { }}
?那么测试执行后连接表的数据为:
testa????????? testb
1?????????????? 2
1?????????????? 3
1??????????????? 1
2???????????????? 2
测试通过。
附 hibernate cascade备忘 :
当关联双方存在父子关系,就可以在 set 处设定 cascade 为 all-delete-orphan
所谓父子关系,即指由父方控制子方的持久化圣明周期,子方对象必须和一个父方对象关联。如果删除父方对象,应该级联删除所有关联的子方对象;如果一个子方对象不再和一个父方对象关联,应该把这个子方对象删除。
all-deleteorphan 的能力:
1. 当保存或更新父方对象时,级联保存或更新所有关联的子方对象,相当于 cascade 为 save-update
2. 当删除父方对象时,级联删除所有关联的子方对象,相当于 cascade 为 delete
3. 删除不再和父方对象关联的所有子方对象
解除父子关系的 java 语句例如:
customer.getOrders().remove(order);
order.setCustomer(null);
tx.commit();
如果 cascade 属性取默认值 null,当解除父子关系时,会执行如下 sql:
update ORDER set CUSTOMER_ID=null where ID=2
inverse 设定的原则:
1. 在映射一对多双向关联关系时,应该设定 many 方的 inverse 为 true,以提高性能
2. 在建立两个对象的双向关联时,应同时修改关联两端的对象的相应属性:
1)customer.getOrders().add(order);
2)order.setCustomer(customer);
如果不执行 1)而仅执行 2),由于 set 元素的 inverse 为 true,因此 hibernate 不会按照 CUSTOMER 对象的状态变化来同步数据库。
inverse 解决性能问题的例子:
1. 建立 Order 到 Customer 的多对一关联关系
order.setCustomer(customer);
相应执行的 SQL 为:
update ORDERS set ORDER_NUMBER='Jack_Order001', CUSTOMER_ID=2 where ID=2;
2. 建立 Customer 到 Order 的一对多关系
customer ORDERS set CUSTOMER_ID=2 where ID=2;
相应 SQL 为:
update ORDERS set CUSTOMER_ID=2 where ID=2;
显然 1 和 2 的 SQL 功能重复了,反复执行这样的 SQL 语句会引起性能下降,因此:
inverse 设定为 true 时,声明 Customer 端的关联只是 Order 端关联的镜像。当两者状态发生变化时,Hibernate 仅按照 Order 对象状态变化来同步数据库。即仅会执行以下 SQL:
update ORDERS set ORDER_NUMBER='Jack_Order001', CUSTOME_ID=2 where ID=2;
Customer.hbm.xml 片段如下:
<set
name="orders"
cascade="all-delete-orphan"
inverse="true"
>
<key column="CUSTOMER_ID" />
<one-to-many />
</set>
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qianyin84/archive/2008/03/26/2219113.aspx
?
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/qiujiaqun/archive/2009/07/25/4379185.aspx