数据库多表设计

多表关系概览

在项目开发中,进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,因为业务之间相互关联,所以说各个表结构之间也存在着各种联系,基本上分为:一对多(多对一)、多对多、一对一这三种。

一对多

假如说需要开发一个员工管理系统,那么肯定是需要两张数据库表:员工表和部门表;而且部门和员工之间的关系是一对多:因为一个部门可以对应多个员工,而一个员工一般只对应一个部门。那么这个时候这两张表就产生了一对多的关系。

首先需要新建两张数据库表,一张是部门表,一张是员工表:

sql 复制代码
create table tb_dept(
    id int unsigned primary key auto_increment comment '主键ID',
    name varchar(10) not null unique comment '部门名称',
    create_time datetime not null comment '创建时间',
    update_time datetime not null comment '修改时间'
) comment '部门表';

员工表:

sql 复制代码
create table tb_emp (
  id int unsigned primary key auto_increment comment 'ID',
  username varchar(20) not null unique comment '用户名',
  password varchar(32) default '123456' comment '密码',
  name varchar(10) not null comment '姓名',
  gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
  image varchar(300) comment '图像',
  job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管',
  entrydate date comment '入职时间',
  dept_id int unsigned comment '部门ID',
  create_time datetime not null comment '创建时间',
  update_time datetime not null comment '修改时间'
) comment '员工表';

通过员工表中的的dept_id字段标识该员工的所属部门,也就是通过dept_id字段使得两张表产生了联系。但只是这样写,在逻辑上两张表确实产生了关系,但是在数据库层面而言,两张表并未建立任何关联:因为直接这么写,就算我们知道两张表的逻辑,数据库也是不知道的。此时若对部门表进行操作,就会产生这样的问题:部门表中的部门可以直接删除,但是此时仍然还有部分员工归属于该部门,但是部门已经删除了。这就导致了数据的不完整、不一致的问题。由此可见,若两张表只在逻辑上有关联,在数据库的层面并未建立关联,无法保证数据的一致性和完整性。

解决方法

使用外键约束,通过对表中的字段添加外键约束------------foreign key,可以使得两张表在物理层面上建立关联。

建表之前给字段添加外键:

sql 复制代码
create table 表名(
    字段名 数据类型 constraint 外键名 foreign key (外键字段名) reference 主表 (字段名)
)

建表之后给字段添加外键:

sql 复制代码
alter table 表名 add constraint 外键名 foreign key (外键字段名) reference 主表(字段名)

比如说这样;

sql 复制代码
create table emp (
  id int unsigned primary key auto_increment comment 'ID',
  username varchar(20) not null unique comment '用户名',
  password varchar(32) default '123456' comment '密码',
  name varchar(10) not null comment '姓名',
  gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女',
  image varchar(300) comment '图像',
  job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管',
  entrydate date comment '入职时间',
  dept_id int unsigned comment '部门ID',
  create_time datetime not null comment '创建时间',
  update_time datetime not null comment '修改时间',
    constraint emp_dept foreign key(dept_id) references dept(id)
) comment '员工表';

这样就在建表的时候创建了一个外键约束,通过员工表中的字段dept_id和部门表中的id进行关联,将dept表中的id作为员工表的外键,使用约束在物理上进行关联,使得数据能够保证一致性和完整性。

使用物理外键存在的问题

使用foreign key外键可以使得两张表产生联系,但是因为是物理上的约束,所以说也有一些缺点:1.影响数据库CRUD的效率,因为每次在CRUD之前都需要检查外键的关系;2.foreign key外键只能用于单节点数据库,不适用于分布式、集群的场景;3.容易引发数据库的死锁问题,消耗性能。现在已经有很多项目明文禁止使用物理外键,现在更加推荐使用逻辑外键的方式解决表的关联问题:在业务层的逻辑中,解决外键关联,主要是通过代码来保证数据的一致性的,通过逻辑外键也可以保证数据的一致性,并且不会存在物理外键的问题,是推荐的做法。

一对一

一对一的关系,常用于多表拆分,将一张表的一些字段放在一张表中,其他字段放在另一张表中,进行分表,可以提高操作效率。一对一关系实现:在一方的字段中添加外键,关联另外一方的主键。

案例分析

比如说用户和其对应的身份证信息关系,可以在一张用户表中存放这两个信息(用户的基本信息和对应身份证信息),但是这种做法是不推荐的:将太多的信息全部放在一张表中,会降低操作效率。所以说一般会进行分表:将用户的基本信息分为一张表,将用户的身份证信息分为另外一张表,在身份信息表中用字段user_id作为外键关联用户信息表的主键,实现两张表的关联和一对一的关系(一个用户只能对应一张身份证)

在user_card表中添加外键user_id,关联user表的id(主键),并且设置外键为唯一,从而完成一对一的多表关系。

多对多

在一些案例中我们需要实现多对多的关系,比如说学生和课程的关系:一个学生可以选择多门课程,一门课程也可以供多个学生进行选择。这就会涉及到多对多的关系,那么这时单纯只依靠两张表之间就无法实现这样的关系了,就需要建立第三张中间表,中间表中至少包含两个外键,分别关联两方的主键:

sql 复制代码
create table tb_student(
    id int auto_increment primary key comment '主键ID',
    name varchar(10) comment '姓名',
    no varchar(10) comment '学号'
) comment '学生表';
sql 复制代码
create table tb_course(
   id int auto_increment primary key comment '主键ID',
   name varchar(10) comment '课程名称'
) comment '课程表';
sql 复制代码
create table tb_student_course(
   id int auto_increment comment '主键' primary key,
   student_id int not null comment '学生ID',
   course_id  int not null comment '课程ID',
   constraint fk_courseid foreign key (course_id) references tb_course (id),
   constraint fk_studentid foreign key (student_id) references tb_student (id)
)comment '学生课程中间表';

我们先创建了两张表,分别是学生表和课程表,然后再创建了第三张中间表:学生课程中间表,其中有两个外键:student_id和 course_id分别关联学生id和课程id,这样就通过建立第三张中间表的方式,成功使得两张表实现了多对多的关系:

相关推荐
qq_1079910405几秒前
Z2400037 Java+Maven+Mysql+spring boot+layui开发极简物业后台管理系统
java·mysql·maven
JSON_L10 分钟前
微信 创建小程序码-有数量限制
后端·微信·小程序
JSON_L10 分钟前
微信创建小程序码 - 数量不受限制
后端·微信·小程序
九圣残炎15 分钟前
【从零开始的LeetCode-算法】3227. 字符串元音游戏
java·算法·leetcode
芭拉拉小魔仙16 分钟前
浏览器数据存储方法深度剖析:LocalStorage、IndexedDB、Cookies、OPFS 与 WASM - SQLite
数据库·sqlite·wasm
Shirleyluck17 分钟前
leetcode1486 官方降低时间复杂度方法
java
极客先躯26 分钟前
高级java每日一道面试题-2024年12月03日-JVM篇-什么是Stop The World? 什么是OopMap? 什么是安全点?
java·jvm·安全·工作原理·stop the world·oopmap·safepoint
凡人的AI工具箱34 分钟前
40分钟学 Go 语言高并发:RPC服务开发实战
开发语言·后端·性能优化·rpc·golang
R6bandito_40 分钟前
Qt几何数据类型:QLine类型详解(基础向)
c语言·开发语言·c++·经验分享·qt
Mercury_@2242 分钟前
项目集成篇:springboot集成redistemple实现自定义缓存,并且可以设置过期时间
后端·缓存