Hibernate 一对多双向关联

一对多双向持久化类和映射文件的搭建

1.创建持久化类

1.创建Classes类

package cn.itcast.hibernate0909.onetomany.doubl;

import java.io.Serializable;
import java.util.Set;

public class Classes implements Serializable{
    private Long cid;
    private String cname;
    private String description;

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    private Set<Student> students;

    public Long getCid() {
        return cid;
    }

    public void setCid(Long cid) {
        this.cid = cid;
    }

    public String getCname() {
        return cname;
    }

    public void setCname(String cname) {
        this.cname = cname;
    }

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

2.创建Student类

package cn.itcast.hibernate0909.onetomany.doubl;

import java.io.Serializable;

public class Student implements Serializable{
    private Long sid;
    private String sname;
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    private String description;

    public Long getSid() {
        return sid;
    }

    public void setSid(Long sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }


    public Classes getClasses() {
        return classes;
    }

    public void setClasses(Classes classes) {
        this.classes = classes;
    }

    private Classes classes;
}

这里写图片描述

2.配置映射文件

1.配置Classes.hbm.xml映射文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="cn.itcast.hibernate0909.onetomany.doubl.Classes">  
        <id name="cid" type="java.lang.Long" length="5">
            <column name="cid"></column>
            <generator class="increment"></generator>
        </id>

        <property name="cname" type="java.lang.String" length="20"></property>
        <property name="description" type="java.lang.String" length="100"></property>
        <!-- 
            cascade指的是对象对对象的操作
            inverse指的是对象对关系的操作
         -->    
        <set name="students" cascade="all" >
            <key>
                <!-- 
                    通过classes建立与student之间的联系
                 -->
                <column name="cid"></column>
            </key>
            <one-to-many class="cn.itcast.hibernate0909.onetomany.doubl.Student"/>
        </set>
    </class>
</hibernate-mapping>

这里写图片描述

2.配置Student.hbm.xml映射文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="cn.itcast.hibernate0909.onetomany.doubl.Student">  
        <id name="sid" type="java.lang.Long" length="5">
            <column name="sid"></column>
            <generator class="increment"></generator>
        </id>

        <property name="sname" type="java.lang.String" length="20"></property>
        <property name="description" type="java.lang.String" length="100"></property>
        <!-- 
            多对一
               注意:在many-to-one中没有inverse属性
                    对student表的修改本身就是维护外键
         -->
        <many-to-one name="classes" class="cn.itcast.hibernate0909.onetomany.doubl.Classes" cascade="all">
            <!-- 
                外键
                   描述了通过student建立与classes之间的联系
             -->
            <column name="cid"></column>
        </many-to-one>
    </class>
</hibernate-mapping>

这里写图片描述

这里写图片描述

2.配置hibernate.cfg.xml文件

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <!-- 是用来描述数据库的连接 -->
<session-factory>
    <!-- 
        驱动
    -->
    <property name="connection.driver_class">
        com.mysql.jdbc.Driver
    </property>
    <!-- 
        url
    -->
    <property name="connection.url">
        jdbc:mysql://localhost:3306/hibernate0909
    </property>
    <!-- 
        username
    -->
    <property name="connection.username">root</property>
    <!-- 
        password
    -->
    <property name="connection.password">123</property>
    <!-- 
        hibernate针对建表的操作
        update  如果有表,检查表的结构,如果没有则创建
        create-drop 启动hibernate创建表,结束hibernate删除表
        create  每次启动都重新创建表
        validate 每次启动都检查表的结构
    -->
    <property name="hbm2ddl.auto">update</property>
    <property name="show_sql">true</property>
    <mapping
        resource="cn/itcast/hibernate0909/onetomany/doubl/Classes.hbm.xml" />
    <mapping
        resource="cn/itcast/hibernate0909/onetomany/doubl/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>

这里写图片描述

一对多双向关联练习

1.保存班级的时候同时保存学生(通过班级端保存)

这里写图片描述
junit测试结果:

这里写图片描述

这里写图片描述

这里写图片描述

2.保存班级的时候同时保存学生(通过学生端保存)

这里写图片描述

junit测试结果:
这里写图片描述
这里写图片描述

这里写图片描述

3. 已经存在一个班级,新建一个学生,并且建立该学生和该班级之间的关系

修改映射文件:
这里写图片描述

这里写图片描述

junit测试结果:
这里写图片描述
这里写图片描述

4.已经存在一个学生,新建一个班级,并且建立该学生和该班级之间的关系

这里写图片描述

junit测试结果:
这里写图片描述

这里写图片描述

这里写图片描述

5.已经存在一个学生,已经存在一个班级,解除该学生和原来班级之间的关系,建立该学生和新班级之间的关系

这里写图片描述

junit测试结果:
这里写图片描述

这里写图片描述

6.已经存在一个学生,解除该学生和该学生所在班级之间的关系

这里写图片描述

junit测试结果:
这里写图片描述

这里写图片描述

7.解除该班级和所有的学生之间的关系,再重新建立该班级和一些新的学员之间的关系

这里写图片描述

junit测试结果:
这里写图片描述

这里写图片描述

删掉数据库的下面两条数据,去掉代码的注释重新junit测试:
这里写图片描述

这里写图片描述

这里写图片描述

全部源码

package cn.itcast.hibernate0909.onetomany.doubl;

import java.util.HashSet;
import java.util.Set;

import javax.print.attribute.HashAttributeSet;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

/**
 * 1、保存班级
 * 2、保存学生
 * 3、保存班级的时候同时保存学生
 * 4、保存班级的时候同时保存学生,并且建立班级和学生之间的关系
 * 5、已经存在一个班级,新建一个学生,并且建立该学生和该班级之间的关系
 * 6、已经存在一个学生,新建一个班级,并且建立该学生和该班级之间的关系
 * 7、已经存在一个学生,已经存在一个班级,解除该学生和原来班级之间的关系,建立该学生和新班级之间的关系
 * 8、已经存在一个学生,解除该学生和该学生所在班级之间的关系
 * 9、解除该班级和所有的学生之间的关系,再重新建立该班级和一些新的学员之间的关系
 * 10、解除该班级和所有的学生之间的关系
 * 11、删除班级
 *      *
 *          *  解除该班级和所有的学生之间的关系
 *          *  删除该班级
 *      *   
 *          删除班级的同时删除学生
 * 12、删除学生
 *      同删除班级
 * @author Administrator
 *
 */
public class OneToManyDoubleTest {
    private static SessionFactory sessionFactory = null;
    static{
        Configuration  configuration = new Configuration();
        configuration.configure("cn/itcast/hibernate0909/onetomany/doubl/hibernate.cfg.xml");
        sessionFactory = configuration.buildSessionFactory();
    }
    /**
     * 保存班级的时候同时保存学生
     *      Hibernate: select max(cid) from Classes
            Hibernate: select max(sid) from Student
            Hibernate: insert into Classes (cname, description, cid) values (?, ?, ?)
            Hibernate: insert into Student (sname, description, cid, sid) values (?, ?, ?, ?)
            Hibernate: update Student set cid=? where sid=?
                    更新外键
        说明:
          classes.setStudents(students);  通过classes来维护关系 ,要发出update语句,更新外键 
     */
    @Test
    public void testSaveClasses_Cascade_S(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = new Classes();
        classes.setCname("1班");
        classes.setDescription("这是1班");
        Student student = new Student();
        student.setSname("小明同学");
        student.setDescription("厉害了我的哥");
        Set<Student> students = new HashSet<Student>();
        students.add(student);
        //通过classes建立classes与students之间的关系
        classes.setStudents(students);
        //通过student建立classes与students之间的关系
        //student.setClasses(classes);
        session.save(classes);
        transaction.commit();
        session.close();
    }
    /**
     * 
     *  Hibernate: select max(sid) from Student
        Hibernate: select max(cid) from Classes
        Hibernate: insert into Classes (cname, description, cid) values (?, ?, ?)
        Hibernate: insert into Student (sname, description, cid, sid) values (?, ?, ?, ?)
            student.setClasses(classes);通过student来维护classes
             对student的增、删、改本身就是对外键的操作,所以这里不再发出update语句
            一对多,多的一方维护关系,效率比较高
     */
    @Test
    public void testSaveStudent_Cascade_C(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = new Classes();
        classes.setCname("2班");
        classes.setDescription("这是2班");
        Student student = new Student();
        student.setSname("小菜同学");
        student.setDescription("厉害了我的小菜同学");
        Set<Student> students = new HashSet<Student>();
        students.add(student);
        //通过classes建立classes与students之间的关系
        //classes.setStudents(students);
        //通过student建立classes与students之间的关系
        student.setClasses(classes);
        session.save(student);
        transaction.commit();
        session.close();
    }

    /**
     * 已经存在一个班级,新建一个学生,并且建立该学生和该班级之间的关系
     */
    @Test
    public void testSaveStudent_R(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Classes classes = (Classes)session.get(Classes.class, 1L);
        Student student = new Student();
        student.setSname("老王");
        student.setDescription("隔壁老王");
        //通过student建立classes与student的关系
        student.setClasses(classes);
        session.save(student);
        transaction.commit();
        session.close();
    }

    /**
     * 已经存在一个学生,新建一个班级,并且建立该学生和该班级之间的关系
     *   通过分析:
     *      *  因为存在建立关系的操作,所以操作学生端效率比较高
     *      *  在这里存在保存班级的操作,所以应该是通过更新学生级联保存班级
     */
    @Test
    public void testUpdateStudent_CasCade(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Student student = (Student)session.get(Student.class, 2L);
        Classes classes = new Classes();
        classes.setCname("顶级班");
        classes.setDescription("都厉害");
        student.setClasses(classes);
        session.save(classes);
        transaction.commit();
        session.close();
    }

    /**
     * 已经存在一个学生,已经存在一个班级,解除该学生和原来班级之间的关系,建立该学生和新班级之间的关系
     */
    @Test
    public void testRebuild_R(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Student student = (Student)session.get(Student.class, 2L);
        Classes classes = (Classes)session.get(Classes.class, 1L);
        student.setClasses(classes);
        transaction.commit();
        session.close();
    }

    /**
     * 已经存在一个学生,解除该学生和该学生所在班级之间的关系
     */
    @Test
    public void testRealse_R(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        Student student = (Student)session.get(Student.class, 2L);
        student.setClasses(null);
        transaction.commit();
        session.close();
    }

    /**
     * 解除该班级和所有的学生之间的关系,再重新建立该班级和一些新的学员之间的关系
     */
    @Test
    public void testRealse_Rebuild_R(){
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        /**
         * 1、获取班级
         * 2、获取该班级的所有的学生
         * 3、遍历学生,把学生的班级设置为null
         * 4、新建两个学员
         * 5、建立两个学员与班级之间的关系
         */
        Classes classes = (Classes)session.get(Classes.class, 1L);//获取班级
        Set<Student> students = classes.getStudents();//获取班级的所有学生
        for(Student student:students){//遍历班级的学生
            student.setClasses(null);//解除学生对应的班级
        }
        Student student = new Student();//创建新学生
        student.setSname("菜肉");
        student.setDescription("厉害了我的菜肉");
        Student student2 = new Student();
        student2.setSname("包子");
        student2.setDescription("厉害了我的包子");
        student.setClasses(classes);
        student2.setClasses(classes);
        students.add(student);
        students.add(student2);
        /**
         * 当发生transaction.commit的时候,hibernate内部会检查所有的持久化对象
         *   会对持久化对象做一个更新,因为classes是一个持久化状态的对象,所以hibernate
         *   内部要对classes进行更新,因为在classes.hbm.xml文件中<set name="students" cascade="all" inverse="true">
         *   意味着在更新classes的时候,要级联操作student,而student是一个临时状态的对象
         *   所以要对student进行保存,在保存student的时候,就把外键更新了
         */
        transaction.commit();
        session.close();
    }
}

一对多的总结

一对多的操作:
   *  hibernate是通过客户端的代码参照映射文件来决定怎么样去数据库进行操作
   *  一对多的双向:既能通过Classes.hbm.xml文件联系到student,也能通过student.hbm.xml文件联系到
      classes,在类中也要体现双向的关系
   *  session.save/update(classes),hibernate内部会参照classes.hbm.xml文件,这个时候student.hbm.xml
      映射文件不起作用,反之也成立
   *  在hibernate一对多的关系中,只有一的一端的set集合中有inverse属性,多的一端没有inverse属性
   *  在hibernate中,inverse属性和数据库的外键对应
   *  在Classes.hbm.xml文件中,set集合,inverse的值如果为true,说明classes放弃关系的维护,如果为false,
      则负责维护关系,但是多的一方维护关系效率比较高
   * cascade说明指的是对象与对象之间的操作,和外键没有关系
   *  处于持久化状态的对象在session中,在客户端不需要做session.save/update操作,hiernate内部会自动去检查
      持久化状态的对象的属性是否发生改变,如果改变则发出update语句,如果没有改变则不会发出update语句。如果
      该对象是一的一方,在一的一方的映射文件中有cascade="all"时,hibernate内部还会检查该持久化对象关联的
      集合,对此集合做update/save操作。但是整个操作和外键没有关系。只有当通过多的一方建立关系以后,才能使
      外键有值
   *  一般一对多设计到关系的维护,都是通过多的一方来操作的
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值