你的位置:首页 > Java教程

[Java教程]Hibernate(六)一对多映射(多对一)


一、Hinbernate中持久化类的关联关系

在数据库中,表表之间是通过外键关联的,在程序中是要转化为持久化类也就是(JAVA Bean)来实例的。

但在Hibernater中持久化的之间的映射关系,不是通外键建立关联,而是通过属性.主要有以下几种

  • 一对一,
  • 一对多(多对一)
  • 多对多

关联方向:

  • 单向关联
  • 双向关联

二、一对多单向关联关系

2.1、建立数据库表

班级表,和学生表,学生生通过班级表中的,班级编号为外键

--班级表create table grade(    gid    number      primary key, --班级ID    gname   varchar2(50),         --班级名称    gdesc   varchar2(50)          --班级介绍);--学生表create table student(    sid    number      primary key, --主键ID学生ID    sname   varchar2(20),      --学生姓名    sex    varchar2(20),      --学生性别    gid    number      references grade(gid) ---外键班级ID);

2.2、建立持久化类和映射配置文件

班级和学生类

package entity;import java.util.HashSet;import java.util.Set;/* * 班级类 */public class Grade implements java.io.Serializable {  // Fields  private static final long serialVersionUID = 1L;  private int gid;  private String gname;  private String gdesc;  private Set<Student> students = new HashSet<Student> ();  // Constructors  /** default constructor */  public Grade() {  }  /** minimal constructor */  public Grade(int gid) {    this.gid = gid;  }  /** full constructor */  public Grade(int gid, String gname, String gdesc, Set<Student> students) {    this.gid = gid;    this.gname = gname;    this.gdesc = gdesc;    this.students = students;  }  // Property accessors  public int getGid() {    return this.gid;  }  public void setGid(int gid) {    this.gid = gid;  }  public String getGname() {    return this.gname;  }  public void setGname(String gname) {    this.gname = gname;  }  public String getGdesc() {    return this.gdesc;  }  public void setGdesc(String gdesc) {    this.gdesc = gdesc;  }  public Set<Student> getStudents() {    return this.students;  }  public void setStudents(Set<Student> students) {    this.students = students;  }}

View Code

 

学生类

package entity;/* * 学生类 */public class Student implements java.io.Serializable {  // Fields  private static final long serialVersionUID = 1L;  private int sid;    private String sname;  private String sex;  // Constructors  /** default constructor */  public Student() {  }  /** minimal constructor */  public Student(int sid) {    this.sid = sid;  }  /** full constructor */  public Student(int sid, String sname, String sex ) {      this.sid = sid;    this.sname = sname;    this.sex = sex;  }  // Property accessors  public int getSid() {    return this.sid;  }  public void setSid(int sid) {    this.sid = sid;  }    public String getSname() {    return this.sname;  }  public void setSname(String sname) {    this.sname = sname;  }  public String getSex() {    return this.sex;  }  public void setSex(String sex) {    this.sex = sex;  }}

View Code

 

 

hibernate.cf.

<??><!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="dialect">    org.hibernate.dialect.Oracle9Dialect  </property>  <property name="connection.url">    jdbc:oracle:thin:@localhost:1521:orcl  </property>  <property name="connection.username">root</property>  <property name="connection.password">root</property>  <property name="connection.driver_class">    oracle.jdbc.OracleDriver  </property>  <property name="show_sql">true</property>  <property name="format_sql">true</property>  <mapping resource="entity/Grade.hbm. />  <mapping resource="entity/Student.hbm. /></session-factory></hibernate-configuration>

持久类配置先来学生类

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Student" table="STUDENT" schema="ROOT">    <id name="sid" type="java.lang.Integer">      <column name="SID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="sname" type="java.lang.String">      <column name="SNAME" length="20" />    </property>    <property name="sex" type="java.lang.String">      <column name="SEX" length="20" />    </property>  </class></hibernate-mapping>

班级类配置

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Grade" table="GRADE" schema="ROOT">    <id name="gid" type="java.lang.Integer">      <column name="GID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="gname" type="java.lang.String">      <column name="GNAME" length="50" />    </property>    <property name="gdesc" type="java.lang.String">      <column name="GDESC" length="50" />    </property>    <!--建立set属性,也可以建立list和持久化类中一致就行 -->    <set name="students">      <key>      <!--这里的列是指学生表中的班级编号 -->        <column name="GID" precision="22" scale="0" />      </key>      <!-- 通过class属性指定set的属性 -->      <one-to-many class="entity.Student" />    </set>  </class></hibernate-mapping>

测试类

package Test;import java.util.Set;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import entity.Grade;import entity.Student;public class Demo1 {  /**   * 测试类   */  public static void main(String[] args) {    save();     find();    update();  }  public static void save() {    // 声明班级对象,并赋值    Grade grade = new Grade();    grade.setGid(201504);    grade.setGname("Java一班");    grade.setGdesc("刚开始学习JAVA");    // 声明2个学生对象    Student stu1 = new Student();    stu1.setSid(201504012);    stu1.setSname("张三");    stu1.setSex("男");    Student stu2 = new Student();    stu2.setSid(201504013);    stu2.setSname("李四");    stu2.setSex("女");    // 将学生添加到班级    grade.getStudents().add(stu1);    grade.getStudents().add(stu2);    // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    // 开始事务    Transaction transaction = session.beginTransaction();    // 保存班级    session.save(grade);    // 保存学生    session.save(stu1);    session.save(stu2);    // 提交事务    transaction.commit();    // 关闭session    session.close();  }  /*   * 将基中一个学生更改为别一个班级   */  public static void update() {    // 声明班级对象,并赋值    Grade grade = new Grade();    grade.setGid(201506);    grade.setGname("Java二班");    grade.setGdesc("学习JAVA二年级");    // 获取一个学生的信息    // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    // 开始事务    Transaction transaction = session.beginTransaction();    Student stu1=(Student) session.get(Student.class, 201504013);    //将学生添加到这个新的班级    grade.getStudents().add(stu1);    // 保存班级    session.save(grade);    // 保存学生    session.save(stu1);    // 提交事务    transaction.commit();    // 关闭session    session.close();  }  // 查询班级  public static void find() {    // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    Grade g = (Grade) session.get(Grade.class, 201504);    System.out.println("班级信息:" + g.getGid() + "\t" + g.getGname()        + g.getGdesc());    // 通过班级获取这个班级的学生信息    System.out.println("201504班的学生信息如下:");    Set<Student> set = g.getStudents();    for (Student stu : set) {      System.out.println(stu.getSid() + "\t" + stu.getSname() + "\t"          + stu.getSex());    }  }}

以上只上单向关联,一般都会有双向关联

同样要在学生类中添加Grade 属性

在学生类的配置文件中配置关联字段

 二、建立双向关联

2.1、更改学生类和配置文件

package entity;/* * 学生类 */public class Student implements java.io.Serializable {  // Fields  private static final long serialVersionUID = 1L;  private int sid;  private String sname;  private String sex;  //增加班级属性  private Grade grade;  // Constructors  /** default constructor */  public Student() {  }  /** minimal constructor */  public Student(int sid) {    this.sid = sid;  }  /** full constructor */  public Student(int sid, String sname, String sex ) {      this.sid = sid;    this.sname = sname;    this.sex = sex;  }  // Property accessors  public int getSid() {    return this.sid;  }  public void setSid(int sid) {    this.sid = sid;  }    public String getSname() {    return this.sname;  }  public void setSname(String sname) {    this.sname = sname;  }  public String getSex() {    return this.sex;  }  public void setSex(String sex) {    this.sex = sex;  }  public Grade getGrade() {    return grade;  }  public void setGrade(Grade grade) {    this.grade = grade;  }  }

配置文件 

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Student" table="STUDENT" schema="ROOT">    <id name="sid" type="java.lang.Integer">      <column name="SID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="sname" type="java.lang.String">      <column name="SNAME" length="20" />    </property>    <property name="sex" type="java.lang.String">      <column name="SEX" length="20" />    </property>    <!--配置grade属性 -->    <many-to-one name="grade" class="entity.Grade">    <!--指定学生表中的外键 -->    <column name="GID" />    </many-to-one>  </class></hibernate-mapping>

2.2、测试类

建立双向关联后,就可以通过学生来获取班级信息

清空数据表中的数据

package Test;import org.hibernate.Session;import org.hibernate.cfg.Configuration;import entity.Student;public class Demo2 {  /**   * 测试类   */  public static void main(String[] args) { save();findByStu();  }    public static void findByStu(){    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    //获取一个学生的信息 get方法为通过主键查询    Student stu=(Student) session.get(Student.class, 201504013);    System.out.println("学生信息:\t"+stu.getSid()+"\t"+stu.getSname()+"\t"+stu.getSex());    //通过学生信息得到班级信息    System.out.println("这个学生的班级信息:"+stu.getGrade().getGid()+"\t"+stu.getGrade().getGname()+"\t"+stu.getGrade().getGdesc());  }}public static void save() {// 声明班级对象,并赋值Grade grade = new Grade();grade.setGid(201504);grade.setGname("Java一班");grade.setGdesc("刚开始学习JAVA");// 声明2个学生对象Student stu1 = new Student();stu1.setSid(201504012);stu1.setSname("张三");stu1.setSex("男");stu1.setGrade(grade);Student stu2 = new Student();stu2.setSid(201504013);stu2.setSname("李四");stu2.setSex("女");stu2.setGrade(grade);// 将学生添加到班级/*grade.getStudents().add(stu1);grade.getStudents().add(stu2);*/// 建立sessionSession session = new Configuration().configure().buildSessionFactory().openSession();// 开始事务Transaction transaction = session.beginTransaction();// 保存班级session.save(grade);// 保存学生session.save(stu1);session.save(stu2);// 提交事务transaction.commit();// 关闭sessionsession.close();}

三、级联保存和删除

能不能只保存学生时,同时保存班级呢,或者保存班级时,同时保存学生呢

3.1、cascade属性

 

保存班级时,同时保存学生信息

修改班级配置,在set标签中添加cascade属性,设置为save-update

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Grade" table="GRADE" schema="ROOT">    <id name="gid" type="java.lang.Integer">      <column name="GID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="gname" type="java.lang.String">      <column name="GNAME" length="50" />    </property>    <property name="gdesc" type="java.lang.String">      <column name="GDESC" length="50" />    </property>    <!--建立set属性,也可以建立list和持久化类中一致就行 -->    <set name="students" cascade="save-update">      <key>      <!--这里的列是指学生表中的班级编号 -->        <column name="GID" precision="22" scale="0" />      </key>      <!-- 通过class属性指定set的属性 -->      <one-to-many class="entity.Student" />    </set>  </class></hibernate-mapping>

测试类

package Test;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import entity.Grade;import entity.Student;public class Demo3 {  /**   * @param args   */  public static void main(String[] args) {    save();  }  public static void save() {    // 声明班级对象,并赋值    Grade grade = new Grade();    grade.setGid(201504);    grade.setGname("Java一班");    grade.setGdesc("刚开始学习JAVA");    // 声明2个学生对象    Student stu1 = new Student();    stu1.setSid(201504012);    stu1.setSname("张三");    stu1.setSex("男");    stu1.setGrade(grade);            Student stu2 = new Student();    stu2.setSid(201504013);    stu2.setSname("李四");    stu2.setSex("女");    stu2.setGrade(grade);    // 将学生添加到班级    grade.getStudents().add(stu1);    grade.getStudents().add(stu2);    // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    // 开始事务    Transaction transaction = session.beginTransaction();    // 保存班级    session.save(grade);    // 保存学生    //session.save(stu1);    //session.save(stu2);    // 提交事务    transaction.commit();    // 关闭session    session.close();  }}

反之,在学生类的配置文件one-many中添加cascade属性设置为save-update

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Student" table="STUDENT" schema="ROOT">    <id name="sid" type="java.lang.Integer">      <column name="SID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="sname" type="java.lang.String">      <column name="SNAME" length="20" />    </property>    <property name="sex" type="java.lang.String">      <column name="SEX" length="20" />    </property>    <!--配置grade属性 -->    <many-to-one name="grade" class="entity.Grade" cascade="save-update">    <!--指定学生表中的外键 -->    <column name="GID" />    </many-to-one>  </class></hibernate-mapping>

package Test;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import entity.Grade;import entity.Student;public class Demo3 {  /**   * @param args   */  public static void main(String[] args) {    save();  }  public static void save() {    // 声明班级对象,并赋值    Grade grade = new Grade();    grade.setGid(201504);    grade.setGname("Java一班");    grade.setGdesc("刚开始学习JAVA");    // 声明2个学生对象    Student stu1 = new Student();    stu1.setSid(201504012);    stu1.setSname("张三");    stu1.setSex("男");    stu1.setGrade(grade);            Student stu2 = new Student();    stu2.setSid(201504013);    stu2.setSname("李四");    stu2.setSex("女");    stu2.setGrade(grade);    // 将学生添加到班级    grade.getStudents().add(stu1);    grade.getStudents().add(stu2);    // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    // 开始事务    Transaction transaction = session.beginTransaction();    // 保存班级    //session.save(grade);    // 保存学生    session.save(stu1);    session.save(stu2);    // 提交事务    transaction.commit();    // 关闭session    session.close();  }}

View Code

 

3.2、inverse属性

 

首先在班级类中设置invers属性为false时,删除班级

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Grade" table="GRADE" schema="ROOT">    <id name="gid" type="java.lang.Integer">      <column name="GID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="gname" type="java.lang.String">      <column name="GNAME" length="50" />    </property>    <property name="gdesc" type="java.lang.String">      <column name="GDESC" length="50" />    </property>    <!--建立set属性,也可以建立list和持久化类中一致就行 -->    <set name="students" cascade="save-update" inverse="false">      <key>      <!--这里的列是指学生表中的班级编号 -->        <column name="GID" precision="22" scale="0" />      </key>      <!-- 通过class属性指定set的属性 -->      <one-to-many class="entity.Student" />    </set>  </class></hibernate-mapping>

View Code

测试类

package Test;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import entity.Grade;import entity.Student;public class Demo4 {  /**   * @param args   */  public static void main(String[] args) {    delete() ;  }  public static void delete() {        // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    // 开始事务    Transaction transaction = session.beginTransaction();    // 保存班级    Grade grade=(Grade) session.get(Grade.class, 201504);    // 保存学生    session.delete(grade);    // 提交事务    transaction.commit();    // 关闭session    session.close();  }}

View Code

结果:发现班级表中的班级已经删除,而学生表中数据没有删除,只是GID字段为NULL

下面将inverse设置为true时,添加新学生,和新的班级

<??><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping>  <class name="entity.Grade" table="GRADE" schema="ROOT">    <id name="gid" type="java.lang.Integer">      <column name="GID" precision="22" scale="0" />      <generator class="assigned" />    </id>    <property name="gname" type="java.lang.String">      <column name="GNAME" length="50" />    </property>    <property name="gdesc" type="java.lang.String">      <column name="GDESC" length="50" />    </property>    <!--建立set属性,也可以建立list和持久化类中一致就行 -->    <set name="students" cascade="save-update" inverse="true">      <key>      <!--这里的列是指学生表中的班级编号 -->        <column name="GID" precision="22" scale="0" />      </key>      <!-- 通过class属性指定set的属性 -->      <one-to-many class="entity.Student" />    </set>  </class></hibernate-mapping>

View Code

测试类

package Test;import org.hibernate.Session;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import entity.Grade;import entity.Student;public class Demo4 {  /**   * @param args   */  public static void main(String[] args) {    delete() ;  }  public static void delete() {        // 声明班级对象,并赋值        Grade grade = new Grade();        grade.setGid(201509);        grade.setGname("Java三班");        grade.setGdesc("ASP.NET");        // 声明2个学生对象        Student stu1 = new Student();        stu1.setSid(201509009);        stu1.setSname("王五");        stu1.setSex("女");        stu1.setGrade(grade);                Student stu2 = new Student();        stu2.setSid(201509045);        stu2.setSname("赵六");        stu2.setSex("女");        stu2.setGrade(grade);        // 建立session    Session session = new Configuration().configure().buildSessionFactory()        .openSession();    // 开始事务    Transaction transaction = session.beginTransaction();          // 保存学生    session.save(stu1);    session.save(stu2);    // 提交事务    transaction.commit();    // 关闭session    session.close();  }}

View Code

结果发现,我并没有用班级添加学生,也没有保存班级,只是保存了学生,班级信息一起保存了