P4006 小 Y 和二叉樹
一、什麼是事務
事務是資料庫操作的最小工作單位,一個事務可以是一條sql語句,也可以是一組sql語句。
事務有四大特徵:原子性,永續性,隔離性,一致性,就是我們常說的ACID
二、原子性
原子性的意思是說一個事務裡的操作會組成一個最小的執行單位,不可再分割,在一個事務中,要麼操作都成功,要麼都失敗。比較經典的例子就是我們的轉賬,A向B轉賬,A要完成減錢,B要完成加錢,這些是都需要完成才能算一個事務完成。如果在其中發生了錯誤那麼就需要回滾。回滾的時候就需要用到我們回滾日誌,undo log。因為我們目前常用的儲存引擎都是Innodb,在Innodb中還使用undo log + mvcc來實現事務的可重複讀和讀已提交這兩個隔離級別。
undo log分為兩種,一種是insert undo log,用來記錄插入操作產生的回滾日誌,一種是update undo log,用來記錄更新,刪除操作的時候產生的回滾日誌。
當我們要操作資料之前,就先把資料備份到undo log中,然後我們再對資料進行修改,在這個過程中如果出現了錯誤,那麼mysql就會利用undo log中的資料來恢復。
undo log的工作方式可以簡單的理解成記錄相反的操作到日誌中,比如我們更新的時候,他就記錄一條之前更新的狀態,我們刪除資料的時候他就會新增一條資料,我們新增資料的時候他就會刪除一條資料。
三、永續性
永續性的意思是說當我們事務提交之後,他形成的資料應該被永久化為資料庫中。也就是應該持久化到磁碟上,因為在記憶體中一斷電就沒了。
永續性實現的原理是redo log,前滾日誌。
因為我們在更新完一條記錄的時候,我們資料是先在記憶體中的,再從記憶體持久化到我們的磁碟。
因為資料一開始在記憶體中,如果斷電肯定資料就沒了,所以redo log就是為了解決這個問題。
當我們每次執行完DML操作之後,也就是當我們事務commit的時候,這裡其實有一個非同步的操作。首先執行過程會寫入Buffer Pool,mysql會優先寫日誌,先保證日誌寫成功,寫日誌會有三種情況,0.寫到Log Buffer,1.直接寫到磁盤裡,然後每秒為單位寫到磁盤裡 2.寫到OS Buffer,然後每秒為單位寫到磁碟。這裡有一個引數innodb_flush_log_at_trx_commit
對於0和2這兩種方式,雖然都是寫到記憶體,但是還有有所差別的,因為Log Buffer屬於資料庫服務,而OS Buffer屬於作業系統,所以如果mysql服務掛了,那麼不會影響OS Buffer把資料寫到磁碟。
四、隔離性
隔離性是說事務之間的執行不應該產生相互影響,他們對資料庫的影響應該和他們序列執行的結果一樣。
但是如果是完成遵守隔離性,對併發的效能影響會比較大,所以一般來說我們工作中會對隔離性有所放寬。正是因為沒辦法兩全,所以產生了一些資料的問題,也就是髒讀,不可重讀,幻讀。sql的標準定義了四個隔離級別,分別是讀未提交,讀已提交,可重複讀,序列化。mysql預設隔離級別是可重複度。四個隔離級別分別是來解決這三種資料問題的。序列化是隔離級別是最高的隔離界別,這種隔離級別情況下,每個讀的資料行上都會加鎖,所以效率很慢,會導致大量的超時現象。可重複讀會出現幻讀,讀已提交會出現不可重讀和幻讀,讀未提交會出現髒讀,不可重讀,幻讀。
實現mysql的隔離級別主要利用的是鎖機制,利用鎖來解決了髒讀幻讀,不可重讀。mysql主要有三種級別的鎖,分別是行鎖,表鎖,頁鎖。表鎖不會出現死鎖,行鎖和頁鎖都有可能出現死鎖。
因為我們大部分是使用Innodb的引擎,所以我也說一下Innodb的鎖,就是兩種,共享鎖和排它鎖,他們都是行級別的鎖。共享是說同一行的資料,可以被多個事務獲取共享鎖,但是隻可以讀,不能修改。排他鎖是指一行資料只能被一個事務獲得排他鎖,獲取排他鎖的事務可以修改資料。
Innodb還支援行鎖和表鎖並存。他這裡的實現原理是利用意向鎖,意向鎖也是兩種,意向共享鎖和意向排他鎖。意向共享鎖就是說在事務準備給資料行加共享鎖前,先給這個表加一個意向共享鎖,意向排他鎖也是相同的意思。各個意向鎖之間是相容的,他設計這個的目的是:當事務想去進行鎖表時,可以先判斷意向鎖是否存在,存在時則可快速返回該表不能啟用表鎖,否則就需要等待。
我們使用Innodb主要是因為他支援行鎖,支援事務,Innodb的行鎖是給索引加鎖實現的,只有通過索引檢索資料,才能使用行鎖,不然就是會使用表鎖。這裡又要提到一個臨鍵鎖(next-key),其實臨鍵鎖就相當與記錄鎖(Record Locks)加上間隙鎖(Gap Locks)。記錄鎖很簡單是單條記錄的鎖,是單個的,間隙鎖也是見名知義,表示我們資料之間的空隙。就是我們的索引項有時候是不連續的,比如id有1,3,7,9這些id中間就有空隙,間隙鎖就是當我們進行範圍查詢的時候,會把這些空隙也鎖住。
通過上面的排他鎖,解決了髒讀,共享鎖解決了不可重複讀,臨鍵鎖解決了幻讀。
1.髒讀,幻讀,不可重讀
髒讀的意思是說多個事務在執行過程中,A事務讀取到了B事務還沒commit的資料,然後B事務又rollback回滾了,那麼A讀到的資料就是髒資料。
不可重讀是指在同一個事務A中,我們對同一組資料進行兩次一模一樣的查詢,但是因為在這兩次查詢中間,有事務B修改了資料,導致事務A兩次查詢結果不一樣,這就出現了不可重複讀。
幻讀一般是我們在進行範圍查詢的時候,事務A對id大於10的資料進行查詢,同樣也是兩次查詢,在這個過程中,事務B新增或者刪除了資料,導致事A在查詢的時候兩次結果不一致。也就是是幻讀。
五、一致性
事務的一致性可以說是最重要的。即事務執行前後資料應該是一致的。還是那個轉賬的例子,當A向B轉錢,那麼最終結果A減錢B加錢,這兩個的和應該還是一樣的。事務的一致性實現的原理其實就是之前是三個特性,原子性,隔離性,永續性共同保證了一致性。