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 有一些幫助,那這幾篇的文章就達到目的了,也歡迎後端的小夥伴來指出文章中的錯誤和不足。

相關文章
相關標籤/搜索