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相关配置时,多的一端不能指明外键为非空。

posted @ 2022-05-05 19:26  Resign~as  阅读(65)  评论(0)    收藏  举报