Hibernate关系映射-维护关系inverse

Hibernate关系映射-维护关系inverse

在双向一对多的学习中,我们总结出维护关系方由多端维护时效率极高,因为DML语句会少执行UPDATE语句,那么为了提高程序效率,我们一般都是将关系维护费设置为多端,这个属性就是Hibernate的inverse。inverse的值是boolean值,该属性一般只能在一端设置。

一、什么是维护关系

如果一端的映射文件中设置为true,说明在映射关系(一对多、多对多)中让对方来维护关系,如果为false,双方都可以维护关系,默认值是false,并且比如一对多,这个一端,也就是在有集合的这端设置。

维护关系:维护什么关系呢?维护外键的关系,上面已经提到,由多端维护,效率极高。

 创建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;
    }
}
复制代码

创建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;
    }
}
复制代码

编写配置文件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所表示类型
            inverse="true":让对方来维护关系
        -->
        <set name="students" cascade="save-update" inverse="true">
            <key foreign-key="fk_grade" column="grade_id"></key>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping>
复制代码

 


编写配置文件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>
复制代码

编写resources(src和test)下面的配置文件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>
复制代码

编写测试类

复制代码
    /**
     * 单向多对一
     */
    @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();
        }

    }
复制代码

 

二、总结

综上所述,得出以下结论:

  • inverse的权限在cascade之上,意思就是cascade是否有用,还得看inverse这个属性

  • 当inverse="false"时,谁管理关系维护。如果都管理了那么都维护。当关系由多的一端来维护时,效率极高。当关系由一的一端来维护时,会多执行UPDATE语句。

  • 当inverse="true"时,关系由另一端管理,不管一的一端是否指明关系,一的一端都不会去维护关系,都由多的一端负责。建议inverse="true",效率极高。

posted @   Resign~as  阅读(80)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示