Hibernate的一对多映射的单向关联和双向关联(九)

简介: Hibernate的一对多映射的单向关联和双向关联(九)

一.Hibernate的一对多的使用范围


在实际的生活和工作中,Hibernate的一对多的使用是最广的。如班级和学生,部门和员工,用户和购买商品,订单和商品等。这里用部门和员工进行举例说明。 运用部门的例子,主要是为下面的自关联做铺垫。一个部门可以有多个员工,但一个员工只能拥有一个部门。


二. 搭建Hibernate环境


跟一对一关联一样,这里就不进行说明了。具体可以参照以前写的博客。


三. 编写具体的实体类


三.一 编写Dept 部门类


package com.yjl.pojo;
/**
 @author: yuejl
 @date: 2019年2月16日 上午10:15:08
 @Description 数据库中一的一方 部门实体
*/
public class Dept {
  /**
   * @param id 部门的编号
   * @param name 部门的名称
   * @param description 部门的描述
   */
  private Integer id;
  private String name;
  private String description;
  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 String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }
  @Override
  public String toString() {
    return "Dept [id=" + id + ", name=" + name + ", description=" + description + "]";
  }
}


三.二 编写User 员工类


package com.yjl.pojo;
/**
 @author:两个蝴蝶飞
 @date: 2019年2月16日 上午10:20:08
 @Description 多的一方,用户实体
*/
public class User {
  /**
   * @param id 标识符Id
   * @param name 用户的名称
   * @param sex 用户的性别
   * @param age 用户的年龄
   * @param description 描述
   */
  private Integer id;
  private String name;
  private String sex;
  private Integer age;
  private String description;
  /*通过组合的方面,将部门引入到用户实体中*/
  /**
   * @param dept 用户所在的那个部门
   */
  private Dept dept;
  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 String getSex() {
    return sex;
  }
  public void setSex(String sex) {
    this.sex = sex;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public String getDescription() {
    return description;
  }
  public void setDescription(String description) {
    this.description = description;
  }
  public Dept getDept() {
    return dept;
  }
  public void setDept(Dept dept) {
    this.dept = dept;
  }
  @Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + ", description=" + description+ "]";
  }
}


四 编写具体的Xxx.hbm.xml文件


四.一 Dept.hbm.xml与以前的一样


<hibernate-mapping package="com.yjl.pojo" >
  <!-- 具体的实体类  由于前面指定了package包名。这里只需要写Dept即可。否则写com.yjl.pojo.Dept 全限定名称-->
  <class name="Dept" table="dept">
    <!-- 主键 -->
    <id name="id" column="id">
      <generator class="native"></generator>  
    </id>
    <!-- 其余属性  这里type运用的是java类型,并不是Hibernate和数据库的-->
    <property name="name" length="20" type="java.lang.String"></property>
    <property name="description" length="100" type="java.lang.String"></property>
  </class>
</hibernate-mapping>


四.二 User.hbm.xml 多添加一个标签


普通的属性,如id,name,sex,age,description与以前的方式一样。 但dept这个字段是不一样的。要用 标签。多对一。


<hibernate-mapping package="com.yjl.pojo" >
  <!-- 具体的实体类 -->
  <class name="User" table="user">
    <!-- 主键 -->
    <id name="id" column="id">
      <generator class="native"></generator>  
    </id>
    <!-- 其余属性  这里type运用的是java类型,并不是Hibernate和数据库的-->
    <property name="name" length="20" type="java.lang.String"></property>
    <property name="sex" length="2" type="java.lang.String"></property>
    <property name="age" length="3" type="java.lang.Integer"></property>
    <property name="description" length="100" type="java.lang.String"></property>
    <!-- 开始进行多对一的关联。 n对m,其中n指的是自己的一方。 m指的是要关联的一方。用户对部门,是多对一。
    部门对用户,是一对多。实际上Dept与package连用,构成全限定名称 -->
    <many-to-one name="dept" column="deptId" class="Dept"></many-to-one>
  </class>
</hibernate-mapping>


五.修改hibernate.cfg.xml的引用约束文件


<!-- 引入相应的约束文件  ctrl点击时可以正确进入-->
    <mapping resource="com/yjl/pojo/Dept.hbm.xml"/>
    <mapping resource="com/yjl/pojo/User.hbm.xml"/>


六. 编写测试文件


六.一 编写测试保存方法


/*单向测试保存*/
  @Test
  public void singleTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    /*2.实例化Dept类*/
    Dept dept=new Dept();
    dept.setName("开发部");
    dept.setDescription("一切为了开发");
    /*3. 实例化User类,并设置与部门的关系*/
    User user=new User();
    user.setName("两个蝴蝶飞");
    user.setSex("男");
    user.setAge(24);
    user.setDescription("一个充满希望的程序员");
    /*设置与部门的关系*/
    user.setDept(dept);
    /*4.进行保存*/
    session.save(dept);
    session.save(user);
  }


控制台依次输出了五个内容:


  1. 创建表dept
  2. 创建表user, 但没有外键引用
  3. 修改表user,引入dept的id字段做为外键
  4. 插入数据表dept表
  5. 插入数据表user表


20190216104533108.png


六.二 编写测试查询方法


/*单向的查询测试*/
  @Test
  public void singleSearchTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    /*2.查询 部门的search*/
    Dept dept=session.get(Dept.class,1);
    System.out.println("部门自己查询的:"+dept);
    /*3.查询员工的*/
    User user=session.get(User.class,1);
    System.out.println("员工自己查询的:"+user);
    /*4.通过员工找到他所在的部门的信息*/
    Dept dept2=user.getDept();
    System.out.println("通过员工找到他所在的部门:"+dept2);
  }


20190216105400602.png


六.三 扩充


1.能不能通过员工直接找到输出他所在的部门。即 将User类中的toString()方法改成:


@Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + ", description=" + description
        + ", dept=" + dept + "]";
  }


/*2.查询员工的*/
    User user=session.load(User.class,1);
    System.out.println("员工自己查询的:"+user);


这个时候再运行的话:


20190216105858633.png

也将部门信息查询了出来。


顺序是:


  1. 先修改user表中的外键
  2. 根据传递进去的参数员工编号,从user表中,将员工的信息查询出来。包括部门的编号。
  3. 根据部门的编号,从dept表中,将部门的信息查询出来。
  4. 将保存部门和员工的顺序进行改变,即先保存员工,后保存部门.


20190216110644468.png


这个时候,员工和部门均可以正常的保存。但是,员工是没有部门的。因为是先插入的员工,此时部门还没有插入。所以,应该先保存部门,然后根据部门的标识符插入员工表。


七. 单向的一对多的缺点


其实,实际开发中用单向的多一点。 但还是说一下吧。 现在,是只能根据员工去找部门,并不能解决查询部门下有多少个员工的问题。开发中用表连接去查。 如果部门中有一个保存员工的集合就好了,那么直接遍历这个集合就可以了。 这就是多向关联。


八.一对多的双向关联


不但要在User中表存储关于Dept的字段。还要在Dept中存储关于User的字段。 只不过,这个时候是集合。 一般用List,不用Set.


八.一 对Dept实体的改变


1.在Dept表中添加一个集合字段,实现setter和getter方法。 需要进行初始化。 添加的是Set集合,并不是List集合。切记


/**
   * @param users 存储员工集合
   */
  private Set<User> users=new HashSet<User>();


  1. 在Dept.hbm.xml中添加set的标签,在description 后面添加即可.


<!-- 添加一对多的关联  采用的是set标签,不是list. 这里面才有one-to-many. class标签里面没有-->
    <set name="users">
      <!-- 这个deptId 要与User.hbm.xml中的dept属性中的column保持一致 -->
      <key column="deptId"></key>
      <one-to-many class="User"/>
    </set>


不用对User.hbm.xml中进行改变。


九. 编写测试的方法


九.一 双向保存测试的方法


/*双向测试保存*/
  /*双向测试保存*/
  @Test
  public void bothTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    Dept dept=new Dept();
    dept.setName("开发部");
    dept.setDescription("一切为了开发");
    /*3. 实例化User类,并设置与部门的关系*/
    User user=new User();
    user.setName("两个蝴蝶飞");
    user.setSex("男");
    user.setAge(24);
    user.setDescription("一个有梦想的程序员");
    User user1=new User();
    user1.setName("两个蝴蝶飞1");
    user1.setSex("男");
    user1.setAge(24);
    user1.setDescription("一个有梦想的程序员");
    User user2=new User();
    user2.setName("两个蝴蝶飞2");
    user2.setSex("男");
    user2.setAge(24);
    user2.setDescription("一个有梦想的程序员");
    /*设置与部门的关系*/
    user.setDept(dept);
    user1.setDept(dept);
    user2.setDept(dept);
    session.save(dept);
    /*级联保存后,就不需要多次保存了。但是要用dept的方法,进行设置关系*/
    session.save(user);
    session.save(user1);
    session.save(user2);
  }


步骤与单向的一对多的步骤一样。


  1. 创建表dept
  2. 创建表user, 但没有外键引用
  3. 修改表user,引入dept的id字段做为外键
  4. 插入数据表dept表
  5. 插入数据表user表


20190216115019149.png


九.二 双向查询的方法


/*双向的查询测试*/
  @Test
  public void bothSearchTest(){
    /*1。通过工具类构建Session*/
    Session session=HibernateUtil.getSession();
    /*2.查询 部门的search*/
    Dept dept=session.get(Dept.class,1);
    System.out.println("部门自己查询的:"+dept);
    /*3.查询员工的*/
    User user=session.get(User.class,1);
    System.out.println("员工自己查询的:"+user);
    /*4.通过部门找到他的员工*/
    Set<User> userList=dept.getUsers();
    System.out.println("通过部门找到他所有的员工:");
    for (User user2 : userList) {
      System.out.println(user2);
    }
    /*5.通过员工找到他所在的部门的信息*/
    Dept dept2=user.getDept();
    System.out.println("通过员工找到他所在的部门:"+dept2);
  }


20190216115214262.png


这个时候,查询员工时,员工所在的部门也是可以查询出来的。


九.三 扩充


  1. 上面查询的方法, 如果按钮dept2继续查询呢? 即:


    /*5.通过员工找到他所在的部门的信息*/
    Dept dept2=user.getDept();
    System.out.println("通过员工找到他所在的部门:"+dept2);
    Set<User> userList2=dept2.getUsers();
    System.out.println("再次通过部门找到他所有的员工:");
    for (User user2 : userList2) {
      System.out.println(user2);
    }


也是可以正常查询的。


20190216115628230.png


2. 如果 部门的toString() 方法中添加输出users呢? 注意:上面的Dept类toString()方法中没有users的输出。另外,一定要注意,User类中toString() 方法中有dept的输出。 此时,输出dept时—>users中输出user---->找到dept2---->输出此时dept2中的users, 这是一个环,即递归调用的死循环。


2019021612013072.png


运行的结果是:


20190216120158118.png


栈溢出了。是Errror,不是Exception。 注意,调用的时候,千万不要形成一个环。


3. 按照2的思路继续思考,此时将User中toString()去除掉dept的输出,保留dept中users的输出呢。


20190216120526827.png


此刻显示的是正常的。 用的时候,一定要注意这一点。


4.一对多中set标签,如果column不一样呢,会造成什么呢?


以前是deptId,现在改成deptId1, 即Dept中的column与User中的column关于外键的列名不一样。


20190216120709172.png


运行的是bothTest() 方法后,没有报错。但,这是什么啊? 故,切记: Hibernate运行生成表之后,一定要看一下,生成的表是不是自己想要的。并不是生成表,无报错,就是OK了。


20190216120925589.png


谢谢!!!

相关文章
|
2月前
|
Java 数据库连接 API
解锁高效开发秘籍:深入探究 Hibernate 如何优雅处理一对多与多对多关系,让数据映射再无烦恼!
【9月更文挑战第3天】Hibernate 是 Java 领域中最流行的 ORM 框架之一,广泛用于处理实体对象与数据库表之间的映射。尤其在处理复杂关系如一对多和多对多时,Hibernate 提供了丰富的 API 和配置选项。本文通过具体代码示例,展示如何使用 `@OneToMany`、`@JoinColumn`、`@ManyToMany` 和 `@JoinTable` 等注解优雅地实现这些关系,帮助开发者保持代码简洁的同时确保数据一致性。
52 4
|
3月前
|
Java 数据库连接 数据库
AI 时代风起云涌,Hibernate 实体映射引领数据库高效之路,最佳实践与陷阱全解析!
【8月更文挑战第31天】Hibernate 是一款强大的 Java 持久化框架,可将 Java 对象映射到关系数据库表中。本文通过代码示例详细介绍了 Hibernate 实体映射的最佳实践,包括合理使用关联映射(如 `@OneToMany` 和 `@ManyToOne`)以及正确处理继承关系(如单表继承)。此外,还探讨了常见陷阱,例如循环依赖可能导致的无限递归问题,并提供了使用 `@JsonIgnore` 等注解来避免此类问题的方法。通过遵循这些最佳实践,可以显著提升开发效率和数据库操作性能。
84 0
|
3月前
|
数据库 开发者 Java
Hibernate映射注解的魔力:实体类配置的革命,让你的代码量瞬间蒸发!
【8月更文挑战第31天】Hibernate 是一款出色的对象关系映射框架,简化了 Java 应用与数据库的交互。其映射注解让实体类配置变得直观简洁。本文深入剖析核心概念与使用技巧,通过示例展示如何简化配置。
45 0
|
SQL XML 存储
Hibernate框架【五】——基本映射——多对多映射
Hibernate框架【五】——基本映射——多对多映射
191 0
|
6月前
|
缓存 Java 数据库连接
Hibernate或MyBatis:ORM映射、缓存机制等知识讲解梳理
Hibernate或MyBatis:ORM映射、缓存机制等知识讲解梳理
129 0
|
6月前
|
Java 数据库连接 数据库
Hibernate5中实体映射命名策略
Hibernate5中实体映射命名策略
134 0
|
6月前
|
SQL 存储 Java
Hibernate - 继承关联关系映射
Hibernate - 继承关联关系映射
71 0
|
6月前
|
SQL XML Java
Hibernate - 单向多对一关联关系映射
Hibernate - 单向多对一关联关系映射
39 0
|
6月前
|
SQL Java 关系型数据库
Hibernate - Java 类型, Hibernate 映射类型及 SQL 类型之间的对应关系
Hibernate - Java 类型, Hibernate 映射类型及 SQL 类型之间的对应关系
63 0
|
SQL XML Java
Hibernate框架【四】——基本映射——多对一和一对多映射
Hibernate框架【四】——基本映射——多对一和一对多映射
173 0