目錄
一、關於SQL數據庫
SQL數據庫承擔了各種應用程序的核心數據存儲,而NoSQL數據庫作爲SQL數據庫的補充,兩者不再是二選一的問題,而是主從關係。
爲什麼需要數據庫?
隨着應用程序的功能越來越複雜,數據量越來越大,如何管理這些數據就成了大問題。
數據庫作爲一種專門管理數據的軟件。應用程序不需要自己管理數據,而是通過數據庫軟件提供的接口來讀寫數據。至於數據本身如何存儲到文件,那是數據庫軟件的事情,應用程序自己並不關心。
總的來說,SQL語言定義了這麼幾種操作數據庫的能力:
DDL:Data Definition Language
DDL允許用戶定義數據,也就是創建表、刪除表、修改表結構這些操作。通常,DDL由數據庫管理員執行。
DML:Data Manipulation Language
DML爲用戶提供添加、刪除、更新數據的能力,這些是應用程序對數據庫的日常操作。
DQL:Data Query Language
DQL允許用戶查詢數據,這也是通常最頻繁的數據庫日常操作。
語法特點
SQL語言關鍵字不區分大小寫!!!
二、關係模型
字段定義了數據類型(整型、浮點型、字符串、日期等),以及是否允許爲NULL
。注意NULL
表示字段數據不存在。一個整型字段如果爲NULL
不表示它的值爲0
,同樣的,一個字符串型字段爲NULL
也不表示它的值爲空串''
。
通常情況下,字段應該避免允許爲NULL。不允許爲NULL可以簡化查詢條件,加快查詢速度,也利於應用程序讀取數據後無需判斷是否爲NULL。
1、主鍵和外鍵
對於關係表,有個很重要的約束,就是任意兩條記錄不能重複。不能重複不是指兩條記錄不完全相同,而是指能夠通過某個字段唯一區分出不同的記錄,這個字段被稱爲主鍵。
選取主鍵的一個基本原則是:不使用任何業務相關的字段作爲主鍵。
作爲主鍵最好是完全業務無關的字段,我們一般把這個字段命名爲id
。
由於外鍵約束會降低數據庫的性能,大部分互聯網應用程序爲了追求速度,並不設置外鍵約束,而是僅靠應用程序自身來保證邏輯的正確性。
一些應用會把一個大表拆成兩個一對一的表,目的是把經常讀取和不經常讀取的字段分開,以獲得更高的性能。例如,把一個大的用戶表分拆爲用戶基本信息表user_info
和用戶詳細信息表user_profiles
,大部分時候,只需要查詢user_info
表,並不需要查詢user_profiles
表,這樣就提高了查詢速度。
2、索引
索引是關係數據庫中對某一列或多個列的值進行預排序的數據結構。通過使用索引,可以讓數據庫系統不必掃描整個表,而是直接定位到符合條件的記錄,這樣就大大加快了查詢速度。
創建索引:
ALTER TABLE students ADD INDEX idx_score (score);
索引的效率取決於索引列的值是否散列,即該列的值如果越互不相同,那麼索引效率越高。反過來,如果記錄的列存在大量相同的值,例如gender(性別)
列,大約一半的記錄值是M(男)
,另一半是F(女)
,因此,對該列創建索引就沒有意義。
可以對一張表創建多個索引。索引的優點是提高了查詢效率,缺點是在插入、更新和刪除記錄時,需要同時修改索引,因此,索引越多,插入、更新和刪除記錄的速度就越慢。
對於主鍵,關係數據庫會自動對其創建主鍵索引。使用主鍵索引的效率是最高的,因爲主鍵會保證絕對唯一。
唯一索引和唯一約束
通過UNIQUE
關鍵字我們可以添加一個唯一索引。
ALTER TABLE students ADD UNIQUE INDEX uni_name (name);
也可以只對某一列添加一個唯一約束而不創建唯一索引
ALTER TABLE students ADD CONSTRAINT uni_name UNIQUE (name);
這種情況下,name
列沒有索引,但仍然具有唯一性保證。
三、數據操作
1、查詢
SQL數據庫查詢大體可分爲基本查詢、條件查詢、投影查詢、分頁查詢、聚合查詢、多表查詢、連接查詢等。
模糊匹配
使用LIKE判斷相似 | name LIKE 'ab%' | name LIKE '%bc%' | %表示任意字符,例如'ab%'將匹配'ab','abc','abcd' |
排序
默認的排序規則是ASC
:“升序”,即從小到大。ASC
可以省略,即ORDER BY score ASC
和ORDER BY score
效果一樣。
2、修改
關係數據庫的基本操作就是增刪改查,即CRUD:Create、Retrieve、Update、Delete。
而對於增、刪、改,對應的SQL語句分別是:—— 均可進行數據的批量操作
- INSERT:插入新記錄;
- UPDATE:更新已有記錄;
- DELETE:刪除已有記錄。
四、數據庫事務
把多條語句作爲一個整體進行操作的功能,被稱爲數據庫事務。數據庫事務可以確保該事務範圍內的所有操作都可以全部成功或者全部失敗。如果事務失敗,那麼效果就和沒有執行這些SQL一樣,不會對數據庫數據有任何改動。
數據庫事務具有ACID這4個特性:
- A:Atomic,原子性,將所有SQL作爲原子工作單元執行,要麼全部執行,要麼全部不執行;
- C:Consistent,一致性,事務完成後,所有數據的狀態都是一致的,即A賬戶只要減去了100,B賬戶則必定加上了100;
- I:Isolation,隔離性,如果有多個事務併發執行,每個事務作出的修改必須與其他事務隔離;
- D:Duration,持久性,即事務完成後,對數據庫數據的修改被持久化存儲。
對於單條SQL語句,數據庫系統自動將其作爲一個事務執行,這種事務被稱爲隱式事務。
要手動把多條SQL語句作爲一個事務執行,使用BEGIN
開啓一個事務,使用COMMIT
提交一個事務,這種事務被稱爲顯式事務,例如,把上述的轉賬操作作爲一個顯式事務:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
數據庫事務是由數據庫系統保證的,我們只需要根據業務邏輯使用它就可以。
隔離級別
對於兩個併發執行的事務,如果涉及到操作同一條記錄的時候,可能會發生問題。因爲併發操作會帶來數據的不一致性,包括髒讀、不可重複讀、幻讀等。數據庫系統提供了隔離級別來讓我們有針對性地選擇事務的隔離級別,避免數據不一致的問題。
SQL標準定義了4種隔離級別,分別對應可能出現的數據不一致的情況:
Isolation Level | 髒讀(Dirty Read) | 不可重複讀(Non Repeatable Read) | 幻讀(Phantom Read) |
---|---|---|---|
Read Uncommitted | Yes | Yes | Yes |
Read Committed | - | Yes | Yes |
Repeatable Read | - | - | Yes |
Serializable | - | - | - |
(1)Read Uncommitted-髒讀
Read Uncommitted是隔離級別最低的一種事務級別。在這種隔離級別下,一個事務會讀到另一個事務更新後但未提交的數據,如果另一個事務回滾,那麼當前事務讀到的數據就是髒數據,這就是髒讀(Dirty Read)。
髒讀場景:分別開啓兩個MySQL客戶端連接,按順序依次執行事務A和事務B
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
2 | BEGIN; | BEGIN; |
3 | UPDATE students SET name = 'Bob' WHERE id = 1; | |
4 | SELECT * FROM students WHERE id = 1; | |
5 | ROLLBACK; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
(2)Read Committed-不可重複讀
在Read Committed隔離級別下,一個事務可能會遇到不可重複讀(Non Repeatable Read)的問題。
不可重複讀是指,在一個事務內,多次讀同一數據,在這個事務還沒有結束時,如果另一個事務恰好修改了這個數據,那麼,在第一個事務中,兩次讀取的數據就可能不一致。
不可重複讀場景:分別開啓兩個MySQL客戶端連接,按順序依次執行事務A和事務B:
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; | SET TRANSACTION ISOLATION LEVEL READ COMMITTED; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 1; | |
4 | UPDATE students SET name = 'Bob' WHERE id = 1; | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 1; | |
7 | COMMIT; |
(3)Repeatable Read - 幻讀
在Repeatable Read隔離級別下,一個事務可能會遇到幻讀(Phantom Read)的問題。
幻讀是指,在一個事務中,第一次查詢某條記錄,發現沒有,但是,當試圖更新這條不存在的記錄時,竟然能成功,並且,再次讀取同一條記錄,它就神奇地出現了。
幻讀場景:分別開啓兩個MySQL客戶端連接,按順序依次執行事務A和事務B:
時刻 | 事務A | 事務B |
---|---|---|
1 | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; | SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; |
2 | BEGIN; | BEGIN; |
3 | SELECT * FROM students WHERE id = 99; | |
4 | INSERT INTO students (id, name) VALUES (99, 'Bob'); | |
5 | COMMIT; | |
6 | SELECT * FROM students WHERE id = 99; | |
7 | UPDATE students SET name = 'Alice' WHERE id = 99; | |
8 | SELECT * FROM students WHERE id = 99; | |
9 | COMMIT; |
幻讀就是沒有讀到的記錄,以爲不存在,但其實是可以更新成功的,並且,更新成功後,再次讀取,就出現了。
(4)Serializable - 串行化
Serializable是最嚴格的隔離級別。在Serializable隔離級別下,所有事務按照次序依次執行,因此,髒讀、不可重複讀、幻讀都不會出現。
雖然Serializable隔離級別下的事務具有最高的安全性,但是,由於事務是串行執行,所以效率會大大下降,應用程序的性能會急劇降低。如果沒有特別重要的情景,一般都不會使用Serializable隔離級別。
(5)默認隔離級別
如果沒有指定隔離級別,數據庫就會使用默認的隔離級別。在MySQL中,如果使用InnoDB,默認的隔離級別是Repeatable Read。