首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

主题:Hibernate多对多删除有关问题的解决(一种方法)

2012-09-01 
主题:Hibernate多对多删除问题的解决(一种方法)主题:Hibernate多对多删除问题的解决博客分类:?HibernateHi

主题:Hibernate多对多删除问题的解决(一种方法)

主题:Hibernate多对多删除问题的解决博客分类:?
  • HibernateHibernateXMLSQL.netSpringHibernate多对多的例子不少,但仔细一看,大多数都是保存的,删除谈的少,但问题还不少,因此有必须简单测试一下,以下我们来个简单的多对多关系建立?

    老师Teacher 与 课程Course 是一个多对多的关系,Pojo与XMl配置如下。?



    Pojo?

    Java代码?
    /**??
    * Course Entity??
    * see table: tbl_course??
    */??
    package com.leo.domain;???
    ??
    import java.util.HashSet;???
    import java.util.Set;???
    ??
    /**??
    * @author superleo??
    *???
    */??
    public class Course {???
    ??
    ??? private String id;???
    ??
    ??? private String name;???
    ??
    ??? private Set<Teacher> teachers = new HashSet<Teacher>();???
    ??
    ??? public String getId() {???
    ??????? return id;???
    ??? }???
    ??
    ??? public void setId(String id) {???
    ??????? this.id = id;???
    ??? }???
    ??
    ??? public String getName() {???
    ??????? return name;???
    ??? }???
    ??
    ??? public void setName(String name) {???
    ??????? this.name = name;???
    ??? }???
    ??
    ??? public Set<Teacher> getTeachers() {???
    ??????? return teachers;???
    ??? }???
    ??
    ??? public void setTeachers(Set<Teacher> teachers) {???
    ??????? this.teachers = teachers;???
    ??? }???
    ??
    }??

    /**?
    * Course Entity?
    * see table: tbl_course?
    */?
    package com.leo.domain;?

    import java.util.HashSet;?
    import java.util.Set;?

    /**?
    * @author superleo?
    *?
    */?
    public class Course {?

    private String id;?

    private String name;?

    private Set<Teacher> teachers = new HashSet<Teacher>();?

    public String getId() {?
    return id;?
    }?

    public void setId(String id) {?
    this.id = id;?
    }?

    public String getName() {?
    return name;?
    }?

    public void setName(String name) {?
    this.name = name;?
    }?

    public Set<Teacher> getTeachers() {?
    return teachers;?
    }?

    public void setTeachers(Set<Teacher> teachers) {?
    this.teachers = teachers;?
    }?

    }?
    Java代码?
    /**??
    * Teacher Entity??
    * see table: tbl_teacher??
    */??
    package com.leo.domain;???
    ??
    import java.util.HashSet;???
    import java.util.Set;???
    ??
    /**??
    * @author superleo??
    *???
    */??
    public class Teacher {???
    ??
    ??? private String id;???
    ??
    ??? private String name;???
    ??
    ??? private Set<Course> courses = new HashSet<Course>();???
    ??
    ??? public String getId() {???
    ??????? return id;???
    ??? }???
    ??
    ??? public void setId(String id) {???
    ??????? this.id = id;???
    ??? }???
    ??
    ??? public String getName() {???
    ??????? return name;???
    ??? }???
    ??
    ??? public void setName(String name) {???
    ??????? this.name = name;???
    ??? }???
    ??
    ??? public Set<Course> getCourses() {???
    ??????? return courses;???
    ??? }???
    ??
    ??? public void setCourses(Set<Course> courses) {???
    ??????? this.courses = courses;???
    ??? }???
    ??
    }??

    /**?
    * Teacher Entity?
    * see table: tbl_teacher?
    */?
    package com.leo.domain;?

    import java.util.HashSet;?
    import java.util.Set;?

    /**?
    * @author superleo?
    *?
    */?
    public class Teacher {?

    private String id;?

    private String name;?

    private Set<Course> courses = new HashSet<Course>();?

    public String getId() {?
    return id;?
    }?

    public void setId(String id) {?
    this.id = id;?
    }?

    public String getName() {?
    return name;?
    }?

    public void setName(String name) {?
    this.name = name;?
    }?

    public Set<Course> getCourses() {?
    return courses;?
    }?

    public void setCourses(Set<Course> courses) {?
    this.courses = courses;?
    }?

    }?


    配置文件也非常简单:?

    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">??
    ??
    <hibernate-mapping>??
    ??? <class name="com.leo.domain.Course" table="tbl_course"??
    ??????? batch-size="100" dynamic-insert="true" dynamic-update="true">??
    ??????? <id name="id" column="id">??
    ??????????? <generator />??
    ??????? </id>??
    ??????? <property name="name" column="name" type="string" />??
    ??
    ??????? <set access="property" lazy="true" inverse="false"??
    ??????????? cascade="save-update" name="teachers" batch-size="10" fetch="select"??
    ??????????? table="tbl_teacher_course">??
    ??????????? <key column="fk_course_id" />??
    ??????????? <many-to-many />??
    ??????? </set>??
    ??
    ??? </class>??
    </hibernate-mapping>??

    <?xml version="1.0"?>?
    <!DOCTYPE hibernate-mapping PUBLIC?
    ??????? "-//Hibernate/Hibernate Mapping DTD 3.0//EN"?
    ??????? "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">?

    <hibernate-mapping>?
    <class name="com.leo.domain.Course" table="tbl_course"?
    batch-size="100" dynamic-insert="true" dynamic-update="true">?
    <id name="id" column="id">?
    <generator />?
    </id>?
    <property name="name" column="name" type="string" />?

    <set access="property" lazy="true" inverse="false"?
    cascade="save-update" name="teachers" batch-size="10" fetch="select"?
    table="tbl_teacher_course">?
    <key column="fk_course_id" />?
    <many-to-many />?
    </set>?

    </class>?
    </hibernate-mapping>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">??
    ??
    <hibernate-mapping>??
    ??? <class name="com.leo.domain.Teacher" table="tbl_teacher"??
    ??????? batch-size="100" dynamic-insert="true" dynamic-update="true">??
    ??????? <id name="id" column="id">??
    ??????????? <generator />??
    ??????? </id>??
    ??????? <property name="name" column="name" type="string" />??
    ??
    ??????? <set access="property" lazy="true" inverse="true"??
    ??????????? cascade="save-update" name="courses" batch-size="10" fetch="select"??
    ??????????? table="tbl_teacher_course">??
    ??????????? <key column="fk_teacher_id" />??
    ??????????? <many-to-many />??
    ??????? </set>??
    ??
    ??? </class>??
    </hibernate-mapping>??

    <?xml version="1.0"?>?
    <!DOCTYPE hibernate-mapping PUBLIC?
    ??????? "-//Hibernate/Hibernate Mapping DTD 3.0//EN"?
    ??????? "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">?

    <hibernate-mapping>?
    <class name="com.leo.domain.Teacher" table="tbl_teacher"?
    batch-size="100" dynamic-insert="true" dynamic-update="true">?
    <id name="id" column="id">?
    <generator />?
    </id>?
    <property name="name" column="name" type="string" />?

    <set access="property" lazy="true" inverse="true"?
    cascade="save-update" name="courses" batch-size="10" fetch="select"?
    table="tbl_teacher_course">?
    <key column="fk_teacher_id" />?
    <many-to-many />?
    </set>?

    </class>?
    </hibernate-mapping>?

    先往数据库里插入一些记录:?



    Java代码?
    public void testSave() {???
    ??????? Session session = HibernateSessionFactory.getSession();???
    ??????? session.beginTransaction();???
    ??
    ??????? // create course???
    ??????? Course c1 = new Course();???
    ??????? Course c2 = new Course();???
    ??????? c1.setName("C");???
    ??????? c2.setName("Java");???
    ??
    ??????? // create teacher???
    ??????? Teacher t1 = new Teacher();???
    ??????? Teacher t2 = new Teacher();???
    ??????? t1.setName("Leo");???
    ??????? t2.setName("Rose");???
    ??
    ??????? // create relationship???
    ??????? c1.getTeachers().add(t1);???
    ??????? c1.getTeachers().add(t2);???
    ??????? t1.getCourses().add(c1);???
    ??????? t2.getCourses().add(c1);???
    ??
    ??????? /* 因为主控方级联设置为save-update,如果设置为none,则下面被注释的代码需要开启,否则会报错 */??
    ??????? //session.save(t1);????
    ??????? //session.save(t2);???
    ??????? session.save(c1);???
    ??
    ??????? session.getTransaction().commit();???
    ??????? session.close();???
    ??? }??

    public void testSave() {?
    Session session = HibernateSessionFactory.getSession();?
    session.beginTransaction();?

    // create course?
    Course c1 = new Course();?
    Course c2 = new Course();?
    c1.setName("C");?
    c2.setName("Java");?

    // create teacher?
    Teacher t1 = new Teacher();?
    Teacher t2 = new Teacher();?
    t1.setName("Leo");?
    t2.setName("Rose");?

    // create relationship?
    c1.getTeachers().add(t1);?
    c1.getTeachers().add(t2);?
    t1.getCourses().add(c1);?
    t2.getCourses().add(c1);?

    /* 因为主控方级联设置为save-update,如果设置为none,则下面被注释的代码需要开启,否则会报错 */?
    //session.save(t1);?
    //session.save(t2);?
    session.save(c1);?

    session.getTransaction().commit();?
    session.close();?
    }?

    下面是测试的一些结果:?

    1. 如果cascade不管主控方设置还是被控方设置成 all, delete等与delete级联删除有关即可,两端以及中间表的记录都会被删除,通常这样的需要是很少的,因此,如果你要这样的情况,只要简单设置成all, delete就可以轻松的将关系以及两端的记录删除的干干净净。?

    2. 只想删除某一端的记录以及中间的表的关联信息。 这种需求通常是很常见的。这个时候cascade的设置是除与delete有关的任何级联约束。以下是删除心得:?

    如果删除的是主控方,只需要简单的删除这条记录,级联关系以及主控方的记录同时删除,但被控方的记录仍然存在。因此只对主控方的多对多删除是最简单,直接的。代码如下:Java代码?
    /**??
    ???? * 多对多 主控方删除(可以删除中间表记录)??
    ???? */??
    ??? public void testDelete() {???
    ??????? String id = "402881ee175f04be01175f04c05d0001";???
    ??????? Session session = HibernateSessionFactory.getSession();???
    ??????? session.beginTransaction();???
    ??????? Course c1 = (Course) session.get(Course.class, id);???
    ??????? session.delete(c1);???
    ??????? session.getTransaction().commit();???
    ??????? session.close();???
    ??? }??

    /**?
    * 多对多 主控方删除(可以删除中间表记录)?
    */?
    public void testDelete() {?
    String id = "402881ee175f04be01175f04c05d0001";?
    Session session = HibernateSessionFactory.getSession();?
    session.beginTransaction();?
    Course c1 = (Course) session.get(Course.class, id);?
    session.delete(c1);?
    session.getTransaction().commit();?
    session.close();?
    }?
    如果你这个时候想直接删除被控方,那么很遗憾的告诉你,你只做到了一半,你只是简单的把被控方的记录删除了,关联关系仍然存在中间表里,系统随时会因为你的关联访问报错,代码如下:Java代码?
    /**??
    * 多对多 被控方删除(无法删除中间表记录)??
    */??
    public void testDeleteByInverse() {???
    ??? String id = "402881ee175a2e7c01175a2e7ead0003";???
    ??? Session session = HibernateSessionFactory.getSession();???
    ??? session.beginTransaction();???
    ??? Teacher t1 = (Teacher) session.get(Teacher.class, id);???
    ??? session.delete(t1);???
    ??? session.getTransaction().commit();???
    ??? session.close();???
    }??

    如果想既想删除被控方,双想删除关联,请看下面代码:Java代码?


    /**?
    * 多对多 被控方删除(可以删除中间表记录)?
    */?
    public void testDeleteByInverse2() {?
    String id = "402881ee175f04be01175f04c06c0002";?
    Session session = HibernateSessionFactory.getSession();?
    session.beginTransaction();?

    Teacher t1 = (Teacher) session.get(Teacher.class, id);?

    Set<Course> cs = t1.getCourses();?
    for (Course c : cs) {?
    c.getTeachers().remove(t1);?
    }?

    session.delete(t1);?
    session.getTransaction().commit();?
    session.close();?
    }?
    完成了。 但如果是Spring+Hiberante下多对多删除,可能会报一个错误,目前的解决办法是把两端的cascade都设置成none. 初步断定可能与事务有关,如果有人遇到了,并知道为什么,希望能留言,先谢谢大家了。?



    注:三个表的表结构?

    1. tbl_course.sql?



    ??? create table "SCOTT"."TBL_COURSE"(?
    ??????? "ID" VARCHAR2(80) not null,?
    ?????? "NAME" VARCHAR2(20) not null,?
    ??????? constraint "SYS_C005315" primary key ("ID")?
    ??? );?

    create unique index "SCOTT"."SYS_C005315" on "SCOTT"."TBL_COURSE"("ID");?



    2. tbl_teacher.sql?




    ??? create table "SCOTT"."TBL_TEACHER"(?
    ??????? "ID" VARCHAR2(80) not null,?
    ?????? "NAME" VARCHAR2(20) not null,?
    ??????? constraint "SYS_C005313" primary key ("ID")?
    ??? );?

    create unique index "SCOTT"."SYS_C005313" on "SCOTT"."TBL_TEACHER"("ID");?



    3.tbl_teacher_course.sql?

    ? create table "SCOTT"."TBL_TEACHER_COURSE"(?
    ??????? "FK_TEACHER_ID" VARCHAR2(80),?
    ?????? "FK_COURSE_ID" VARCHAR2(90)?
    ??? );?