欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Hibernate学习笔记】7:单向1-N关联和双向1-N关联,其中的Lazy Loading(懒加载)

程序员文章站 2022-04-22 16:10:57
...

单向1-N关联

如果在Teacher的POJO中组合了所有该老师带的Student对象,而在Student的属性中没有他所属的Teacher,这种情况就是单向1-N关联,即从1的一方去维护所有的相关的N。

在教师的POJO类添加

// 新增的该老师所带的全部学生,设定HashSet的初始容量是0
private Set<Student> set_stu = new HashSet<Student>(0);

// 有参构造器,新增这个学生集合
public Teacher(String tchrNo, String tchrName, Integer mny, Set<Student> stu) {
    this.tchrNo = tchrNo;
    this.tchrName = tchrName;
    this.mny = mny;
    this.set_stu = stu;// 新增
}

//对它所组合的Student集合生成getter和setter

public Set<Student> getSet_stu() {
    return set_stu;
}

public void setSet_stu(Set<Student> set_stu) {
    this.set_stu = set_stu;
}

在学生的POJO类修改

注释掉组合了所属Teacher的属性和相关的方法,在单向1-N关联中不允许N方的对象能直接获取所关联的1方。

// private Teacher tchr;

// 有参构造器,去掉这一参数
public Student(String stuNo, String stuName, Date dtIn/* , Teacher tchr */) {
    this.stuName = stuName;
    this.stuNo = stuNo;
    this.dtIn = dtIn;
    // this.tchr = tchr;
}

// 注释掉原Teacher属性的getter和setter

//  public Teacher getTchr() {
//      return tchr;
//  }
//
//  public void setTchr(Teacher tchr) {
//      this.tchr = tchr;
//  }

更改教师的映射文件

注意只要是1-N关联都是N方外键引用1方主键,数据库中表的结构还是和上篇生成的一样的。只是关联的方向不同,显示在面向对象层面的维护方式不同。

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="myPOJO">
    <class name="Teacher" table="TeacherTable">

        <id name="id" column="ID" type="int">
            <generator class="native" />
        </id>

        <property name="tchrNo" column="TCHRNO" type="string" not-null="true" />
        <property name="tchrName" type="string" not-null="true">
            <column name="TCHRNAME" />
        </property>
        <property name="mny" column="MONEY" type="int" not-null="false" />

        <!--新增单向1-N关联中1方的集合属性,指出属性名-->
        <set name="set_stu">
            <!--指出N方表中外键的字段名,只要是1-N关联都是N方外键引用1方主键-->
            <key column="TEACHER_ID"/>
            <!--指出所维护的N方所在的POJO类-->
            <one-to-many class="Student"/>
        </set>

    </class>
</hibernate-mapping>

更改学生的映射文件

注释掉上篇配置的N-1映射。

<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="myPOJO">
    <class name="Student" table="StudentTable">

        <id name="id" column="ID" type="int">
            <generator class="native" />
        </id>

        <property name="stuNo" column="STUNO" type="string" not-null="true" />
        <property name="stuName" type="string" not-null="true">
            <column name="STUNAME" />
        </property>
        <property name="dtIn" column="DATEIN" type="date" not-null="true" />

        <!-- <many-to-one name="tchr" column="TEACHER_ID" class="Teacher" not-null="false" cascade="all"/> -->

    </class>
</hibernate-mapping>

在主类中测试

因为Hibernate的懒加载策略,当不确定会使用这种需要额外查询才能获得的PO中组合的N方的集合时,并不会去加载它。如果提前关闭了Session,如在下面中的第18行或者第23行,将没有办法依靠1-N关联从1方中获取N方的集合。

import java.util.Set;

import myPOJO.Student;
import myPOJO.Teacher;
import myTools.HibernateUtils;

import org.hibernate.Session;

//测试学生到班主任的N-1关系映射
public class Main {

    // 主方法
    public static void main(String[] args) {
        // 根据逻辑主键id来获取一个教师PO
        System.out.println("根据逻辑主键id来获取一个教师PO");
        Session sssn = HibernateUtils.getSession();
        Teacher tchr = (Teacher) sssn.get(Teacher.class, 1);
        // HibernateUtils.closeSession();

        // 因为存在单向1-N映射,从这个教师PO中可以获取其所有学生
        System.out.println("因为存在单向1-N映射,从这个教师PO中可以获取其所有学生");
        Set<Student> set_stu_from_tchr = tchr.getSet_stu();
        // HibernateUtils.closeSession();
        System.out.println(tchr.getTchrName() + "的学生有这些:");
        System.out.println("逻辑主键\t学号\t姓名\t入学时间");
        for (Student s : set_stu_from_tchr) {
            System.out.println(s.getId() + "\t" + s.getStuNo() + "\t"
                    + s.getStuName() + "\t" + s.getDtIn());
        }

        // 因为Hibernate的懒加载,在单向1-N中不去主动getN方的集合时并不会去从数据库中读到PO里
        HibernateUtils.closeSession();
    }
}

运行结果

根据逻辑主键id来获取一个教师PO
Hibernate: select teacher0_.ID as ID1_1_0_, teacher0_.TCHRNO as TCHRNO2_1_0_, teacher0_.TCHRNAME as TCHRNAME3_1_0_, teacher0_.MONEY as MONEY4_1_0_ from TeacherTable teacher0_ where teacher0_.ID=?
因为存在单向1-N映射,从这个教师PO中可以获取其所有学生
大司马的学生有这些:
逻辑主键    学号  姓名  入学时间
Hibernate: select set_stu0_.TEACHER_ID as TEACHER_5_1_0_, set_stu0_.ID as ID1_0_0_, set_stu0_.ID as ID1_0_1_, set_stu0_.STUNO as STUNO2_0_1_, set_stu0_.STUNAME as STUNAME3_0_1_, set_stu0_.DATEIN as DATEIN4_0_1_ from StudentTable set_stu0_ where set_stu0_.TEACHER_ID=?
2   S0002   刘傻逼 2018-04-20
1   S0001   刘知昊 2018-04-20

双向1-N关联

双向1-N关联就是双向N-1关联,只要再将前面对N方POJO及其映射文件的注释解除就可以实现,即单向1-N和单向N-1共同使用。

尽量使用双向1-N关联而不是单向1-N关联。因为懒加载的存在,双向1-N关联比单向N-1关联带来的代价不高。