數據庫事務是指作為單個邏輯工作單元執行的一系列操作,要么完全執行,要么完全地不執行。
事務必須具備ACID四個特性:
原子性是指事務包含的所有操作要么全部成功,要么全部失敗回滾。
一致性是指事務必須使數據庫從一個一致的狀態變到另外一個一致的狀態,也就是執行事務之前和之后的狀態都必須處于一致的狀態。
隔離性是指當多個用戶并發訪問數據庫時,比如操作同一張表時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作所干擾,多個并發事務之間要相互隔離。
持久性是指一個事務一旦被提交了,那么對于數據庫中的數據改變就是永久性的,即便是在數據庫系統遭遇到故障的情況下也不會丟失提交事務的操作。
提交事務:
>set autocommit = 0 禁止自動提交
>start transaction;
>update accout set money=money+100 where name="Jason";
>commit;
回滾事務:
>set autocommit = 0 禁止自動提交
>start transaction;
>update account set money=money-100 where name="justin";
>rollback;
1、事務的隔離級別
mysql修改事務的隔離級別
>set? [global | session]? transaction isolation level 隔離級別名稱;
>set tx_isolation=’隔離級別名稱;’
隔離級別:Serializable | Repeatable read | Read committed |Read uncommitted
設置默認級別是指當前session的下一個事務
設置session級別是指當前session以后的所有事務
設置global級別是指對之后的所有session,不包括當前session
四種隔離級別和可能產生的問題
不可重復讀:Read committed讀已提交事務的數據,可能是兩次查詢過程中間插入了一個事務更新的原有的數據,導致出現同一事務的不同實例先后讀取的內容不同。在 Repeatable read通過數據庫事務版本號方式解決。
事務1:
mysql> begin;
Query OK, 0 rows affected
mysql> select * from student where stu_id = 2;
+----+------+--------+
| id | name | stu_id |
+----+------+--------+
|? 2 | 生物 |????? 2 |
+----+------+--------+
1 row in set
事務2:
mysql> begin;
Query OK, 0 rows affected
mysql> update student set name = '地理' where stu_id = 2;
Query OK, 1 row affected
Rows matched: 1? Changed: 1? Warnings: 0
mysql> commit;
Query OK, 0 rows affected
接下來事務1再次查詢:
mysql> select * from student where stu_id = 2;
+----+------+--------+
| id | name | stu_id |
+----+------+--------+
|? 2 | 地理 |????? 2 |
+----+------+--------+
1 row in set
上述過程可見,帶事務1的一個事務中,兩次請求得到了不同的結果,就導致了不可重復讀的現象。
幻讀:在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。
數據庫默認隔離級別是 Repeatable read。
2、鎖與事務
數據庫采用兩段鎖協議(Two-Phase Locking――2PL)
在對任何數據進行讀、寫操作之前,首先要申請并獲得對該數據的封鎖,即擴展階段。
在釋放一個封鎖之后,事務不再申請和獲得其它任何封鎖,即收縮階段。
若所有事務均遵守兩段鎖協議,則這些事務的所有交叉調度都是可串行化的。
mysql的讀操作,通常是不會加鎖的(和隔離機制有關),也就是說通常的讀操作是不加鎖的,而是通過mvcc去解決的,對于通常的寫請求,insert、update、delete通常會加行鎖、間隙鎖或表鎖(這和索引是有關系的),這些鎖通常是排他的,會阻塞其他的事務寫事務。具體的情況需要結合隔離機制。
(1)、鎖的類型:
共享鎖(S Lock)和排他鎖(X Lock)
意向共享鎖(IS Lock):事務想要獲取一張表中的某幾行共享鎖。
意向排他鎖(IX Lock):事務想要獲取一張表中的某幾行的排它鎖。
表鎖:
對一整張表加鎖,并發能力低下(即使有分讀鎖、寫鎖),一般在DDL處理時使用。
行鎖:
只鎖住特定行的數據,并發能力強,MySQL一般都是用行鎖來處理并發事務。
在更新記錄的時候會對此記錄加行鎖,在事務沒有commit之前不會釋放鎖,所以事務2的更新會阻塞等待事務1的排它鎖,當事務1Commit后,行鎖釋放事務2獲得行鎖,更新成功。
Gap鎖(間隙鎖):
是MySQL使用索引對行鎖兩邊的區間進行加鎖,避免其他事務在這兩個區間insert的一種鎖。
如圖所示:數據庫中存在值5,30。那么數據庫會將數據段切分以下幾個區間:
(negative infinity, 5],(5,30],(30,positive infinity)
select * from table where number=30 for update;
當對值為30這一行加行鎖的時候,會同時對(5,30]和(30,positive infinity)加GAP鎖。這樣其他事務如果想在這兩個區間進行insert操作的時候,需要等待本次事務完成。如果對不存在的數據進行更新,比如更新20(不存在)對應數據行,那么數據庫也會對其存在的區間(5,30]加GAP鎖。
Next-Key鎖:
Next-Key鎖是行鎖和GAP鎖的合并(MySQL使用它來避免幻讀)。
當按照id(非唯一索引,不是主鍵)進行更新或刪除的時候會先對id索引進行next_key鎖,防止幻讀,因為新增加的記錄只能在30的左邊和30的右邊或者就是30。那么鎖住范圍后就能保證防止“幻讀”。
注意:如果用到無索引的字段,那么MySQL會在存儲引擎層面將所有的記錄加鎖,然后由MySQL Server過濾,如果不滿足會調用unlock_row把不滿足條件的記錄釋放鎖(這里違背了二段鎖協議)。
(2)、Mvcc(多版本并發控制):
Mvcc是多版本的并發控制協議,Innodb中的樂觀鎖實現。讀不加鎖,讀寫不沖突。通過它提高MySQL的讀取操作的性能。并能解決MySQL的重復讀問題。
MVVC在每一行記錄的后面加兩個隱含列(記錄創建版本號和刪除版本號)。這里的版本號指的是事務的版本號(每個事務啟動的時候,都有一個遞增的版本號)。在更新時進行版本號的遞增,插入時新建一個版本號,同時舊版本數據存儲在undo日志中。
? ● 比如插入一條記錄(事務id為1)
? ● 如果把這條記錄name更新為dog
在更新操作的時候,采用的是先標記舊的那行記錄為已刪除,并且刪除版本號是事務版本號,然后插入一行新的記錄的方式。
? ● 刪除這條記錄時
刪除操作的時候,就把事務版本號作為刪除版本號
執行查詢操作需要符合如下規則才能被查出來
1) 刪除版本號 大于 當前事務版本號,就是說刪除操作是在當前事務啟動之后做的。
2) 創建版本號 小于或者等于 當前事務版本號 ,就是說記錄創建是在事務中(等于的情況)或者事務啟動之前。
mvcc分為快照讀和當前讀。
快照讀只是針對于目標數據的版本小于等于當前事務的版本號,也就是說讀數據的時候可能讀到舊的數據,但是這種快照讀不需要加鎖,性能很高。
當前讀是讀取當前數據的最新版本,但是更新等操作會對數據進行加鎖,所以當前讀需要獲取記錄的行鎖,存在鎖爭用的問題。
下面是快照讀和當前讀的常見操作:
快照讀:就是select * from table ....;
當前讀:特殊的讀操作(加共享鎖或排他鎖),插入/更新/刪除操作,需要加鎖。
select from table where ? lock in share mode;
select from table where ? for update;
其實Mysql實現的Mvcc并不純粹,因為在當前讀的時候需要對記錄進行加鎖,而不是多版本競爭。下面是具體操作時的Mvcc機制:
? 1. SELECT時,讀取創建版本號<=當前事務版本號,刪除版本號為空或>當前事務版本號。
? 2. INSERT時,保存當前事務版本號為行的創建版本號
? 3. DELETE時,保存當前事務版本號為行的刪除版本號
? 4. UPDATE時,插入一條新紀錄,保存當前事務版本號為行創建版本號,同時保存當前事務版本號到原來刪除的行
總結:
RC提交讀,采用行鎖和MVCC的當前讀,有幻讀和不可重復讀問題。RR可重讀,采用Next-key(默認)和MVCC的快照讀,無幻讀和可重復讀。
mysql的鎖機制和事務隔離級別有關。并不是說所有的讀操作都不加鎖,寫操作加鎖,加什么鎖也和索引類型、有無索引有關。
感謝分享:
http://www.lxweimin.com/p/bcc614524024
http://www.lxweimin.com/p/edbe22beaecb