數據庫設計
1. 軟件項目開發週期中的數據庫設計
- 需求分析階段:分析客戶的業務和數據處理需求
- 概要設計階段:設計數據庫的E-R模型圖,確認需求的正確和完整性
- 詳細設計階段:應用三大範式審覈數據庫
- 代碼編寫階段:物理實現數據庫,編碼實現應用
- 軟件測試階段
- 安裝部署
2. 設計數據庫的步驟
2.1 收集信息
- 與相關人員進行交流、訪談充分了解用戶需求,理解數據庫需要完成的任務
2.2 標示實體(Entity)
- 標識數據庫要管理的關鍵對象或者實體,實體一般是名詞
2.3 標示實體的屬性(Attribute)
2.4 標示實體之間的關係(RelationShip)
3. 數據庫ER圖
- ER圖:實體關係同,簡記E-R圖,是指以實體、關係、屬性三個基本概念概括數據的基本結構,從而描述靜態數據結構的概念模式
符號 | 含義 |
---|---|
長方形 |
實體,一般是名詞 |
橢圓形 |
屬性,一般是名詞 |
菱形 |
關係,一般是動詞 |
3.1 ER圖的實體(entity)
- ER圖的實體(entity)即數據模型中的數據對象,例如人、學生、音樂都可以作爲一個數據對象,用長方形來表示
3.2 ER圖的屬性(attribute)
- ER圖的屬性(attribute)即數據對象所具有的屬性,例如學生具有姓名、學好、年級等屬性,用橢圓形表示
- 屬性分類
- 唯一屬性:唯一可用來標識該實體實例或成員的屬性,用下劃線表示,一般來講實體至少有一個唯一屬性。
- 非唯一屬性
3.3 ER圖的關係(relationship)
- ER圖的關係用來表現數據對象和數據對象之間的聯繫
- 例如:
- 學生的實體和成績表的實體之間有一定的聯繫,每個學生都有自己的成績表,這就是一種關係,關係用菱形來表示
3.4 ER圖中的關聯關係
3.4.1 1對1(1:1)
- 1對1關係,指:
- 對於實體集合A與實體集合B,A中的每一個實體之多與B中一個實體有關係;反之,在實體B中的每個實體至多與實體集A中有一個實體關係。
學生
身份證信息
- X ---------------------------------------------------Y
- X ---------------------------------------------------Y
- X ---------------------------------------------------Y
- X ---------------------------------------------------Y
3.4.2 1對多(1:N)
- 1對多關係,指
- 實體集A和實體集B中至少有N(N>0)個實體有關係;並且實體B中每一個實體至多與實體A中一個實體有關係
- 實體集A和實體集B中至少有N(N>0)個實體有關係;並且實體B中每一個實體至多與實體A中一個實體有關係
3.4.3 多對多(M:N)
- 多對多,指的是
- 實體集A中的每一個實體與實體集B至少有M(M>0)個實體有關係,並且實體集B中的每一個實體與實體集A中的至少N(N>0)個實體有關係。
- 實體集A中的每一個實體與實體集B至少有M(M>0)個實體有關係,並且實體集B中的每一個實體與實體集A中的至少N(N>0)個實體有關係。
4 數據庫設計的三大範式
4.1 不合理的表設計
- 信息重複
- 更新異常
- 插入異常
- 刪除異常
4.2 三大範式
4.2.1 第一範式(1NF)
- 數據表中的每一列(每一個字段)都必須是不可拆分的最小單元,也就是確保每一列的原子性
ID | 地址 |
---|---|
1 | 中國上海 |
2 | 美國曼哈頓 |
3 | 英國倫敦 |
4 | 日本大阪 |
… | … |
應該根據第一範式轉化爲:
ID | 國家 | 城市 |
---|---|---|
1 | 中國 | 上海 |
2 | 美國 | 曼哈頓 |
3 | 英國 | 倫敦 |
4 | 日本 | 大阪 |
… | … | … |
4.2.2 第二範式(2NF)
-
滿足1NF後,要求表中的所有列,都必須依賴於主鍵,而不能有任何一列與主鍵沒有關係,也就是說一個表只能描述意見事情
-
舉例:如下訂單表,主鍵是訂單編號,就不滿足第二範式要求,因爲:
- 每列都需要跟主鍵有關,而身份證號等個人信息那麼多,跟訂單編號沒有關係
- 一個人同時頂幾個房間,就會出來一個訂單號多條數據,這樣子聯繫人都是重複的,就會造成數據冗餘
- 所以可以轉成一張訂單表跟一張聯繫人表,如下面第二和第三張表
訂單編號 | 房間號 | 聯繫人 | 聯繫人電話 | 身份證號 |
---|
優化後的表有如下兩張:
訂單編號 | 房間號 | 聯繫人編號 |
---|
以上是訂單表
聯繫人編號 | 聯繫人 | 聯繫人電話 | 身份證 |
---|
以上是聯繫人表
4.2.3 第三範式(3NF)
- 滿足2NF後,要求:表中的每一列只與主鍵又直接關係,而不是間接關係(表中的每一列只能依賴於主鍵)
- 數據不能存在傳遞關係,即每個屬性都跟主鍵又直接關係而不是間接關係
學生編號 | 學生姓名 | 年級ID | 年級名稱 |
---|---|---|---|
1 | 張三 | 1 | 年級 |
主鍵爲學生編號,學生姓名依賴主鍵,年級ID依賴主鍵,但是年級名稱是依賴年級ID,而不是直接依賴主鍵學生編號,所以需要拆分成如下兩個表
學生編號 | 學生姓名 | 年級ID |
---|---|---|
1 | 張三 | 1 |
以上是學生表
年級ID | 年級名稱 |
---|---|
1 | 一年級 |
以上是年級表
4.2.4 如何更好的區分三大範式
- 第一範式和第二範式的區別在於有沒有分出兩張表,第二範式是說明第一張表中包含了多種不同的實體屬性,那麼要必須分成多張表
- 第三範式是要求已經分成了多張表,那麼一張表中只能有另一張表中的id(主鍵)。而不能有其他的任何信息(其他的信息一律用未安檢在另一張表的主鍵查看)
5. RBAC
- 基於角色的權限訪問控制(Role-Based Access Control)
- RBAC就是用戶通過角色與權限進行關聯
- 簡單地說,一個用戶擁有若干橘色,每個橘色擁有若干權限,每個權限可以操作若干資源,這樣就構造成"用戶-角色-權限-資源"的授權模型
- 在這種模型中,用戶與角色之間,橘色與權限之間,權限與資源之間,一般都是多對多的關係
- 在RBAC中最重要的概念包括:用戶(User)、角色(Role)、權限(Permission)、資源(Resource)
5.1 安全原則
- 最小權限原則
- RBAC可以將其角色配置成其完成任務所需要的最小的權限集
- 責任分離原則
- 可以通過互斥的角色來共同完成敏感的任務
- 比如:記賬員和財務管理員共同過賬
- 可以通過互斥的角色來共同完成敏感的任務
- 數據抽象可以通過權限的抽象來體現
- 比如財務操作用借款、存款等來替代操作系統提供的典型的讀、寫、執行權限。
6. 事務
6.1 爲什麼需要事務
- 銀行轉賬問題
- A賬戶資金減少
- B賬戶資金增加
CREATE DATEBASE bank;
use bank;
CREATE TABLE account
(
name varchar(64),
balance decimal(10,2)
)
INSERT INTO account(name,balance) VALUES('張三',100);
INSERT INTO account(name,balance) VALUES('李四',100);
UPDATE account SET balance = balance - 10 WHERE name = '張三';
UPDATE account SET balance = balance + 10 WHERE name = '李四';
6.2 什麼是事務
- 事務是作爲單個邏輯工作單元執行的一系列操作
- 多個操作作爲一個整體向系統提交,要麼都執行,要麼都不執行
- 事務是一個不可分割的工作邏輯單元
轉賬過程就是一個整體,它需要兩條UPDATE語句,如果任何一個出錯,則整個轉賬業務取消,兩個賬戶餘額都恢復到原來的數據,確保總月不變
6.3 事務的特性ACID
- 原子性(Atomicity)事務是一個完整的操作,事務各個部分是不可分的,要麼都執行,要麼都不執行
- 一致性(Consistency)當事務完成後,數據必須處理完整的狀態
- 隔離性(Isolation)併發事務彼此隔離、獨立,他不應該以任何方式依賴於其他事務
- 持久性(Durability)事務完成後,它對數據庫的修改被永久保持
6.4 如何創建事務
- 開始事務 START TRANSACTION 或者 BEGIN
- 提交事務 COMMIT
- 關閉/開啓自動提交狀態 SET AUTOCOMMIT=0/1 0關閉 1開啓
關閉自動提交後,從嚇一跳SQL語句開始開啓新的事務,需要使用COMMIT或ROLLBACK結束該事務
7. 鎖
- 鎖時計算機協調多個進程或線程併發訪問某一資源的機制
7.1 鎖的分類
- 從對數據庫操作的類型分類,分爲:
- 讀鎖(共享鎖):針對同一份數據,多個讀操作可以同時進行而不會相互影響,但是不能刪除跟修改
- 寫鎖(排它鎖):當前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖,也就是我寫完前,別人不能讀也不能寫
- 讀鎖會阻塞寫,但不會阻塞讀;而寫鎖則會把讀和寫都阻塞。
- 從對數據操作的粒度分,分爲
- 表鎖:把整個表鎖住,別人就不能操作表內的任何內容
- 行鎖:可以鎖定某一行,鎖定的行,別人不能操作,其他沒鎖定的可以操作
8.2 表鎖
- 表鎖偏向MyISAM存儲引擎,開銷小,加鎖快,鎖定粒度大,發生鎖衝突的概率最高,併發度最低
- MyISAM存儲引擎:操作非常快,但不支持事務
- INNODB存儲引擎:操作慢,但支持事務
- 語法:
- 加一個鎖:LOCK TABLE 表名1 read(write),表名2 read(write);
- read表示加的是讀鎖
- write表示加的是寫鎖
- 解鎖:UNLOCK TABLES;
8.2.1 表鎖舉例:
- 準備數據
CREATE TABLE users(
id INT(11) NOT NULL AUTO_INCREMENT,
name VARCHAR(20) DEFAULT NULL,
PRIMARY KEY(id)
)ENGINE=MyISAM DEFALUT CHARSET=utf8;
INSERT INTO users(id,name) VALUES(1,'a');
INSERT INTO users(id,name) VALUES(2,'b');
INSERT INTO users(id,name) VALUES(3,'c');
INSERT INTO users(id,name) VALUES(4,'d');
LOCK TABLE 表名1 read(write),表名2 read(write);
8.3 行鎖
- 行鎖偏向InnoDB存儲引擎,開銷大,加鎖慢,會出現死鎖,鎖定粒度小,發生鎖衝突的概率最低,併發度也最高
- InnoDB與MYISAM的最大不同是:
- 前者支持事務,後者不支持
- 前者採用了行級鎖,後者是表級鎖
8.3.1 行鎖支持事務
8.3.1.1 併發事務處理帶來的問題
8.3.1.1.1 更新丟失(Lost Update)
-
當兩個或多個事務選擇同一行,然後基於最初選定的值更新該行時,由於每個事務都不知道其他事務的存在,就會發生丟失更新問題——最後的更新覆蓋了由其他事務所做的更新。
-
後面的事務覆蓋了前面的值
-
舉例:
- A同學建立了一個事務,正在修改數據,且沒有提交。B同學也建立了一個事務,也在修改數據,且沒有提交。
//A同學 set autocommit=0;//關閉自動提交 begin; select * from user; update user set age = 90 where name='張三'; //此時正在修改,並沒有commit提交 //B同學 set autocommit=0;//關閉自動提交 begin; select * from user; update user set age = 80 where name='張三'; //此時正在修改,並沒有commit提交
- 這時候A先提交,B也提交了。
- A提交完,張三是90歲,B提交完,張三成了80歲。B的提交覆蓋了A的提交,而A並不知道B在提交,所以A以爲現在張三還是90歲,其實已經被後提交的事務覆蓋成了80歲。
8.3.1.1.2 髒讀(Dirty Reads)
- 一個事務正在對一條記錄做修改,在這個事務完成並提交前,這條記錄的數據就處於不一致的狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”數據,並據此作進一步的處理,就會產生未提交的數據依賴關係。這種現象叫做“髒讀”
- 一句話:事務A讀取了事務B已經修改但尚未提交數據,還在這個數據基礎上做了操作。此時,如果B事務回滾,A讀取的數據無效,不符合一致性要求。
- 髒讀是事務B修改了數據,這是不正常的
- 解決辦法:如果在第一個事務提交前,任何其他事務不可讀取其修改過的值,則可以避免該問題。
8.3.1.1.3 不可重複讀(Non-Repeatable Reads)
- 一個事務在讀取某些數據後的某個時間,再次讀取以前讀過的數據,卻發現其讀出的數據已經發生了改變、或某些記錄已經被刪除了!這種現象叫"不可重複讀"。
- 一句話:事務A讀取到了事務B已經提交的修改數據,不符合隔離性,這是不正常的。
- 解決辦法:如果只有在修改事務完全提交之後纔可以讀取數據,則可以避免該問題。
8.3.1.1.4(Phantom Reads)
- 一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就成爲“幻讀”。
- 一句話:事務A讀取到了事務B提交的新增數據,不符合隔離性
- 幻讀是事務B裏面新增了數據,這是不正常的
- 解決辦法:如果在操作事務完成數據處理之前,任何其他事務都不可以添加新數據,則可避免該問題。
8.3.1.2 事務隔離四種級別
- read uncommited:讀取尚未提交的數據:就是髒讀
- read committed:讀取已經提交的數據:可以解決髒讀
- repeatable read:重讀讀取:可以解決髒讀和不可重複讀 (mysql默認的)
- serializable:串行化:解決髒讀、不可重複讀和幻讀 (相當於鎖表)
8.3.1.2.1 事務隔離操作
- 查看當前表的事務隔離等級
SELECT @@tx_isolation;
- 修改表的事務隔離等級
set session transaction isolation level read uncommitted;//修改成了髒讀等級
8.3.2 死鎖
- A在修改數據庫,B想改A在改的那個數據庫,那麼B是修改不了的,要等A釋放,B纔可以修改。這就是死鎖。
- 鎖的學問很大,可以自己學習。