數據庫設計原則
ACID
- 原子性
- 事務是最小單元,不可分割,當前事務的操作要麼全部成功,要麼全部失敗,由 undo log 來日誌保證
- 一致性
- 要求所有 DML 語句操作的時候,必須保證同時成功或同時失敗
- 隔離性
- 事務 A 和 事務 B 之間具有隔離,併發執行時互補影響
- 持久性
- 事務的保證,事務終結的標誌【內存中的數據持久化至硬碟中】,由 redo 日誌來保證。
關鍵字:
- 開啟事務 Start transaction
- 事務結束 End transaction
- 提交事務 Commit transaction
- 回滾事務 Rollback transaction
和事務相關的 SQL 語句【TCL】:
- commit【提交】
- rollback【回滾】
開啟事務的標誌/結束事務的標誌
- 開啟的標誌:任何一條 DML 語句執行,標誌事務的開始。
- 結束的標誌:提交或回滾
- 提交,成功的結束,將所有 DML 語句操作歷史記錄和底層硬碟文件中的數據做一次同步。
- 回滾,失敗的結束,將所有 DML 語句操作歷史記錄,全部清空。
重點: 事務進行過程中,未結束前,DML 語句是不會更改底層數據庫文件的數據。只是將操作記錄記錄保存在內存中,事務結束後,並且是事務成功,才會修改底層文件中的數據。
三范式
- 第一范式:要有主鍵,要求每一字段原子性不可再分。
- 第二范式:要求所有非主鍵字段完全依賴主鍵,不能產生部份依賴。
- 所有非主鍵字段和主鍵字段之間不能產生傳遞依賴。
經典設計
- 一對一:
- 第一種方案:分兩張表儲存,共享主鍵。
- 第二種方案:分兩張表儲存,外鍵唯一。
- 一對多:分兩張表儲存,在多的一方添加外鍵,外鍵字段引用的一方的主鍵字段。
- 多對多:分三張表儲存,學生表儲存學社訊息,課程表儲存課程訊息,學生選課表中儲存學生和課程的關係訊息。
實際開發是怎樣?
盡量遵守三范式,但還是根據實際情況進行取捨,有時候拿冗余換速度,最終滿足客戶目的。
ESR
事務
- 一個“最小”的“不可分割”的工作單元。
- 通常一個事務對應一個完整業務。【銀行轉帳】
- 一個完整事務需要批量 DML 語句(insert/update/delete)共同聯合完成。
- 事務只和 DML 語句有關。
- 批量 DML 語句數量具體有多少和業務邏輯有關。
例如銀行轉帳業務 t_act 帳戶表
actno | balance |
---|---|
act-100 | 600000 |
act-200 | 200000 |
執行轉帳業務(100000):
# 以下兩條 DML 語句要求必須同時成功或同時失敗,最小單元不可分割
# 當第一條 DML 語句成功,並不能將底層數據庫第一個帳戶的數據修改,只是將操作記錄下來在內存中完成
# 第二條 DML 語句成功之後,和底層數據庫文件的數據完成同步
# 若第二條 DML 語句失敗,清空所有相關的歷史操作記錄
update t_act set balance = 500000 where actno = "act-100";
update t_act set balance = 300000 where actno = "act-200";
事務隔離級別
InnoDB引擎中定義四種級別提供使用,級別越高隔離性越好,但性能越低,隔離級別由各種鎖和MVCC機制實現。
- 事務A和事務B之間具有一定隔離性
- 4個隔離級別:
- read uncommitted 讀未提交:
- 事務A和事務B,事務A "未提交" 數據,事務B可以讀取,導致 "髒數據"。
- read committed 讀已提交:
- 事務A和事務B,事務A "提交" 數據,事務B才能讀取,導致 "不可重複讀"。Oracle 預設隔離級別
- repeatable read 可重複讀
- 事務A和事務B,事務A "提交" 數據,事務B不能讀取,達到 "可重複讀,避免髒讀",導致 "幻象讀"(讀取緩存,事務結束緩存更新產生新的數據)。MYSQL 預設隔離級別
- serializable 串行化:
- 事務A和事務B,事務A在操作數據庫表中的數據時,事務B只能排隊等待,不再併發,此級別很少使用,吞吐量低用戶體驗差,達到 "避免幻象讀",每次讀取都是數據庫的真實數據。
- read uncommitted 讀未提交:
- 事務隔離級別,決定事務之間可見的級別。
- 客戶端併發訪問同一張表時,可能出現一致性問題:
- 髒讀取(Dirty Read):一個事務開始讀取某數據,但是另一個事務已經更新了此數據但還未提交,產生髒讀取。
- 不可重複讀(Non-repeatable Read):同一個事務中,同一個讀操作對同一個數據的前後兩次讀取產生不同結果,這就是不可重複讀。
- 幻想讀(Phantom Read):同一個事務中,以前沒有的數據,由於其他事務提交而出現的數據。快照讀。
隔離級別與一致性
隔離級別 | 髒讀取 | 不可重複讀 | 幻想讀 |
---|---|---|---|
讀未提交 | 可能 | 可能 | 可能 |
讀已提交 | 不可能 | 可能 | 可能 |
可重複讀 | 不可能 | 不可能 | 對InnoDB不可能 |
串行化 | 不可能 | 不可能 | 不可能 |