一对多

例:一个班级可以有多个学生,而一个学生只能属于一个班级。

模型

package com.zze.bean;

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

public class Class {
    private Integer id;
    private String name;

    private Set<Student> students = new HashSet<>();

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

班级:com.zze.bean.Class

package com.zze.bean;

import java.util.Date;

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Date birthday;
    private String address;

    private Class clazz;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }
}

学生:com.zze.bean.Student

配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Class" table="class">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <!--
        set :
            name : ‘多’的一方在当前类中的属性名
        -->
        <set name="students">
            <!--
            key :
                column : 外键表中的关联当前类对应表的外键名称
            -->
            <key column="cid"/>
            <!--
            one-to-many : 标识一对多关系
                class : ‘多’的一方全限定类名
            -->
            <one-to-many class="com.zze.bean.Student"/>
        </set>
    </class>
</hibernate-mapping>

com/zze/bean/Class.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Student" table="student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <property name="age"/>
        <property name="birthday"/>
        <property name="address"/>
        <!--
        many-to-one : 标识多对一关系
            name : ‘一’的一方在当前类中属性名
            column : 外键名称
            class : ‘一’的一方的全限定类名
        -->
        <many-to-one name="clazz" column="cid" class="com.zze.bean.Class"/>
    </class>
</hibernate-mapping>

com/zze/bean/Student.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://192.168.208.153:3306/test</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="current_session_context_class">thread</property>
        <property name="hibernate.hbm2ddl.auto">create</property>
        <mapping resource="com/zze/bean/Class.hbm.xml"></mapping>
        <mapping resource="com/zze/bean/Student.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

hibernate.cfg.xml

普通操作

@Test
public void test1() {
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    // 创建一个班级
    Class clazz = new Class();
    clazz.setName("1班");
    // 创建两个学生
    Student student1 = new Student();
    student1.setName("张三");
    Student student2 = new Student();
    student2.setName("李四");

    // 让班级关联学生
    clazz.getStudents().add(student1);
    clazz.getStudents().add(student2);

    // 让学生关联班级
    student1.setClazz(clazz);
    student2.setClazz(clazz);
    // 保存班级
    session.save(clazz);

    // 保存学生
    session.save(student1);
    session.save(student2);
    transaction.commit();
}

例 1:两方关联,保存两方 - 新建一个班级,新建两个学生,班级主动关联学生,学生也主动关联班级,保存班级,再保存学生,成功

@Test
public void test2() {
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    // 创建一个班级
    Class clazz = new Class();
    clazz.setName("1班");
    // 创建两个学生
    Student student1 = new Student();
    student1.setName("张三");
    Student student2 = new Student();
    student2.setName("李四");

    // 让班级关联学生
    clazz.getStudents().add(student1);
    clazz.getStudents().add(student2);

    // 让学生关联班级
    student1.setClazz(clazz);
    student2.setClazz(clazz);
    // 保存班级
    session.save(clazz);
    transaction.commit();

    /*
     抛异常:org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.zze.bean.Student
     原因是:保存班级时,班级关联的学生为瞬时态对象,不能与瞬时态对象建立关系。
     */
}

例 2:两方关联,保存一方 - 新建一个班级,新建两个学生,班级主动关联学生,学生也主动关联班级,只保存班级,异常,需使用下面的级联保存。

级联操作

级联:

级联指的是:操作一个对象的时候,是否会同时操作其关联的对象。

级联的方向性:

操作一的一方的时候,是否会同时操作到多的一方。

操作多的一方的时候,是否会同时操作到一的一方。

  • 级联保存或更新

    保存‘一’级联保存‘多’:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
        <class name="com.zze.bean.Class" table="class">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" length="32"/>
            <set name="students" cascade="save-update">
                <key column="cid"/>
                <one-to-many class="com.zze.bean.Student"/>
            </set>
        </class>
    </hibernate-mapping>

    com/zze/bean/Class.hbm.xml:修改‘一’(班级)的映射文件,在 set 标签中添加属性 cascade="save-update"

    @Test
    public void test3() {
        Session session = HibernateUtil.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 创建一个班级
        Class clazz = new Class();
        clazz.setName("1班");
        // 创建两个学生
        Student student1 = new Student();
        student1.setName("张三");
        Student student2 = new Student();
        student2.setName("李四");
    
        // 让班级关联学生
        clazz.getStudents().add(student1);
        clazz.getStudents().add(student2);
        // 保存班级级联保存学生
        session.save(clazz);
        transaction.commit();
    }

    例 3:‘一’方关联,保存‘一’方 - 新建一个班级,新建两个学生,班级主动关联学生,只保存班级,级联保存了学生,成功

    保存‘多’级联保存‘一’:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
        <class name="com.zze.bean.Student" table="student">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" length="32"/>
            <property name="age"/>
            <property name="birthday"/>
            <property name="address"/>
            <many-to-one name="clazz" column="cid" class="com.zze.bean.Class" cascade="save-update"/>
        </class>
    </hibernate-mapping>

    com/zze/bean/Student.hbm.xml:修改‘多’(学生)的映射文件,在 many-to-one 标签中添加属性 cascade="save-update"

    @Test
    public void test4(){
        Session session = HibernateUtil.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        // 创建一个班级
        Class clazz = new Class();
        clazz.setName("1班");
        // 创建两个学生
        Student student1 = new Student();
        student1.setName("张三");
        Student student2 = new Student();
        student2.setName("李四");
    
        // 让学生关联班级
        student1.setClazz(clazz);
        student2.setClazz(clazz);
        // 保存学生级联保存班级
        session.save(student1);
        session.save(student2);
        transaction.commit();
    }

    例 4:‘多’方关联,保存‘多’方 - 新建一个班级,新建两个学生,学生主动关联班级,只保存学生,级联保存了班级,成功

  • 级联删除

    假如表中已有如下数据:

    删除‘一’级联删除‘多’:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
        <class name="com.zze.bean.Class" table="class">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" length="32"/>
            <set name="students" cascade="save-update,delete">
                <key column="cid"/>
                <one-to-many class="com.zze.bean.Student" />
            </set>
        </class>
    </hibernate-mapping>

    com/zze/bean/Class.hbm.xml:修改‘一’(班级)的映射文件,在 set 标签中添加属性 cascade="delete"

    @Test
    public void test5() {
        Session session = HibernateUtil.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Class clazz = session.get(Class.class, 1);
        session.delete(clazz);
        transaction.commit();
    }

    例 5:删除班级,级联删除该班级下所有学生。

    删除‘多’级联删除‘一’:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
        <class name="com.zze.bean.Student" table="student">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" length="32"/>
            <property name="age"/>
            <property name="birthday"/>
            <property name="address"/>
            <many-to-one name="clazz" column="cid" class="com.zze.bean.Class" cascade="save-update,delete"/>
        </class>
    </hibernate-mapping>

    com/zze/bean/Student.hbm.xml:修改‘多’(学生)的映射文件,在 many-to-one 标签中添加属性 cascade="delete"

    @Test
    public void test6() {
        Session session = HibernateUtil.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Student student = session.get(Student.class, 1);
        session.delete(student);
        transaction.commit();
        // 级联删除‘一’的一方,将其它关联‘一’的一方的数据的外键设为 null。
        // 如果‘一’的一方也设置了级联删除,那么所有关联‘一’的一方的数据都会被删除。
    }

    例 6:删除学生,级联删除该学生所属班级。

放弃维护外键关系

假入表中已有如下数据:

先要把张三从 1 班转到 2 班:

@Test
public void test7(){
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Student student = session.get(Student.class, 1); // 获取张三
    Class clazz = session.get(Class.class, 1); // 获取 2 班
    clazz.getStudents().add(student);
    student.setClazz(clazz);
    transaction.commit();
    /*
    此时会执行一下两条 SQL:
    Hibernate:
        update
            student
        set
            name=?,
            age=?,
            birthday=?,
            address=?,
            cid=?
        where
            id=?
    Hibernate:
        update
            student
        set
            cid=?
        where
            id=?
     */
}

例 7:

执行两条 SQL 的原因是:在上述代码中获取了两个持久态对象,并且在事务提交时两个持久态对象的属性都发生了变化,所以 Hibernate 发出了两条 SQL。

但显然这个操作其实一条 SQL 就能搞定的,这个时候就需要控制一方不维护外键关系了。

‘一’的一方放弃维护外键关系:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Class" table="class">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <set name="students" cascade="save-update" inverse="true">
            <key column="cid"/>
            <one-to-many class="com.zze.bean.Student" />
        </set>
    </class>
</hibernate-mapping>

com/zze/bean/Class.hbm.xml:修改‘一’(班级)映射文件,在 set 标签中添加属性 inverse="true"

依旧是执行上述“例 7”代码,会发现只会由‘多’(学生)的一方发出一条 update 语句。

在 Hibernate 中,‘多’的一方不可以放弃维护外键关系。

为什么‘多’的一方不能放弃维护外键关系?换句话说为什么 Hibernate 要让多的一方来维护关系?

原因是当‘一’的一方维护关系时,Hibernate 会额外发出一条 select 语句查出它所关联的所有的多的一方,显然没必要。而多的一方维护关系就比较简单了,直接 update 它本身的外键即可。

看到过一个有趣应景的说法:十三亿人民(‘多’)记住(维护)国家领导人的名字很简单,但要想国家领导人(‘一’)记住(维护)十三亿就不可能了。

理解 inverse 和 cascade:
@Test
public void test8() {
    // com/zze/bean/Class.hbm.xml 的 set 中设置了 cascade="save-update"、inverse="true"
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Student student = new Student();
    student.setName("王五");
    Class clazz = session.get(Class.class, 2); // 获取 1 班
    clazz.getStudents().add(student);
    session.save(clazz);
    transaction.commit();

    /*
    上述代码执行结果会是怎么样?
        先明确 cascade 和 inverse 的作用:
            cascade:为 save-update,即 Class 会级联保存和更新 Student。
            inverse:为 true,即 Class 放弃维护外键关系。
        首先 session 保存的是 clazz,clazz 是持久态对象。
        在事务提交时 clazz 的外键字段 students 发生了变化,添加了 student,
        班级有级联操作学生的能力,所以“王五”这个 student 会被保存到数据库。
        而班级放弃了维护外键关系,所以“王五”这个 student 添加到数据库后对应的外键字段为 null。
    结果如下:
        mysql> select * from student;
        +----+--------+------+----------+---------+------+
        | id | name   | age  | birthday | address | cid  |
        +----+--------+------+----------+---------+------+
        |  1 | 张三   | NULL | NULL     | NULL    |    1 |
        |  2 | 王五   | NULL | NULL     | NULL    | NULL |
        +----+--------+------+----------+---------+------+
        2 rows in set (0.00 sec)
     */
}

例 8:

多对多

例:一名学生可以选多门课程,一门课程也可以被多名学生选择:

模型

package com.zze.bean;

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private Date birthday;
    private String address;

    private Class clazz;

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

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

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

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

学生:com.zze.bean.Student

package com.zze.bean;

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

public class Course {
    private Integer id;
    private String name;

    private Set<Student> students = new HashSet<>();

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

课程:com.zze.bean.Course

配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Student" table="student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <property name="age"/>
        <property name="birthday"/>
        <property name="address"/>
        <many-to-one name="clazz" column="cid" class="com.zze.bean.Class" cascade="save-update,delete"/>

        <set name="courses" table="student_course">
            <!--
            key :
                column : 当前对象类对应中间表的外键名称
            -->
            <key column="studentId"/>
            <!--
            many-to-many : 标识多对多关系
                class : 对方类全路径
                column : 对方对应中间表的外键名称
            -->
            <many-to-many class="com.zze.bean.Course" column="courseId"/>
        </set>
    </class>
</hibernate-mapping>

com/zze/bean/Student.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Course" table="course">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <set name="students" table="student_course">
            <!--
            key :
                column : 当前对象类对应中间表的外键名称
            -->
            <key column="courseId"/>
            <!--
            many-to-many : 标识多对多关系
                class : 对方类全路径
                column : 对方对应中间表的外键名称
            -->
            <many-to-many class="com.zze.bean.Student" column="studentId"/>
        </set>
    </class>
</hibernate-mapping>

com/zze/bean/Course.hbm.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://192.168.208.153:3306/test</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="current_session_context_class">thread</property>
        <property name="hibernate.hbm2ddl.auto">create</property>
        <mapping resource="com/zze/bean/Class.hbm.xml"></mapping>
        <mapping resource="com/zze/bean/Student.hbm.xml"></mapping>
        <mapping resource="com/zze/bean/Course.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

hibernate.cfg.xml

普通操作

@Test
public void test9() {
    Session session = HibernateUtil.getCurrentSession();
    Transaction transaction = session.beginTransaction();
    Student student = new Student();
    student.setName("张三");
    Course course = new Course();
    course.setName("数学");
    student.getCourses().add(course);
    course.getStudents().add(student);
    session.save(student);
    session.save(course);
    transaction.commit();
    /*
     抛异常:org.hibernate.exception.ConstraintViolationException: could not execute statement
     原因:因为多对多关系的维护是依赖第三张中间表,而中间表的字段是两个分别关联多对多这两张表的主键的外键,
     且这两个外键在中间表中组成了联合主键,而上述代码实际上进行了两次 insert 操作,这两次操作的内容违
     反了联合主键约束,所以会抛出异常。
     */
}

例 9:两方关联,保存两方 - 新建一个学生,新建一个课程,让学生主动关联课程,也让课程主动关联学生,保存学生与课程,异常

分析原因后,可以得出结论,在多对多中两方关联时,必须有一方得放弃维护外键关系(一般是被动方放弃,即 Course 放弃),下面配置二选一:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Student" table="student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <property name="age"/>
        <property name="birthday"/>
        <property name="address"/>
        <many-to-one name="clazz" column="cid" class="com.zze.bean.Class" cascade="save-update,delete"/>

        <set name="courses" table="student_course" inverse="true">
            <!--
            key :
                column : 当前对象类对应中间表的外键名称
            -->
            <key column="studentId"/>
            <!--
            many-to-many : 标识多对多关系
                class : 对方类全路径
                column : 对方对应中间表的外键名称
            -->
            <many-to-many class="com.zze.bean.Course" column="courseId"/>
        </set>
    </class>
</hibernate-mapping>

com/zze/bean/Student.hbm.xml:修改 set 标签,添加属性 inverse="true"

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.zze.bean.Course" table="course">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" length="32"/>
        <set name="students" table="student_course" inverse="true">
            <!--
            key :
                column : 当前对象类对应中间表的外键名称
            -->
            <key column="courseId"/>
            <!--
            many-to-many : 标识多对多关系
                class : 对方类全路径
                column : 对方对应中间表的外键名称
            -->
            <many-to-many class="com.zze.bean.Student" column="studentId"/>
        </set>
    </class>
</hibernate-mapping>

com/zze/bean/Course.hbm.xml:修改 set 标签,添加属性 inverse="true"

修改配置后,再次执行 “例 9” 中代码,成功。

级联操作

  • 级联保存或更新

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
        <class name="com.zze.bean.Student" table="student">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" length="32"/>
            <property name="age"/>
            <property name="birthday"/>
            <property name="address"/>
            <many-to-one name="clazz" column="cid" class="com.zze.bean.Class" cascade="save-update,delete"/>
    
            <set name="courses" table="student_course" cascade="save-update">
                <!--
                key :
                    column : 当前对象类对应中间表的外键名称
                -->
                <key column="studentId"/>
                <!--
                many-to-many : 标识多对多关系
                    class : 对方类全路径
                    column : 对方对应中间表的外键名称
                -->
                <many-to-many class="com.zze.bean.Course" column="courseId"/>
            </set>
        </class>
    </hibernate-mapping>

    com/zze/bean/Student.hbm.xml:修改 set 标签,添加属性 cascade="save-update"

    @Test
    public void test10() {
        Session session = HibernateUtil.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Student student = new Student();
        student.setName("张三");
        Course course = new Course();
        course.setName("数学");
        student.getCourses().add(course);
        session.save(student);
        transaction.commit();
    }

    例 10:一方关联,保存一方 - 新建一个学生,新建一个课程,让学生主动关联课程,保存学生,级联保存了课程,成功

  • 级联删除

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE hibernate-mapping PUBLIC
            "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
            "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
    
    <hibernate-mapping>
        <class name="com.zze.bean.Student" table="student">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" length="32"/>
            <property name="age"/>
            <property name="birthday"/>
            <property name="address"/>
            <many-to-one name="clazz" column="cid" class="com.zze.bean.Class" cascade="save-update,delete"/>
    
            <set name="courses" table="student_course" cascade="save-update,delete">
                <!--
                key :
                    column : 当前对象类对应中间表的外键名称
                -->
                <key column="studentId"/>
                <!--
                many-to-many : 标识多对多关系
                    class : 对方类全路径
                    column : 对方对应中间表的外键名称
                -->
                <many-to-many class="com.zze.bean.Course" column="courseId"/>
            </set>
        </class>
    </hibernate-mapping>

    com/zze/bean/Student.hbm.xml:修改 set 标签,添加属性 cascade="delete"

    @Test
    public void test11() {
        Session session = HibernateUtil.getCurrentSession();
        Transaction transaction = session.beginTransaction();
        Student student = session.get(Student.class, 1);
        session.delete(student);
        transaction.commit();
    }

    例 11:删除学生,级联删除该学生所选的课程

java框架之Hibernate(3)-一对多和多对多关系操作的更多相关文章

  1. Java基础-SSM之mybatis一对多和多对一关系映射

    Java基础-SSM之mybatis一对多和多对一关系映射 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.准备测试环境(创建数据库表)  1>.创建customers表: ...

  2. Hibernate中一对多和多对一关系

    1.单向多对一和双向多对一的区别? 只需要从一方获取另一方的数据时 就使用单向关联双方都需要获取对方数据时 就使用双向关系 部门--人员 使用人员时如果只需要获取对应部门信息(user.getdept ...

  3. Hibernate自身一对多和多对多关系映射

    一对多关系映射大家都明白,关系双方都一个含有对方多个引用,但自身一对多很多同学都不明白什么意思,那么首先我就说明一下什么是自身一对多,其实也很好理解,自身一对多就是自身含有本身的多个引用,例如新闻类别 ...

  4. JAVA框架之Hibernate框架的学习步骤

    首先介绍一下Java三大框架的关系 以CRM项目即客户关系管理项目示例 hibernate框架的学习路线: 1.学习框架入门,自己搭建框架,完成增删改查的操作 2.学习一级缓存,事物管理和基本查询 3 ...

  5. JPA一对多和多对一关系

    1-m:多的一方为关系维护端,关系维护端负责外键纪录的更新,关系被维护端没有权力更新外键纪录. 维护端注解 @OneToMany(cascade = { CascadeType.PERSIST, Ca ...

  6. EF里一对一、一对多、多对多关系的配置和级联删除

    本章节开始了解EF的各种关系.如果你对EF里实体间的各种关系还不是很熟悉,可以看看我的思路,能帮你更快的理解. I.实体间一对一的关系 添加一个PersonPhoto类,表示用户照片类 /// < ...

  7. Django 一对多,多对多关系解析

    [转]Django 一对多,多对多关系解析   Django 的 ORM 有多种关系:一对一,多对一,多对多. 各自定义的方式为 :        一对一: OneToOneField         ...

  8. EF——一对一、一对多、多对多关系的配置和级联删除 04(转)

    EF里一对一.一对多.多对多关系的配置和级联删除   本章节开始了解EF的各种关系.如果你对EF里实体间的各种关系还不是很熟悉,可以看看我的思路,能帮你更快的理解. I.实体间一对一的关系 添加一个P ...

  9. django ORM模型表的一对多、多对多关系、万能双下划线查询

    一.外键使用 在 MySQL 中,如果使用InnoDB引擎,则支持外键约束.(另一种常用的MyIsam引擎不支持外键) 定义外键的语法为fieldname=models.ForeignKey(to_c ...

随机推荐

  1. RTP推流及验证

    [时间:2018-07] [状态:Open] [关键词:rtp,rtcp, ffmpeg,ffplay,sdp,h264,mp2,ts,推流] 近期在学习有关RTP/RTCP的资料,发现看了很多资料, ...

  2. jinfo

    jinfo是jdk自带的命令,用来查看.修改jvm的配置参数. [weblogic@host bin]$ jinfo-bash: jinfo: command not found[weblogic@h ...

  3. 【iCore4 双核心板_uC/OS-II】例程三:任务的挂起与恢复

    一.实验说明: 当一个任务正在运行的时候,由于某种情况可能需要终止运行一段时间,终止的这段时间就是 所谓的任务的挂起,可以由该任务自身或者其他任务来挂起一个任务.当被挂起的任务需要再次运 行的时候,可 ...

  4. yml 后面的配置覆盖前面的

    事情是这样的: a: b: c: tomcat d: hoho # 中间还隔了好多 a: b: c: tomcat 这种情况下,后面的配置会覆盖前面的所有配置,即 a.d = hoho 也会被覆盖 y ...

  5. py-faster-rcnn 训练参数修改(转)

    faster rcnn默认有三种网络模型 ZF(小).VGG_CNN_M_1024(中).VGG16 (大) 训练图片大小为500*500,类别数1. 一. 修改VGG_CNN_M_1024模型配置文 ...

  6. uglifyjs 合并压缩 js, clean-css 合并压缩css

    本文主要介绍如何通过CLI命令行(也就是终端或者cmd打开的那个shell窗口)实现 js和 css 的合并压缩. uglifyjs 合并压缩 js: 1.安装node 这一步就不多说了,下载node ...

  7. 关于azkaban上传job压缩包报错问题的解决方案

    在azkaban上传job压缩包如果出现 installation Failed Error Chunking during uploading files to db.. 错误,可通过如下方法解决. ...

  8. 框架源码系列四:手写Spring-配置(为什么要提供配置的方法、选择什么样的配置方式、配置方式的工作过程是怎样的、分步骤一个一个的去分析和设计)

    一.为什么要提供配置的方法 经过前面的手写Spring IOC.手写Spring DI.手写Spring AOP,我们知道要创建一个bean对象,需要用户先定义好bean,然后注册到bean工厂才能创 ...

  9. GraphX学习笔记——Programming Guide

    学习的资料是官网的Programming Guide https://spark.apache.org/docs/latest/graphx-programming-guide.html 首先是Gra ...

  10. K好数(DP)

    问题描写叙述 假设一个自然数N的K进制表示中随意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数. 求L位K进制数中K好数的数目. 比如K = 4,L = 2的时候.全部K好数为11.13.2 ...