MySQL —— 简单聊一聊数据库设计

在这里插入图片描述

阅读原文

前言

这是关于 MySQL 系列文章的第三篇,在前两篇文章 《MySQL —— 数据库基础》《MySQL —— SQL 语句总结》 中,主要介绍了一些数据库的基础概念、建立表的方式以及 SQL 语句的使用,本篇在使用的基础上作一个小小的升华,来简单聊一聊数据库的设计,还有一句话不得再也不次赘述,数据库博大精深,本系列文章内容较浅,适合于前端的同窗们对 MySQL 的入门,这也是个人学习笔记,但愿能够帮助你们。前端

为何设计数据库

说到为何要设计数据库,就要说到数据的完整性,咱们要在设计数据库时保证域的完整性和实体的完整性,同时从性能出发,咱们要保证最大限度的节省存储空间,好比一张成绩表,上面不必存储学生的姓名、年龄等信息,只须要存储成绩,若是一个数据库设计的合理,最后的结果就是方便咱们对数据库的开发和扩展。mysql

若是是一个 “糟糕” 的数据库设计会形成一系列的不良反应,好比数据冗余,存储空间浪费,内存浪费,有时甚至会形成数据插入和更新的异常,好比学生表存了学生信息,而成绩表也存了,这样在修改时没有所有修改就会出现错误。sql

软件项目开发中数据库设计的生命周期

软件项目开发中数据库设计的生命周期可大概分为如下几个阶段:数据库

  • 需求分析阶段,分析客户的业务和数据处理需求;
  • 概要设计阶段,设计数据库 E-R 模型图,确认需求的正确和完整性;
  • 详细设计阶段,应用三大范式审核数据库;
  • 代码编写阶段,物理实现数据库,编码实现应用;
  • 软件测试阶段;
  • 安装部署阶段。

上面数据库的设计经历了从 “现实世界” 到 “信息世界” 到 “数据库模型” 再到 “数据库” 产生的一个完整过程。后端

设计数据库的步骤

收集信息:收集信息其实就是与相关人员进行交流、访谈、调研,充分了解用户需求,理解整个项目的完整流程,并理解数据库须要完成的任务,这部分工做大部分由需求人员完成,并根技术人员进行对接。安全

标识实体和实体属性:开发人员在明确需求和流程以后,标识数据库的实体,好比学生信息表,每一条实体中应该由哪些字段组成,成绩表中实体由哪些字段组成等等。微信

标识实体之间的关系:其实就是经过表之间的某字段对表进行关联,对表的实体之间创建对应关系,如学生表的 id 字段会关联成绩表的 student_id 字段,用来查找某个学生的成绩。并发

数据库 E-R 图

一、E-R 图基本概念

E-R 图也叫作实体关系图,是指用实体、关系、属性三个基本概念归纳数据的基本结构,从而描述静态数据的概念模型。数据库设计

E-R 图的实体:即数据模型中的数据对象,每一张表就是一个 E-R 图的实体。性能

E-R 图的属性:即数据对象中所具备的属性,例如学生表的学生、姓名、年龄等,属性又分为惟一属性和非惟一属性,惟一属性如通过惟一约束和主键约束的属性,不可重复,其余的都是非惟一属性。

E-R 图的关系:用来表示每个数据对象与数据对象之间的联系,即每个实体之间的联系,例如学生表和成绩表之间的联系,由于每一个学生都有本身的成绩。

二、E-R 图的关联关系

(1) 1 对 1 (1 : 1)

11 关系是指对于实体集 A 和 实体集 BA 中的每个实体最多与 B 中的一个实体有关系,反之在实体集 B 中的每个实体之多与实体集 A 中的一个实体有关系。

在这里插入图片描述

(2) 1 对多(1 : N)

1 对多关系是指实体集 A 与实体集 B 中至少有 N (N > 0) 个实体有关系,而且实体集 B 中最多与实体集 A 中的一个实体有关系。

在这里插入图片描述

(3) 多对多(M : N)

多对多关系是指实体集 A 中的每个实体与实体集 B 中至少有 M (M > 0) 个实体有关系,而且实体集 B 中的每个实体与实体集 A 中至少有 N (N > 0) 个实体有关系。

在这里插入图片描述

数据库设计的三大范式

一、确保每列的原子性

若是每列都是不可再分的最小单元信息,则知足第一范式,好比下图中,地址是由国家和城市组成的,显然能够继续在拆分红两个列,国家和城市,是不知足第一范式的,须要将地址列差分红国家和城市两个列。

在这里插入图片描述

举一个简单的例子,咱们平时在淘宝购物的时候须要添加地址,在填写新地址时,都是让咱们选择国家、省、城市、区、街道、小区这样的方式,而不是让咱们本身将这些地址写在一块儿,其缘由就是由于淘宝的数据库设计严格遵循每列的原子性,这样的提交能够方便后端获取每个列的信息在数据库中进行存储。

二、每一个表只能描述一件事情

以下图中所示,在左侧的表中,描述了学生信息和课程信息,这明显是两件事情,假设再有一张成绩表,也要描述学生信息,课程信息和成绩等多件事情,就会形成数据的重复、冗余,也可能会致使更新、插入、删除数据异常的现象。

在这里插入图片描述

因此正确的作法是应该将左侧表差分红两张表分别为学生表和课程表,并使用学生编号与课程编号进行关联。

三、其余列都不传递依赖于主键列

其余列都不传递依赖于主键列的意思是表中各列必须都与主键直接相关,不能简介相关,从下图左表能够看出,学生编号为主键,年级 ID 也应该为主键,正常应该经过学生编号找到年级 ID,再找到年级名称,这样年级名称与学生编号之间就造成了一个传递而且依赖于主键年级 ID,即年级 ID 作为主键在中间隔了一层,这样就使年级名称与主键学生编号间接相关,若是在同一张表中,全部的字段都是应该直接依赖于主键,而不是再经过其余的主键传递。

在这里插入图片描述

若是一个表中表述了多件事情并有多个做为主键的列,与上一条的处理方式相同,应该拆成多张表,而且每张表只有一个主键列。

RBAC 基于角色的访问控制

一、RBAC 的含义

RBAC(Role-Based Access Control)基于角色的访问控制,就是用户经过角色与权限进行关联,简单的说,一个用户拥若干个角色,每一个角色拥有若干个权限,这样就构形成了 “用户 → 角色 → 权限 → 资源” 的受权模型,在这个模型中,用户与角色之间,角色与权限之间,权限与资源之间,通常都是多对多的关系,在 RBAC 中最重要的概念主要有四部分,就是用户(User)、角色(Role)、权限(Permission)和资源(Resource)。

二、RBAC 的安全原则

  • 最小权限原则:最小权限原则之因此被 RBAC 所支持,是由于 RBAC 能够将其角色配置成完成任务所须要的最小的权限集;
  • 责任分离原则:能够经过调用相互独立互斥的角色来共同完成敏感的任务而体现,好比要求一个计账员和财务管理员共参与同一个账目;
  • 数据抽象原则:数据抽象能够经过权限的抽象来体现,如财务操做用借款、存款等抽象权限,而不用操做系统提供的典型的读、写、执行权限。

三、RBAC 的 E-R 图

以前说 RBAC 最重要的概念由四部分,其实体如今数据库的表中有主要三部分,由于角色和用户是重叠的,那么主要有三张表分别为用户表、权限表和资源表,其中用户表与权限表之间有一张关联表,权限表与资源表之间有一张关联表,E-R 图以下。

在这里插入图片描述

事务

一、为何须要事务?

在生活中咱们常用银行转帐或者支付宝和微信支付,这种操做每一次至少影响两个用户的数据信息,好比一方给另外一方转钱,若是成功则转钱方余额减去转出金额,而收钱方余额增长收到的金额,这应该是一个请求操做了数据表中的俩个实体,若是在两个操做数据的环节任意一个失败了,都会影响两我的数据的正确性,这种时候须要两个操做同时失败或同时成功,就是说有一个操做出现失败的状况,即便另外一个成功了也须要进行回滚操做,这就是事务的由来。

二、什么是事务

事务是做为单个逻辑工做单元执行的一系列操做,多个操做做为一个总体向系统提交,要么都执行,要么都不执行,是一个不可分割的工做逻辑单元。

转帐过程就是一个总体,它须要两条 UPDATE 语句,若是任何一个出错,则整个转帐业务取消,两个帐户的余额都恢复到原来的数据(回滚),确保总余额不变。

这里再举一个例子,有一个上传文件的功能,后端接收到文件流时是须要先写入的,当写入成功后,会将上传成功的结果返回给客户端,若是文件很大,写入的时间就会长,若是在此期间忽然写入失败,则会删除以前写入的内容,将整个操做回滚到写入以前,这里面主要两步操做,建立一个新文件并写入,写入成功删除旧文件,若是写入失败,两个操做将会同时失败,即不会删除旧文件,这也是一个事务的例子,只是没有转帐那么明显。

三、事务的特性 ACID

事务具备如下特性,被简称为 ACID:

  • 原子性(Atomicity):事务是一个完整的操做,事务各个部分是不可分的,要么都执行,要么都不执行;
  • 一致性(Consistency):当事务完成后,数据必须处理完整的状态;
  • 隔离性(Isolation):并发事务彼此隔离、独立,它不该该以任何方式依赖于其它事务;
  • 持久性(Durability):事务完成后,它对数据库的修改被永久保持。

四、如何建立事务

(1) 建立表

建立表 accountid 列为主键列,name 列为姓名,balance 为余额。

CREATE TABLE `account` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(64) NOT NULL,
    `balance` INT(11) DEFAULT 0
    PRIMARY KEY (`id`)
);

(2) 添加数据

将表 account 添加两条数据,分别为 “张三” 和 “李四”,余额都为 100

INSERT INTO `student` (`name`, `balance`) VALUES ("张三", 100);
INSERT INTO `student` (`name`, `balance`) VALUES ("李四", 100);

(3) 使用 NodeJS 实现事务

const mysql = require("mysql");

// 建立数据库链接
const connection = mysql.createConnection({
    host: "localhost", // 主机名
    port: "3306", // 数据库服务端口号
    username: "root", // 数据库名称
    pwd: "123456", // 数据库密码
    database: "school"  // 链接的数据库名称
});

connection.connect();

// 开启事务
connection.beginTransaction(err => {
    // 回调参数为错误对象,返回结果,返回字段描述
    connection.query("UPDATE account SET balance - 50 WHERE id = 1", (err, result, fields) => {
        if (err) {
            connection.rollback(); // 若是失败直接回归
        } else {
            connection.query("UPDATE account SET balance - 50 WHERE id = 1", (err, result, fields) => {
                if (err) {
                    connection.rollback(); // 若是失败直接回归
                } else {
                    connection.commit(); // 若是两个都成功了则提交事务
                }
            });
        }
    });
});

总结

到此关于 MySQL 的系列文章就告一段落了,但愿前端的同窗们在看了这几篇文章后对大家入门 MySQL 有一些帮助,那这几篇的文章就达到目的了,也欢迎后端的小伙伴来指出文章中的错误和不足。

相关文章
相关标签/搜索