spirngboot使用hibernate,完成映射关系及其使用场景探究

37 篇文章 0 订阅
36 篇文章 1 订阅

   一直对数据库映射这块缺乏练习,导致在实践中总是卡在一个某个具体的问题上。因此这里花上一小段时间将映射这块练习一下,方便日后回顾。

   环境准备:

    

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.automannn</groupId>
    <artifactId>hibernateRelationShipPractice</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>


</project>

数据源,目录,以及启动类:

package com.automannn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:51
 */
@SpringBootApplication
public class App {

    public static void main(String[] args) {
        SpringApplication.run(App.class);
    }
}

    一对一单向映射的练习:

设  一个学校有且仅有一个校长,一个校长仅能任职于一个学校。 因此他们就构成了一对一的关系。  

package com.automannn.entity;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 17:08
 */
@Entity
public class HeadMaster {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String headMasterName;

    @OneToOne
    private School school;
}
package com.automannn.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * @author automannn@163.com
 * @time 2018/10/20 17:07
 */
@Entity
public class School {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String schoolName;
}

  这个时候,校长是主控方,持有学校的信息。运行之后查表:

  在这种场合下,我们可以通过主控方查看另一方的信息。即通过校长查看到相应的学校信息。 反之,若学校为主控方,那么相应的也要反转,这是单向的。  并且他们的联系是通过外键关联的,但是我看到很多的博客都说不要使用外键,关系的对应通过程序控制。

  一对一双向映射练习:

package com.automannn.entity;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 17:08
 */
@Entity
public class HeadMaster {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String headMasterName;

    @OneToOne(mappedBy = "headMaster")
    private School school;
}
package com.automannn.entity;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 17:07
 */
@Entity
public class School {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String schoolName;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "headMaster_id")
    private HeadMaster headMaster;
}

它们的表结构如下:

   要注意,将hibernate在update状态下,貌似对于删除表结构的操作可能有缺陷,所以导致我测试浪费了一些时间。

   

   最简形式:

  

  通过它的构成形式,可以猜测,这个步骤是hibernate的工作,而非数据库的工作。   同时,注解的属性与类中的属性通过程序上下文联系起来。  不具有固定性!!!   后面思考了下,这种说法不准确,虽然是上下文,但是属性变量实际上是起到了一个管道的作用,因此要写的对应关系还是很好理解的了。

多与一的常见关系映射练习:

  设:  某个班具有多个学生,每个学生只能属于一个班。  因此,构成了这样的一个多与一的映射关系。

   现有一个需求如下:

     需要知道每个班有哪些学生?  那么可以通过单向一对多,单向多对一考虑。

    单向一对多:

package com.automannn.entity;

import javax.persistence.*;
import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:53
 */
@Entity
public class Clazz {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String clazzName;

    @OneToMany
    private List<Student> studentList;
}
package com.automannn.entity;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:52
 */

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

}

  这种情况下,它生成的表结构:

   会生成一张只具有外键的中间表。 并不是我们想要的效果。

  这是在具有最简注解:的情况。

当我们在Clazz.class修改如下:

  可以发现它的表结构:

   可以发现一个现象,就是我们的那个joinColumn是在 Clazz.class实体写的,但是加入的属性列在Student表中。  因为,只要是一与多的关系,hibernate都是在多的一方记录信息。 

   多对一,与一对多的根本区别在于:一致性维护由哪一方完成,因为这里涉及到性能的问题。但是由于这里是单向的关系,jpa规范应该是默认由多的一方完成吧,因为在注解中没找到inverse属性,同时看网上的解释也有:

  因此就不再去看了。  另外要注意,mappedBy  与 joinColumn不能同时出现,会报错。mappedBy只适用于双向关系的那种可能。

  最简配置:

   结构:

以上可以满足通过班级查询学生,而且是比较直观的理解。

那么,多对一实际也可以满足这种需求。

  单向一对多的练习:

package com.automannn.entity;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:52
 */

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    @ManyToOne
    private Clazz clazz;

}
package com.automannn.entity;

import javax.persistence.*;
import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:53
 */
@Entity
public class Clazz {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String clazzName;

}

   它生成的表结构:

   这种情况下,我们实际上是去查询学生表,将班级以属性的方式进行查询的

   而上面的那种情况是查询班级表,以列表方式直观的将本班级学生给查询出来

   值得注意的是,在这两种情况下,我们都能够对两个表的信息进行增删该查。 并且表的结构也一样,只是查询的逻辑不同,还有就是性能方面可能有一些不同。

    由于我并没有很多的实战经验,但是我的感觉是,当查询的请求为主时,完全可以使用单向一对多的方式将所有的信息给查出来。否则,当以数据更新操作为主的时候,应该使用单向多对一的方式。

Ok,如果有另一个需求,需要知道每个学生所在的班级信息。  也就是需要从多的一端获取一的数据。这个时候可以这样干,那就是在根本上修改这种一与多的关系,导致它变长多与多的关系,形成一个回环。  但是这样很明显是不明智的。正确的做法应该是使用双向关系。因为这里是双向的,所以也就不存在方向性了,因为它的表结构都是一样的。

  双向多与一映射关系练习:

package com.automannn.entity;

import javax.persistence.*;
import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:53
 */
@Entity
public class Clazz {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String clazzName;

    @OneToMany(mappedBy = "clazz")
    private List<Student> studentList;

}
package com.automannn.entity;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:52
 */

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    @ManyToOne
    private Clazz clazz;

}

    它生成的表结构:

   注意一下,@ManyToOne是没有mappedBy属性的。

    fetch属性一般默认即可,因为默认的都是推荐的。

     可以说,双向的这种一与多的关系简直就是我们的理想状态了。  并且将维护关系设置为多的一方,那我们就可以很方便,愉快的进行开发哈哈哈。  都说对性能有影响,但是我觉得性能是一个虚的概念,当业务需求根本不可能到达瓶颈的时候,性能问题根本不是问题了。

   很开心愉快的进行了一对一单双向,一对多单向,多对一单向,一与多双向的练习。  接下来就进入最后一个的练习。 多对多映射。

多对多映射的练习:

 设:一个老师有多个学生,一个学生可以被多个老师教。  因此他们就构成了一种多对多的关系。

  在这种多对多的关系中,我们经常要通过一方查询另一方的需求,因此也就不考虑单双向的问题了。

   但是发现多对多关系中是存在单双向问题的:

  

package com.automannn.entity;

import javax.persistence.*;
import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/20 19:29
 */
@Entity
public class Teacher {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String teacherName;

    @ManyToMany
    private List<Student> student;
}
package com.automannn.entity;

import com.automannn.before.Clazz;

import javax.persistence.*;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:52
 */

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;


}

生成的表结构如下:

   这是单向的情况。  接着修改代码,使之变为双向,以满足业务需求。

package com.automannn.entity;

import javax.persistence.*;
import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/20 19:29
 */
@Entity
public class Teacher {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String teacherName;

    @ManyToMany(mappedBy ="teacherList" )
    private List<Student> studentList;
}
package com.automannn.entity;

import com.automannn.before.Clazz;

import javax.persistence.*;
import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/20 16:52
 */

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    @ManyToMany
    private List<Teacher> teacherList;
}

它的表结构:

实践过程的一些反思与总结:

    1.OnetoOne,ManyToOne,OneToMany,ManyToMany这几种关系中,是这样来表示逻辑关系的:  to之前的表示本端,或者说本实体对象,to之后的表示当前的属性对象,即被注解的实体对象。

     2.哪些情况下会在不设置其它的附加信息的情况下会生成中间表?  当被映射的实体对象为“一”的逻辑地位(不论是To之前还是之后),同时具有“多”外键的情况下的时候,会生成中间表!!!  即当“一”的一方需要维护多的一方关系的时候,会自动生成中间表。如:单向OneToMany,且不加@JoinColumn的情况。

     3.当逻辑地位为“多”的属性时候,必需设置为集合,否则会报错!  如: @ManyToOne private Student student;正确,而  @OneToMany private Student student; 错误!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值