# 知識點3mysql
悲觀鎖-一鎖二查三更新pcc,pessimistic concurrency control
樂觀鎖-在數據上加一個版本號或者時間戳occ,optimistic concurrency control
acid:
A: 原子性(atomicity)
C: 一致性(consistency)
I: 隔離行(isolation)
D: 持久性(durability)
MySQL事務的實現
隔離性通過Mysql InnoDB鎖就可以實現,
原子性、一致性、持久性通過數據庫的redo和undo來完成
對于事務操作的統計
QPS:question per second,每秒請求數
TPS:transaction per second,每秒事務處理的能力
計算TPS的方法是(com_commit+com_rollback)/time,用這種方法的前提是,所有的事務必須都是顯式提交的。
SQL標準定義的四個隔離級別為:
1、READ UNCOMMITED
2、READ COMMITED
3、REPEATABLE READ
4、SERIALIZABLE
1, READ UNCOMMITTED(未提交讀)
事務中的修改,即使沒有提交,對其它事務也是可見的. 臟讀(Dirty Read).
2, READ COMMITTED(提交讀)
一個事務開始時,只能"看見"已經提交的事務所做的修改. 這個級別有時候也叫不可重復讀(nonrepeatable read).
3, REPEATABLE READ(可重復讀)
該級別保證了同一事務中多次讀取到的同樣記錄的結果是一致的. 但理論上,該事務級別還是無法解決另外一個幻讀的問題(Phantom Read).
幻讀: 當某個事務讀取某個范圍內的記錄時,另外一個事務又在該范圍內插入了新的記錄.當之前的事務再次讀取該范圍時,會產生幻行.(Phantom Row).
幻讀的問題理應由更高的隔離級別來解決,但mysql和其它數據不一樣,它同樣在可重復讀的隔離級別解決了這個問題.
也就是說, mysql的可重復讀的隔離級別解決了 "不可重復讀" 和 “幻讀” 2個問題. 稍后我們可以看見它是如何解決的.
而oracle數據庫,可能需要在 “SERIALIZABLE ” 事務隔離級別下才能解決 幻讀問題.
mysql默認的隔離級別也是: REPEATABLE READ(可重復讀)
4, SERIALIZABLE (可串行化)
強制事務串行執行,避免了上面說到的 臟讀,不可重復讀,幻讀 三個的問題.
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
1 row in set
mysql> select @@global.tx_isolation;
+-----------------------+
| @@global.tx_isolation |
+-----------------------+
| REPEATABLE-READ |
+-----------------------+
1 row in set
mysql> show variables like 'innodb_support_xa';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| innodb_support_xa | ON |
+-------------------+-------+
1 row in set
MVCC(Multi-Version Concurrency Control) 多版本并發控制
MVCC的實現,是通過保存數據在某個時間點的快照來實現的.
InnoDB的MVCC是通過在每行記錄后面保存2個隱藏的列來實現的,一列保存了行的創建時間,一列保存了行的過期時間(或刪除時間).但它們都存儲的是系統版本號
MVCC最大的作用是: 實現了非阻塞的讀操作,寫操作也只鎖定了必要的行.(并行讀,行鎖)
MYSQL的MVCC 只在 read committed 和 repeatable read 2個隔離級別下工作.
InnoDB 鎖的算法
5.1 Record Lock: 單個行記錄的鎖
5.2 GAP Lock: 間隙鎖,鎖定一個范圍,但不包含記錄本身.
5.3 Next-Key Lock: Gap Lock+Record Lock 鎖定一個范圍并鎖定記錄本身.
下面的2句話是InnoDB在不同隔離級別下產生"不可重復讀" 和 "幻讀" 和解決它 的根本原因:
InnoDB存儲引擎默認的事務隔離級別(repeatable read)下,采用的是 Next-Key Locking的方式來加鎖.
read committed隔離級別下采用的是: Record Lock 的方式來加鎖.
總結:
1, InnoDB用MVCC來實現非阻塞的讀操作,不同隔離級別下,MVCC通過讀取不同版本的數據來解決"不可重復讀" 的問題.
2, InnoDB的默認隔離級別解決2個問題,"不可重復讀" 和 "幻讀", oracle需要在串行讀中解決"幻讀"問題. InnoDB的實現方式和一般隔離級別的定義不一致.
3, InnoDB的默認隔離級別采用Next-key Lock(間隙鎖) 來解決幻讀問題. 而 read committed隔離級別采用Record鎖,因此會產生"幻讀"問題.
4, InnoDB的存儲引擎不存在鎖升級的問題(太多的行鎖升級為表鎖),來降低鎖的開銷. 因為不是根據記錄來產生行鎖的,根據頁對鎖進行管理.
事務的分類
1.1 扁平事務
要么都執行,要么都回滾,InnoDB最常用,最常見的事務.
1.2 帶有保存點的偏平事務
事務的操作過程有 begin, A, B, C, D, commit 幾個過程,那么帶有保存點的扁平事務過程大致如下:
begin--> 隱含保存點1(save work 1)-->A-->B(save work2)-->C-->D(rollback work2) -->commit
上述過程中如果遇到rollback work2, 只需要回滾到保存點2,不需要全部回滾.
簡單來說,帶有保存點的扁平事務就是有計劃的回滾操作。
保存點是容易失的(volatile), 而非持久的.系統崩潰,所有保存點都將丟失.
1.3 鏈事務
鏈事務提交一個事務時,釋放不需要的數據對象,將必要的上下文傳遞給下一個要開始的事務. 下一個事務可以看到上一個事務的結果.
帶有保存點的偏平事務可以回滾到任意正確的保存點,鏈事務只能回滾到當前事務.
扁平全程持鎖,鏈事務在commit后釋放鎖.
鏈事務如: T1->T2->T3
1.4 嵌套事務
可以理解為一顆事務樹,頂層事務控制著下面的子事務. 所有的葉子節點是扁平事務,實際工作是由葉子節點完成的.
1.5 分布式事務
分布式環境下運行的扁平事務.
InnoDB支持上述除嵌套事務以外的所有事務類型.
總結
1, redo log(事務日志)保證事務的原子性和持久性(物理日志)
2, undo log保證事務的一致性,InnoDB的MVCC也是用undo log來實現的(邏輯日志).
3, redo log中帶有有checkPoint,用來高效的恢復數據.
4, 物理日志記錄的是修改頁的的詳情,邏輯日志記錄的是操作語句. 物理日志恢復的速度快于邏輯日志.