事務
事務概念和用法這裏不詳細介紹,請自行百度吧
開啓事務 START TRANSACTION
提交 COMMIT
回滾ROLLBACK
事務需要經過嚴格的ACID測試。ACID分別代表
- A(atomicity)[ˌætəˈmɪsəti]:原子性
- C(consistency)[kənˈsɪstənsi] :一致性
- I(isolation) [ˌaɪsəˈleɪʃn]:隔離性
- D(durability)[dərəˈbɪlɪti]:持久性
原子性:一個事務必須被視爲一個不可分割的最小單位,要不全部提交成功,要麼全部失敗回滾。
一致性:數據庫總是從一個一致性的狀態轉換到另外一個一致性狀態,不會部分數據狀態改變了部分狀態沒有改變。
隔離性:通常來說,一個事務所做的修改在最終提交之前,對其他事務是不可見的。這個和數據庫的隔離級別有關,所以只能通常來說。
持久性:一旦事務提交,則其所做的修改會被永久保存到數據庫中。
隔離級別
- READ UNCOMMITTED(未提交讀)
事務中的修改,即使沒有提交,對其他事務也是可見的。 - READ COMMITTED(提交讀)
一個事務開始時,只能“看見”已經提交的事務所做的修改。有時候提交讀也叫不可重複讀(nonrepeatable read)。 - REPEATABLE READ(可重複讀)
同一個事務中,多次讀取同樣記錄的結果是一致的。mysql默認的隔離級別。 - SERIALIZABLE(可串行化)
最高隔離級別,讀取每一行數據都加上鎖,可能導致大量的超時和鎖爭用問題,一般不使用。
幾個常見概念
髒讀(Dirty Read):事務可以讀取未提交的數據
不可重複讀(nonrepeatable read),也叫虛讀:前後讀取的記錄數可能不一致。事務A在第一次讀取記錄文章閱讀數位5,然後事務B執行了更改,把閱讀數改爲10.事務A在第二次讀取文章閱讀數爲10.
幻讀(Phantom Read):當某個事務A在讀取某個範圍內的記錄時,另外一個事務B又在該範圍插入新的記錄,當事務A再次讀取該範圍的記錄時,會產生幻行。
網上看了很多人分不清不可重複讀和幻讀,我覺得是因爲不理解幻讀。幻讀舉例
CREATE TABLE `user` (
`id` INT ( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR ( 25 ) NOT NULL DEFAULT '',
`age` SMALLINT ( 5 ) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8;
INSERT INTO `user` ( `id`, `name`, `age` ) VALUE ( 1, "李一", 10 ),( 2, "李二", 20 );
結果如圖:
客戶端A和客戶端BB執行流程如下:
步驟 | 客戶端A | 客戶端B | 說明 |
---|---|---|---|
1 | START TRANSACTION; SELECT * FROM user; |
結果如圖1 | |
2 | DELETE FROM user WHERE id = 2 | 結果如圖2。MySQL默認採用自動提交方式,不顯式開啓一個事務,每個sql語句都當作一個事務 | |
3 | SELECT * FROM user; | 結果仍然和圖1一樣,id=2的行實際不存在,這時候出現了幻行 | |
4 | INSERT INTO user (id,name,age) VALUE (2,“老王”,40); SELECT * FROM user; |
在第3步查詢時候,存在id=2的行,且id是主鍵。結果如圖3 | |
5 | INSERT INTO user (id,name,age) VALUE (3,“李三”,30); | 此時,結果如圖4.但是客戶端A看到的結果仍然如圖3 | |
6 | SELECT * FROM user; | 客戶端A看到的結果仍然如圖3 | |
7 | INSERT INTO user (id,name,age) VALUE (3,“李三”,30); | 因爲id=3實際存在了,報錯:1062 - Duplicate entry ‘3’ for key ‘PRIMARY’ | |
8 | COMMIT; | 去掉步驟8的語句,提交事務,結果如圖5 |
圖1 | 圖2 | 圖3 |
---|---|---|
圖4 | 圖5 |
---|---|
兩個客戶端如下圖