1. 程式人生 > 其它 >Hibernate關係對映-級聯操作

Hibernate關係對映-級聯操作

Hibernate關係對映-級聯操作cascade

在雙向一對多的學習中,我們發現每次儲存物件時,學生物件和年紀物件都需要我們持久化之session,既然它們兩者有關聯關係,可不可以只持久化其中一端,另一端就會自動的被持久化呢,這個屬性就是Hibernate的cascade。cascade是多對一、一對多、一對一、多對多各種關係之間的一種級聯操作行為。(關鍵語句:cascade="save-update"。)

一、什麼是級聯操作

官方解釋:必須級聯到關聯目標的操作,預設情況下沒有級聯操作。

當Hibernate持久化一個瞬時物件時,在預設情況下,它不會自動持久化所關聯的其他臨時物件,而是會丟擲org.hibernate.TransientObjectException。

級聯的意思是:本實體做了什麼事,也要拉上另一個關聯的實體,導致另一個實體跟著做事情。就是說我刪除了,你也必須刪除!關聯目標,指的是關聯的那個實體 。

二、準備案例

在明確了級聯操作的概念知識以後,使用學生表和年紀表的雙向一對多關係,實現級聯操作行為。

學生表和年紀表的雙向一對多關係學習請參考(Hibernate關係對映-雙向一對多)。

cascade級聯操作,預設是none不級聯。

none:不級聯。

save-update:儲存和更新某一端資料時,另一端資料可以一起儲存和更新。

delete:刪除級聯-不能在多的一端使用。

all:表示所有操作都級聯

三、實現級聯操作

1、配置多端

  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 cascade="save-update" name="grade" class="Grade" column="grade_id" foreign-key="fk_grade"/> </class> </hibernate-mapping>

     

    2.編寫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" cascade="save-update">
                <key foreign-key="fk_grade" column="grade_id"></key>
                <one-to-many class="Student"/>
            </set>
        </class>
    </hibernate-mapping>

     

    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. 編寫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();
                  }
          ​
              }

           

四、總結

大家可以嘗試除了新增以外的其他操作,可以得出以下結論

  • 在多對一的關係中,多的一端不能操作級聯為delete,一般在多的一端設為save-update;

  • 在一對多的關係中,如果一的一端設為delete相關配置時,多的一端不能指明外來鍵為非空。