Hibernate的雙向多對多的關係映射

      最近在學習Hibernate的時候,對象關係映射(ORM)特別重要也特別難懂,現在來記錄一下學習過程.
多對多的關係在生活中特別常見,比如老師和學生.一個老師有對應多個學生,一個學生可以有好多個老師.現在就以這個爲例子進行學習.
一.首先,建表
      對多對的關係映射在僅有的兩張數據庫表中student和teacher是對應不起來的.需要一箇中間表student_teacher來建立聯繫.
studen表 (student_id爲主鍵自增)

這裏寫圖片描述

teacher表(teacher_id是主鍵自增)
這裏寫圖片描述

中間表student_teacher—>student_id和teacher_id是聯合主鍵(不能設置自動遞增)
這裏寫圖片描述
二.創建映射實體類
Student.java
(生成的get.set方法就不寫了)

public class Student {

    private Integer studentId;
    private String studentName;
    private Set<Teacher> teachers = new HashSet<>();

Teacher.java
(生成的get.set方法就不寫了)

public class Teacher {
    private Integer teacherId;
    private String teacherName;
    private Set<Student> students = new HashSet<>();

三.寫對應的映射文件
student.hbm.xml

<hibernate-mapping package="com.qiushiju.model">
    <class name="Student" table="student">
        <id name="studentId" column="student_id">
            <generator class="native"></generator>
        </id>
        <property name="studentName" column="student_name" />

        <set name="teachers" table="student_teacher" >
            <key column="student_id" />
            <many-to-many class="Teacher" column="teacher_id" />
        </set>
    </class>
</hibernate-mapping>

Teacher.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 package="com.qiushiju.model">
    <class name="Teacher" table="teacher">
        <id name="teacherId" column="teacher_id">
            <generator class="native" />
        </id>

        <property name="teacherName" column="teacher_name" />

        <set name="students" table="student_teacher" >
            <key column="teacher_id"/>
                <many-to-many class="Student" column="student_id"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

四.編寫Hibernate的配置文件.把映射文件注入配置文件中
配置文件爲hibernate.cfg.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="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/hibernate2</property>
        <property name="connection.username">root</property>
        <property name="connection.password">qqq030053</property>

        <!-- 數據庫方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 是否打印展示SQL語句 -->
        <property name="show_sql">true</property>

        <!-- 當前session保存在什麼地方 -->
        <property name="current_session_context_class">thread</property>

        <!-- Disable the second-level cache -->
        <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>

        <!-- 注入映射文件-->
        <mapping resource="M2MStudent.hbm.xml"/>
        <mapping resource="M2MTeacher.hbm.xml"/>

    </session-factory>
</hibernate-configuration>

五.寫測試類
先測試添加

public class TestManyToMany {
     public static void main(String[] args) {
        //讀取cfg.xml文件
         Configuration configuration = new Configuration().configure();

         //建立sessionFactory
         SessionFactory factory = configuration.buildSessionFactory();

         //取得session
        Session session = factory.openSession();
        session.beginTransaction();

        //創建多個老師
        Teacher teacher1 = new Teacher();
        teacher1.setTeacherName("老師1");
        Teacher teacher2 = new Teacher();
        teacher2.setTeacherName("老師2");

        //創建多個學生
        Student student1 = new Student();
        student1.setStudentName("學生1");
        Student student2 = new Student();
        student2.setStudentName("學生2");

        //設定關聯關係
        //爲每個老師添加多名學生
        teacher1.getStudents().add(student1);
        teacher1.getStudents().add(student2);
        teacher2.getStudents().add(student1);
        teacher2.getStudents().add(student2);

        //爲每個學生配多名老師
        student1.getTeachers().add(teacher1);
        student1.getTeachers().add(teacher2);
        student2.getTeachers().add(teacher1);
        student2.getTeachers().add(teacher2);

        //保存
        session.save(teacher1);
        session.save(teacher2);
        session.save(student1);
        session.save(student2);

        // 提交.-->這一步纔是把數據真正提交至數據庫中
        session.getTransaction().commit();

輸出結果爲:
異常:
ERROR: Duplicate entry ‘9-9’ for key ‘PRIMARY’
Exception in thread “main” org.hibernate.exception.ConstraintViolationException: could not execute statement

     出現異常是因爲兩個映射文件的inverse都設爲默認的false,則會出現(主鍵重複),導致插入失敗;如果兩邊都設置inverse爲true,則Student和Teacher都去維護關聯關係,即同時向連接表插入記錄,則會導致主鍵重複插入失敗.
     解決辦法:讓其中一方的inverse設爲true,讓對方去維護關聯關係.
    [PS:inverse屬性:nverse的真正作用就是指定由哪一方來維護之間的關聯關係。當一方中指定了“inverse=false”(默認),那麼那一方就有責任負責之間的關聯關係,設爲true就是放棄維護關聯關係.讓對方維護;cascade屬性:級聯操作]
比如Teacher.hbm.xml中修改爲:

<set name="students" table="student_teacher" cascade="all" inverse="true">

修改後輸出結果爲:

Hibernate: insert into teacher (teacher_name) values (?)
Hibernate: insert into student (student_name) values (?)
Hibernate: insert into teacher (teacher_name) values (?)
Hibernate: insert into student (student_name) values (?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)
Hibernate: insert into student_teacher (student_id, teacher_id) values (?, ?)

此時數據庫爲:
teacher
這裏寫圖片描述
student_teacher
這裏寫圖片描述
student
這裏寫圖片描述
六.測試關聯查詢

        //通過session操作數據庫,得到老師對象
        Teacher teacher3 = (Teacher) session.get(Teacher.class, 7);

        //老師信息爲
        System.out.println("--->"+teacher3.getTeacherName());

        //通過老師找到這個老師對應的全部學生集合
        Set<Student> students = teacher3.getStudents();

        //遍歷輸出學生
        for (Student student : students) {
            System.out.println(student.getStudentName());
        }

輸出結果爲:

--->老師1

學生2
學生1
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章