1. 程式人生 > 其它 >Hibernate的雙向一對多

Hibernate的雙向一對多

Hibernate關係對映-雙向一對多

一、學生表和年級表

                                                          Student表

id name age grade_id
1 張三 20 1
2 李四 22 1
3 王五 22 2

                                                          Grade表

id name
1 基礎
2 中級
  1. 建立Student類

public class Student implements Serializable {
    
private Integer id; private String name; private Integer age; private Grade grade; ​ @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", grade=" + grade + '}'; } ​
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 Grade getGrade() { return grade; } ​ public void setGrade(Grade grade) { this.grade = grade; } }

 

  1. 建立Grade類

public class Grade implements Serializable {
    private Integer id;
    private String name;
    private Set<Student> students = new HashSet<>();
​
    @Override
    public String toString() {
        return "Grade{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", students=" + students +
                '}';
    }
​
    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;
    }
}

 

  1. 建立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 package="com.uestc">
    <class name="Student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <property name="age"/>
        <!--
            多對一
            name對應的欄位名稱
            class對應的型別
            not-null不可以為空
            column外來鍵列名
            foreign-key外來鍵名稱
         -->
        <many-to-one name="grade" class="Grade"
                     column="grade_id" foreign-key="fk_grade"/>
    </class>
</hibernate-mapping>

 

  1. 建立Grade.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.uestc">
    <class name="Grade">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <!--
        單向一對多關係
            set:Grade類中的集合屬性
            name:集合屬性名稱
            key:外來鍵
            column:外來鍵列名
            foreign-key:生成外來鍵約束的名字(可以不寫,預設隨機)
            not-null="true" 不可以為空(可以不寫,預設false)
            one-to-many:Grade類中屬性students所表示型別
        -->
        <set name="students">
            <key foreign-key="fk_grade" column="grade_id"></key>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping>

 

  1. 在src和test的resources下面建立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>
      <!-- 初始化JDBC連線 -->
      <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
      <property name="connection.url">jdbc:mysql:///hibernate</property>
      <property name="connection.username">root</property>
      <property name="connection.password">root</property>
      <!-- 方言 -->
      <property name="dialect">org.hibernate.dialect.MySQL8Dialect</property>
      <!-- 資料庫生成方式 -->
      <property name="hbm2ddl.auto">update</property>  <!-- validate檢測,create-drop刪了重新建立,create重新建表,update表如果存在插資料,如果不存在建表插資料 -->
      <!-- 列印sql -->
      <property name="show_sql">true</property>
      <!-- 格式化sql -->
      <property name="format_sql">true</property>
      <!-- 關聯物件配置檔案 -->
      <mapping resource="com/uestc/Grade.hbm.xml"/>
      <mapping resource="com/uestc/Student.hbm.xml"/>
   </session-factory>
</hibernate-configuration>

 

  1. 測試類

/**
 * 單向多對一
 */
@Test
public void testSingleManyToOne() {
    Session session = null;
    Transaction tx = null;
    try {
        session = HibernateUtil.getSession();
        tx = session.beginTransaction();
​
        //建立例項物件
        Grade grade1 = new Grade();
        grade1.setName("基礎");
​
        Grade grade2 = new Grade();
        grade2.setName("中級");
​
​
​
        Student student = new Student();
        student.setName("張三");
        student.setAge(18);
        student.setGrade(grade1);
​
        Student student2 = new Student();
        student2.setName("李四");
        student2.setAge(18);
        student2.setGrade(grade1);
​
        Student student3 = new Student();
        student3.setName("王五");
        student3.setAge(18);
        student3.setGrade(grade2);
​
        //儲存的順序是根據外來鍵約束而定的,如果外來鍵不可以為空,必須先儲存外來鍵的一端
        //如果外來鍵可以為空,隨意儲存,但是建議先儲存外來鍵的一端,因為會多執行update
        session.save(grade1);
        session.save(grade2);
​
        session.save(student);
        session.save(student2);
        session.save(student3);
​
​
​
        tx.commit();
​
    }catch (Exception e){
        e.printStackTrace();
        tx.rollback();
    }finally {
        HibernateUtil.closeSession();
    }
}
​
/**
 * 獲取
 * 查詢不用開啟事務,會降低效能
 */
@Test
public void testSingleGetManyToOne() {
    Session session = null;
    Transaction tx = null;
    try {
        session = HibernateUtil.getSession();
        tx = session.beginTransaction();
​
        Student student = session.get(Student.class,1);
        System.out.println("stuName:" +student.getName() + ",grade:" +student.getGrade().getName());
​
​
        tx.commit();
​
    }catch (Exception e){
        e.printStackTrace();
        tx.rollback();
    }finally {
        HibernateUtil.closeSession();
    }
}
​
/**
 * 單向一對多
 */
@Test
public void testSingleOneToMany() {
    Session session = null;
    Transaction tx = null;
    try {
        session = HibernateUtil.getSession();
        tx = session.beginTransaction();
​
        //建立例項物件
​
        Student student = new Student();
        student.setName("張三");
        student.setAge(18);
​
        Student student2 = new Student();
        student2.setName("李四");
        student2.setAge(18);
​
​
        Student student3 = new Student();
        student3.setName("王五");
        student3.setAge(18);
​
        Grade grade1 = new Grade();
        grade1.setName("基礎");
        grade1.getStudents().add(student);
        grade1.getStudents().add(student2);
​
        Grade grade2 = new Grade();
        grade2.setName("中級");
        grade2.getStudents().add(student3);
​
        //儲存的順序是根據外來鍵約束而定的,如果外來鍵不可以為空,必須先儲存外來鍵的一端
        //單向一對多會多執行update語句,效率不如多對一
        session.save(grade1);
        session.save(grade2);
​
        session.save(student);
        session.save(student2);
        session.save(student3);
​
​
        tx.commit();
​
    }catch (Exception e){
        e.printStackTrace();
        tx.rollback();
    }finally {
        HibernateUtil.closeSession();
    }
}
​
/**
 * 獲取
 * 查詢不用開啟事務,會降低效能
 */
@Test
public void testSingleGetOneToMany() {
    Session session = null;
    Transaction tx = null;
    try {
        session = HibernateUtil.getSession();
        tx = session.beginTransaction();
​
        Student student = session.get(Student.class,1);
        System.out.println("stuName:" +student.getName() + ",grade:" +student.getGrade().getName());
        System.out.println("---------------------分割線-------------------");
        Grade grade = session.get(Grade.class,1);
        System.out.println("grade:" +grade.getName());
        for(Student stu : grade.getStudents()){
            System.out.println("stuName:" +stu.getName());
        }
​
​
​
        tx.commit();
​
    }catch (Exception e){
        e.printStackTrace();
        tx.rollback();
    }finally {
        HibernateUtil.closeSession();
    }
​
​
​
}

 

先執行單向一對多,在執行單向多對一,最後執行這個測試testSingleGetOneToMany類。就能看到下圖所示結果。通過張三鎖定基礎,通過基礎鎖定張三和李四。

 

 

二、總結

在雙向一對多關係對映中,通過觀察最後的執行結果,可以得出以下結論:

  • 注意一的一端的配置:<key>中不用指定關聯列;

  • 如果想要一的一端來維護關係,那麼在多的一端不用指定關聯列非空;

  • 關係由多的一端來維護 ,DML語句會少執行UPDATE語句,效率極高。