Hibernate 之 cascade 和 inverse

来源:互联网 发布:淘宝正道体育 编辑:程序博客网 时间:2024/05/27 12:21

1、Inverse在一对多关系和多对多关系中被声明使用(在多对一中没有inverse关键字) 理解关键字:关系

"inverse",应该改成“relationship owner"吗?
在hibernate,只有“关系的拥有者”才能维护两个实体类之间的关联关系(一对多或多对多)。“inverse”关键字创建的目的是指明哪一边(实体类)是关系的拥有者。 然而“inverse”关键字生涩难懂,建议改为“relationship_owner”
总之,inverse=“true”说明当前配置文件对应的实体类不是关系的拥有者,而其对应的关联实体类是关系的拥有者(也就是inverse属性所在元素对应的集合变量引用的实体类为关系的拥有者),反之相反。

2、cascade属性的作用是描述关联对象进行操作时的级联特性。因此,只有涉及到关系的元素才有cascade属性。 理解关键字:级联

3、上示例代码:

背景描述:城市、学校、学生三个对象;全部是1对多的关系;即

TestCity.java

package com.test;import java.util.HashSet;import java.util.Set;/** * 测试-城市 * Created by zmf on 16/4/13. */public class TestCity {    private int id;    private String name;    private Set<TestSchool> schoolSet = new HashSet<TestSchool>();    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<TestSchool> getSchoolSet() {        return schoolSet;    }    public void setSchoolSet(Set<TestSchool> schoolSet) {        this.schoolSet = schoolSet;    }}

TestSchool.java

package com.test;import java.util.HashSet;import java.util.Set;/** * 测试-学校 * Created by zmf on 16/4/13. */public class TestSchool {    private int id;    private String name;    private Set<TestStudent> students = new HashSet<TestStudent>();    private TestCity city;    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<TestStudent> getStudents() {        return students;    }    public void setStudents(Set<TestStudent> students) {        this.students = students;    }    public TestCity getCity() {        return city;    }    public void setCity(TestCity city) {        this.city = city;    }}

TestStudent.java

package com.test;import java.util.HashSet;/** * 测试-学生 * Created by zmf on 16/4/13. */public class TestStudent {    private int id;    private String name;    private TestSchool school;    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 TestSchool getSchool() {        return school;    }    public void setSchool(TestSchool school) {        this.school = school;    }}

映射文件:

TestCity.hbm.xml

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!--     Mapping file autogenerated by MyEclipse - Hibernate Tools--><hibernate-mapping>    <class name="com.test.TestCity"><id name="id">            <generator class="identity" />        </id><property name="name"/><set name="schoolSet"><key column="city_id"></key><one-to-many class="com.test.TestSchool"></one-to-many></set>    </class></hibernate-mapping>

TestSchool.hbm.xml

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!--     Mapping file autogenerated by MyEclipse - Hibernate Tools--><hibernate-mapping>    <class name="com.test.TestSchool"><id name="id">            <generator class="identity" />        </id><property name="name"/><many-to-one name="city" column="city_id" class="com.test.TestCity"></many-to-one><set name="students"><key column="school_id"></key><one-to-many class="com.test.TestStudent"></one-to-many></set>    </class></hibernate-mapping>

TestStudent.hbm.xml

<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><!--     Mapping file autogenerated by MyEclipse - Hibernate Tools--><hibernate-mapping>    <class name="com.test.TestStudent"><id name="id">            <generator class="identity" />        </id><property name="name"/><many-to-one name="school" column="school_id" class="com.test.TestSchool"></many-to-one>    </class></hibernate-mapping>

测试代码

package com.test;import com.util.HibernateSessionFactory;public class TestInverseAndCascade {public static void main(String[] args) {//testInverse_false();//两种删除方式TestCity city = (TestCity) HibernateSessionFactory.get(TestCity.class, 21);//TestCity city = new TestCity();//city.setId(19);////这时,city中的集合为空,则不会删除集合中的对象;HibernateSessionFactory.delete(city);}/** * 测试inverse属性为false时的关系维护,以及SQL的执行; 默认为false. */public static void testInverse_false () {TestCity city = new TestCity();city.setName("北京");TestSchool school = new TestSchool();school.setName("北京一中");TestStudent student1 = new TestStudent();student1.setName("张三");TestStudent student2 = new TestStudent();student2.setName("李四");//在主控方来设置关联关系//城市和学校city.getSchoolSet().add(school);//学校和学生school.getStudents().add(student1);school.getStudents().add(student2);//只处理城市HibernateSessionFactory.add(city);/*1 / 没有设置cascade时,sql如下,且报错Hibernate: insert into TestCity (name) values (?)Hibernate: update TestSchool set city_id=? where id=?由此可见,inverse只是负责维护之间的关系,并不负责处理save/update/delete关联对象(由cascade控制)此处有2个解决办法,第一个是在主控方来设置cascade;第二种是自己保存城市和学生,然后由inverse来控制关系第一种办法,先设置cascade为all,所有情况下均执行;cascade属性可选值:all : 所有情况下均进行关联操作。none:所有情况下均不进行关联操作。(默认值)save-update:在执行save/update/saveOrUpdate时进行关联操作。delete:在执行delete时进行关联操作。设置好,执行;Hibernate: insert into TestCity (name) values (?)Hibernate: insert into TestSchool (name, city_id) values (?, ?)Hibernate: update TestSchool set city_id=? where id=?Hibernate: update TestStudent set school_id=? where id=? //学校的学生set节点也要加设置好,执行:Hibernate: insert into TestCity (name) values (?)Hibernate: insert into TestSchool (name, city_id) values (?, ?)Hibernate: insert into TestStudent (name, school_id) values (?, ?)Hibernate: insert into TestStudent (name, school_id) values (?, ?)Hibernate: update TestSchool set city_id=? where id=?Hibernate: update TestStudent set school_id=? where id=?Hibernate: update TestStudent set school_id=? where id=?**cascade级联先发生,最后hibernate会根据inverse来判断是否来控制关联关系!**cascade用于触发增删改的级联操作,inverse来控制关联关系;设计时,要根据实际情况:1/城市的建立,不一定要建学校;2/学校建的时候会选择在哪个城市来建校,所以关系应该由学校控制;所以城市的set集合inverse应该设置为true;3/城市更名时,和学校的属性没有多大关系,房间和学生也不会更改任何属性.4/一旦城市被炸毁,则学校也一同死掉,但学生很可能因为事先逃亡了,所以没有死,只是不上学了.因此城市中的set节点应该是<set name="schoolSet" cascade="delete" inverse="true"><key column="city_id"></key><one-to-many class="com.test.TestSchool"></one-to-many></set>学校中,多对一的城市节点,应该是 cascade=none, 即学校改名/被拆,和城市没有关系,不用级联操作;<many-to-one name="city" column="city_id" cascade="none" class="com.test.TestCity" lazy="false"></many-to-one>学校中的学生,同理,建校时,没有学生,学校被拆和学生没有关系;学生上学和学校有关系,学生改名或者死掉不会影响学校<set name="students" inverse="true" cascade="none"><key column="school_id"></key><one-to-many class="com.test.TestStudent"></one-to-many></set>学生中的学校<many-to-one name="school" column="school_id" class="com.test.TestSchool" cascade="none" lazy="false"></many-to-one>**所以inverse 90%以上是由many来控制的,也是默认的.在one的一方,set标签中设置inverse=true.cascade 90%不用设置是(默认值none).即一方改名和删除和另一方没有关系.如果像城市/学校这样,城市被毁,则学校被毁,就设置delete.同样要设置delete的有 订单-订单明细;  用户-消费记录/登录记录;以上的代码要改成TestCity city = new TestCity();city.setName("北京");//创建城市,和玩游戏一样HibernateSessionFactory.add(city);//创建学校TestSchool school = new TestSchool();school.setName("北京一中");//设置关系school.setCity(city);HibernateSessionFactory.add(school);//学生出生TestStudent student1 = new TestStudent();student1.setName("张三");HibernateSessionFactory.add(student1);TestStudent student2 = new TestStudent();student2.setName("李四");HibernateSessionFactory.add(student2);//学生1去上学student1.setSchool(school);HibernateSessionFactory.update(student1);//学生2去上学student2.setSchool(school);HibernateSessionFactory.update(student2);Hibernate: insert into TestCity (name) values (?)Hibernate: insert into TestSchool (name, city_id) values (?, ?)Hibernate: insert into TestStudent (name, school_id) values (?, ?)Hibernate: insert into TestStudent (name, school_id) values (?, ?)Hibernate: update TestStudent set name=?, school_id=? where id=?Hibernate: update TestStudent set name=?, school_id=? where id=?考虑对象关系时,考虑2点:1/我的属性值改变或者我的存在消失,是否影响你的状态和你的消失,如果有影响则有cascade;2/我们的关系,是你管理好,还是我管理好.如果你关系好,则设置inverse=true;many一方没有这个属性;*/}/*sql脚本delete testSchool;DELETE  testCity;DELETE  testStudent;DECLARE @school_id int;INSERT INTO  testCity (name) VALUES ('北京');INSERT INTO  testSchool (name,city_id) VALUES ('北京一中', @@identity);SET @school_id=  @@identity;INSERT INTO  testStudent (name,school_id) VALUES ('张三', @school_id);INSERT INTO  testStudent (name,school_id) VALUES ('李四', @school_id);SELECT * from testCitySELECT * from testSchoolSELECT * from testStudent */}


0 0
原创粉丝点击