Hibernate入门—— 一对多多对多关系

Posted gdwkong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate入门—— 一对多多对多关系相关的知识,希望对你有一定的参考价值。

一、一对多关系

1.概念

​   一对多关系是关系型数据库中两个表之间的一种关系。通常在数据库层级中,两表之间是有主外键关系的。在ORM中,如何通过对象描述表之间的关系,是ORM核心。

2.Hibernate的一对多关联映射【重点】

2.1表关系的分析

mysql语句

CREATE TABLE `t_category` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`cid`)
);
​
CREATE TABLE `t_product` (
  `pid` int(11) NOT NULL AUTO_INCREMENT,
  `pname` varchar(255) DEFAULT NULL,
  `price` double DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`pid`),
  KEY `FKq8yr5sflwtcj3jqp58x0oy7lx` (`cid`),
  CONSTRAINT `FKq8yr5sflwtcj3jqp58x0oy7lx` FOREIGN KEY (`cid`) REFERENCES `t_category` (`cid`)
);

2.2创建持久化类

  • Category.java(一的一方)

     1 public class Category {
     2     private Integer cid;
     3     private String cname;
     4     //在一的一方,用一个集合表示和product的关系
     5     private Set<Product> products = new HashSet<Product>();
     6     
     7     public Integer getCid() {
     8         return cid;
     9     }
    10     public void setCid(Integer cid) {
    11         this.cid = cid;
    12     }
    13     public String getCname() {
    14         return cname;
    15     }
    16     public void setCname(String cname) {
    17         this.cname = cname;
    18     }
    19     public Set<Product> getProducts() {
    20         return products;
    21     }
    22     public void setProducts(Set<Product> products) {
    23         this.products = products;
    24     }
    25 }
  • Product.java(多的一方)

     1 public class Product {
     2     private Integer pid;
     3     private String pname;
     4     private double price;
     5     //用一个对象表示,当前商品属于哪个类别
     6     private Category category;
     7  8     public Integer getPid() {
     9         return pid;
    10     }
    11 12     public void setPid(Integer pid) {
    13         this.pid = pid;
    14     }
    15 16     public String getPname() {
    17         return pname;
    18     }
    19 20     public void setPname(String pname) {
    21         this.pname = pname;
    22     }
    23 24     public double getPrice() {
    25         return price;
    26     }
    27 28     public void setPrice(double price) {
    29         this.price = price;
    30     }
    31 32     public Category getCategory() {
    33         return category;
    34     }
    35 36     public void setCategory(Category category) {
    37         this.category = category;
    38     }
    39     
    40 }
2.3创建映射
  • 分类的映射

    <hibernate-mapping>
        <class name="com.pri.bean.Category" table="t_category">
            <!--一,主键属性  -->
            <id name="cid" column="cid">
                <generator class="native"></generator>
            </id>
            <!-- 二,其它属性 -->
            <property name="cname" column="cname"/>
        
            <!-- 三,表示和商品的关系 -->
            <!--3.1 set标签的name属性:多的一方的集合的名字  -->
            <set name="products">
                <!--3.2 key的 column表示多的一方外键名 -->
                <key column="cid"/>
                <!--3.3 one-to-many的class属性表示多的一方类的全限定名  -->
                <one-to-many class="com.pri.bean.Product"/>
            </set>
        </class>
    </hibernate-mapping>
  • 商品的映射

    <hibernate-mapping>
        <class name="com.pri.bean.Product" table="t_product">
            <!--一,主键属性  -->
            <id name="pid" column="pid">
                <generator class="native"></generator>
            </id>
            <!-- 二,其它属性 -->
            <property name="pname" column="pname"/>
            <property name="price" column="price"/>
        
            <!-- 三,表示和分类的关系 -->
            <!--3.1name:一的一方对象的名字
                  class: 一的一方类的全限定名
                  column:外键的名字
              -->
            <many-to-one name="category" class="com.pri.bean.Category" column="cid"/>
        </class>
    </hibernate-mapping>
2.4将映射添加到配置文件
<!-- 三、加载映射关系配置 -->
<mapping resource="com/pri/bean/Product.hbm.xml"/>
<mapping resource="com/pri/bean/Category.hbm.xml"/>

2.5写代码测试

  • TestDb

    public class TestDb {
        
        @Test
        public void fun01(){
            Session session = HibernateUtils.openSession();
             Transaction transaction = session.beginTransaction();
           
             transaction.commit();
             session.close();
        }
    ​
    }

3.级联操作

3.1概念

​   如果我们对某一个表进行了操作,那么也会顺带对关联表进行操作。或者说当对主对象进行某种操作时是也对其关联的从对象也作类似的操作.

​   eg:如果我们删除了一个公司,那么就得要求,员工表也得把属于这个公司的所有员工也删除掉。

​   如果我们删除了一个类别, 那么该类别下的商品是否要删除或者不删除只删除外键,那么这样的操作就属于级联操作了.

3.2 级联保存和修改
3.2.1 操作一方级联保存多方【掌握】
  • 保存Category(一的一方)的时候级联保存Product(多的一方)

  • 应用场景: 保存一方的同时也需要保存多方(并且多方的数据比较多). eg: 订单和订单项

  • <!-- 三、表示和商品的关系 -->
    <!-- 3.1 set标签的name属性:多的一方的集合的名字 -->
    <set name="products" cascade="save-update"/>
        <!-- 3.2 key的column表示多的一方外键名 -->
        <key column="cid"/>
        <!-- 3.3 one-to-many的class属性表示多的一方类的全限定名 -->
        <one-to-many class="com.pri.bean.Product"/>
    </set>
 1    /**
 2     * 只保存分类,通过级联把当前分类下的商品也保存
 3      * 配置: 在category.hbm.xml下设置:
 4      *      <set cascade="save-update">
 5      */
 6     @Test
 7     public void fun02(){
 8         Session session = HibernateUtils.openSession();
 9         Transaction transaction = session.beginTransaction();
10         
11         Category c1 = new Category();
12         c1.setCname("水果");
13         
14         Product p1 = new Product();
15         p1.setPname("苹果");
16         p1.setPrice(5);
17         
18         //c1和p1 产生关系
19         c1.getProducts().add(p1);
20         //p1和c1产生关系
21         p1.setCategory(c1);
22         session.save(c1);
23         //session.save(p1);不需要了,通过级联保存特性自动保存
24         transaction.commit();
25         session.close();
26     }
3.2.2操作多方级联保存一方【了解】

 

 

 

 

<!--三.表示和分类的关系 -->
<!-- 3.1 name:一的一方对象的名字
        class: 一的一方类的全限定名
        column:外键的名字
-->
<many-to-one name="category" class="com.pri.bean.Category" column="cid" cascade="save-update"/>
  • 保存Product(多的一方的)的时候级联保存Category(一的一方)

     1    /**
     2      * 只保存商品,通过级联的特性保存商品对应的分类
     3      * 配置: 在product.hbm.xml下设置:
     4      *      <many-to-one cascade="save-update"/>
     5      */
     6     @Test
     7     public void fun03(){
     8         Session session = HibernateUtils.openSession();
     9         Transaction transaction = session.beginTransaction();
    10         
    11         Category c1 = new Category();
    12         c1.setCname("水果");
    13         
    14         Product p1 = new Product();
    15         p1.setPname("苹果");
    16         p1.setPrice(5);
    17         
    18         //p1和c1发生关系
    19         p1.setCategory(c1);
    20         
    21         session.save(p1);
    22       
    23         //session.save(c1); 不需要了
    24         
    25         transaction.commit();
    26         session.close();
    27     }
3.3级联删除
3.3.1删除一方级联删除多方【掌握】
  • 删除Category(一的一方)的时候级联删除Product(多的一方)

  • 场景: 删除一方的时候确保多方的数据没有任何用途的时候的才会用. eg: 公司和员工

  • 实际开发里面很少删除用户的数据. 通常用一个字段标识的

  • <!--  三.表示和商品的关系 -->
    <!-- 3.1 set标签的name属性:多的一方的集合的名字 -->
    <set name="products" cascade="delete">
        <!--3.2 key 的column表示多的一方外键名 -->
        <key column="cid"/>
        <!-- 3.3 one-to-many的class属性表示多的一方类的全限定名 -->
        <one-to-many class="com.pri.bean.Product"/>
    </set>
  •  1 @Test
     2 //级联删除商品: 删除id为1的类别,级联删除当前类别下的所有商品
     3 //因为删除的是类别,所有在Category.hbm.xml配置:<set name="products" cascade="delete">
     4 public void fun03(){
     5       Session session = HibernateUtils.getCurrentSession();
     6       Transaction transaction = session.beginTransaction();
     7                  
     8       //先查 id为1的类别
     9       Category category = session.get(Category.class, 1);
    10       session.delete(category);
    11       transaction.commit();
    12 }
3.3.2 删除多方级联删除一方【了解】
  • 删除Product(多的一方)的时候级联删除Category(一的一方)

    <!--三.表示和分类的关系 -->
         <!-- 3.1 name:一的一方对象的名字
                 class: 一的一方类的全限定名
                 column:外键的名字
         -->
    <many-to-one name="category" class="com.pri.bean.Category" column="cid" cascade="delete"/>
 1    @Test
 2      //级联删除分类: 删除id为1的商品,级联删除这个商品所属的类别(了解)
 3      //把当前id为1商品删除,把这个商品所属的类别删除, 商品表里面该类别其它的商品的记录的外键置为null;
 4      public void fun04(){
 5          Session session = HibernateUtils.getCurrentSession();
 6          Transaction transaction = session.beginTransaction();
 7          
 8          //先查 id为1的类别
 9          Product product = session.get(Product.class, 1);
10          session.delete(product);
11          
12          
13          transaction.commit();
14      }

4.外键维护

4.1 双向关联产生多余的SQL语句

​   一旦存在主外键关系,那么外键就由双方对象去维护了, 那么就会造成对这个外键执行了多次操作, 有一次操作其实可以避免的。 也就是说这个外键只要让一个人去维护即可。 外键属于谁,就让谁去维护。

  • eg:修改产品对应的类别

4.2inverse标签属性
4.2.1概念

  inverse:外键维护,默认为false。代表一方不去维护多方外键。(inverse有反转的意思)

  外键属于谁, 谁就负责维护.

4.2.2一方的放弃外键维护
  • 只能在一的一方放弃外键维护

    <set  inverse="true">
        ...
    </set>
  • EG:

  • <!--  三.表示和商品的关系 -->
    <!-- 3.1 set标签的name属性:多的一方的集合的名字 -->
    <set name="products" cascade="delete" inverse="true">
        <!--3.2 key 的column表示多的一方外键名 -->
        <key column="cid"/>
        <!-- 3.3 one-to-many的class属性表示多的一方类的全限定名 -->
        <one-to-many class="com.pri.bean.Product"/>
    </set>
 1 /**
 2    * 把苹果(p1)的类别设置为水果(c2)
 3      * 衣服是(c1)
 4      */
 5     @Test
 6     public void fun02(){
 7         Session session = HibernateUtils.openSession();
 8         Transaction transaction = session.beginTransaction();
 9         //获得苹果
10         Product p1 = session.get(Product.class, 1);
11         //获得食物类别
12         Category c2 = session.get(Category.class, 2);
13         
14         //p1和c2关联
15         p1.setCategory(c2);
16         //c2和p1关联
17         c2.getProducts().add(p1);
18         
19         transaction.commit();
20         session.close();
21     }

二、多对多的关系

1.概念

​ 多对多关系是关系数据库中两个表之间的一种数据关系,为了维护这种关系,通常会存在一张中间关系表。两张表都只和关系表间建立主外键关系。

2.Hibernate的多对多关联映射【重点】

2.1表关系的分析

  • MySql语句

2.2创建实体
  • Student.java

     1 public class Student {
     2     
     3     private Integer sid;
     4     private String sname;
     5     
     6     private Set<Course> courses = new HashSet<Course>();
     7  8     public Integer getSid() {
     9         return sid;
    10     }
    11 12     public void setSid(Integer sid) {
    13         this.sid = sid;
    14     }
    15 16     public String getSname() {
    17         return sname;
    18     }
    19 20     public void setSname(String sname) {
    21         this.sname = sname;
    22     }
    23 24     public Set<Course> getCourses() {
    25         return courses;
    26     }
    27 28     public void setCourses(Set<Course> courses) {
    29         this.courses = courses;
    30     }
    31     
    32 33     
    34 }
  • Course.java

     1 public class Course {
     2     
     3     private Integer cid;
     4     private String cname;
     5     
     6     private Set<Student> students = new HashSet<Student>();
     7  8     public Integer getCid() {
     9         return cid;
    10     }
    11 12     public void setCid(Integer cid) {
    13         this.cid = cid;
    14     }
    15 16     public String getCname() {
    17         return cname;
    18     }
    19 20     public void setCname(String cname) {
    21         this.cname = cname;
    22     }
    23 24     public Set<Student> getStudents() {
    25         return students;
    26     }
    27 28     public void setStudents(Set<Student> students) {
    29         this.students = students;
    30     }
    31      
    32 }
2.3创建映射