該文爲《 MySQL 實戰 45 講》的學習筆記,感謝查看,若有錯誤,歡迎指正
mysql
事務就是爲了保證一組數據庫操做,要麼所有成功,要麼所有失敗。sql
事務是在引擎層實現的,也就是說並非全部引擎均可以使用事務,MyISAM 就不支持事務,這也是爲何會被 InnoDB 取代的緣由。數據庫
說到事務,就不得不說 ACID 特性(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔離性、持久性)。安全
一個事務中的多組操做,要麼所有成功,要麼所有失敗。在事務提交(commit)成功以後,全部的操做都生效,提交失敗,全部的操做都會回滾。微信
一個事務執行以前和執行以後數據庫都必須處於一致性狀態。在事務執行的過程當中,只要事務未提交,就不會改變數據庫的狀態。提交以後事務已完成,此時數據庫狀態發生變化。併發
事務在執行過程當中,是與外界徹底隔離的,即便數據庫發生了變動,事務中也獲取不到。A 事務對數據庫作的變動,在事務未提交之間,數據庫中也看不到,B 事務中也看不到。學習
事務一旦提交,對數據庫的變動就會持久化到磁盤,即便數據庫發生異常重啓,數據也不會丟失。
atom
當數據庫出現有多個事務同時執行時,就可能出現髒讀
,幻讀
,不可重複讀
等問題,隔離級別就是爲了解決這些問題的。隔離的越嚴實,效率就越低,併發越低,安全性越高。日誌
隔離級別分爲如下 4 種:code
讀未提交(read uncommitted,RU)
一個事務還未提交時,它作的變動就能夠被別的事務看到。
讀提交(read committed,RC)
事務提交之後,它作的變動才能被其它事務看到。可是在這個事務未提交以前,數據庫中發生的變動,這個事務也能看見。
可重複度(repeatable read,RR)
事務老是隻能看見在啓動的那個時刻,數據庫的狀態。事務未提交以前作的變動,其它事務看不見。事務執行期間,數據庫中已經發生的變動,這個事務也看不見。只能看見事務剛啓動時刻,數據庫的狀態。
串行化(serializable)
事務對某一行的操做會加鎖,「寫」會加「寫鎖」,「讀」會加「讀鎖」,在鎖釋放掉以前,其它的事務都沒法都這一行的記錄進行操做。必須等以前的事務執行完畢,釋放鎖。後面的事務又會從新加鎖。
咱們經過一個例子來講明一下四種隔離級別具體是怎麼體現的。
給出一個建表語句:
mysql> create table T(c int) engine=InnoDB; mysql> insert into T(c) values(1);
假設有如下兩個事務,其中執行的操做如圖,從上至下是時間前後順序:
在四種不一樣的隔離級別下,V1
、V2
、V3
的值分別爲多少呢?咱們如今分析一下:
讀未提交
讀提交下,事務還未提交,作的變動就能被其它事務看見,所以事務 B 修改了值爲 2 ,事務 A 能夠直接看見。因此 V1 = 2
,V2 = 2
,V3 = 2
。
讀提交(RC)
讀提交下,事務在提交以前,作的變動都沒法被其它事務看見,可是事務自己能夠看到數據庫的變動。 所以,事務 B 作了修改之後,事務 A 沒法馬上看見,V1 = 1
,事務 B 提交之後,事務 A 就能夠看到數據庫的變動了,所以 V2 = 2
,V3 = 2
。
可重複讀(RR)
事務老是隻能看到在啓動的那個時刻,數據庫的狀態,即在事務未提交以前,本身作的變動別的事務看不見,數據庫中的變動本身也看不見。
所以,事務 B 提交以前,A 看不見 B 作的變動,V1 = 1
,事務 B 提交之後,數據庫的值雖然發生了變動,可是事務 A 還未提交,A 仍是隻能看到本身在啓動時刻,數據庫的值(能夠理解爲數據庫有版本,只能看見歷史版本)。所以,V2 = 1
,事務 A 提交之後,就能夠看到數據庫的變動了,所以 V3 = 2
。
串行化
串行化是指,事務在操做某一行記錄時會加鎖,「讀」會加「讀鎖」,「寫」會加「寫鎖」。
事務 A 在啓動後,先執行了 1 條查詢語句,對這行數據加了「讀鎖」,這個「讀鎖」要等事務 A 提交之後,纔會釋放。所以事務 B 執行查詢語句會處於等待鎖釋放狀態。這時候事務 B 會一直等待。所以,V1 = 1
,V2 = 1
,事務 A 提交以後,「讀鎖」釋放,事務 B 獲取該行記錄的「讀鎖」,並更新了數據(又加了一個「寫鎖」),事務 B 未提交以前,A 再去查數據也須要等待鎖釋放,事務 B 提交之後,鎖釋放,A 拿到鎖,開始查詢數據,所以,V3 = 2
。
以上是如何實現的呢?
數據庫中會建立一個視圖,在「可重複讀」隔離級別下,這個視圖是在事務啓動時建立的,整個事務存在期間都用這個視圖。在「讀提交」隔離級別下,這個視圖是在每一個 SQL 語句開始執行的時候建立的。這裏須要注意的是,「讀未提交」隔離級別下直接返回記錄上的最新值,沒有視圖概念;而「串行化」隔離級別下直接用加鎖的方式來避免並行訪問。
在 MySQL 中,實際上每條記錄在更新的時候都會同時記錄一條回滾操做。記錄上的最新值,經過回滾操做,均可以獲得前一個狀態的值。同一條記錄在系統中能夠存在多個版本,就是數據庫的多版本併發控制(MVCC)。
回滾日誌何時刪除呢,系統中沒有比這個回滾日誌更早的 read-view 時,這個回日誌就會被刪除。
所以不建議使用長事務,容易致使回滾日誌太多,大量佔用存儲空間。
begin
或 start transaction
。配套的提交語句是 commit
,回滾語句是 rollback
。set autocommit=0
,此時不須要顯式啓動,好比執行了一個select
語句就直接啓動了事務,可是須要再執行一條commit
來提交;所以建議設置set autocommit=1
,此時須要用begin
來開啓事務,若是以爲多了一次交互,比較麻煩的話,也可使用commit work and chain
,表示提交當前事務,而且再啓動一個新的事務,這樣就只有一次begin
了。
感謝閱讀,有興趣的小夥伴能夠關注個人微信公衆號DevOps探索之旅
,你們一塊兒學習進步