MySQL性能調優(4)Innodb存儲引擎的事務

事務

數據庫操作的最小工作單元,是作爲單個邏輯工作單元執行的一系列操作;事務是一組不可再分割的操作集合(工作邏輯單元);

MySQL中如何開啓事務:
begin / start transaction -- 手工
commit / rollback -- 事務提交或回滾
set session autocommit = on/off; -- 設定事務是否自動開啓
JDBC編程開啓事務
connection.setAutoCommit(boolean);
true:sql命令的提交(commit)由驅動程序負責 
false:sql命令的提交由應用程序負責,程序必須調用commit或者rollback方法// connection.commit()
事務的ACID特性
  • 原子性(Atomicity)

最小的工作單元,整個工作單元要麼一起提交成功,要麼全部失敗回滾

  • 一致性(Consistency)

事務中操作的數據及狀態改變是一致的,即寫入資料的結果必須完全符合預設的規則,不會因爲出現系統意外等原因導致狀態的不一致

原子性和一致性的的側重點不同:原子性關注狀態,要麼全部成功,要麼全部失敗,不存在部分成功的狀態。
而一致性關注數據的可見性,中間狀態的數據對外部不可見,只有最初狀態和最終狀態的數據對外可見。
  • 隔離性(Isolation)

一個事務所操作的數據在提交之前,對其他事務的可見性設定(一般設定爲不可見)

  • 持久性(Durability)

事務所做的修改就會永久保存,不會因爲系統意外導致數據的丟失

理解併發帶來的髒讀、幻讀、不可重複讀
  • 髒讀

髒讀就是指當一個事務正在訪問數據,並且對數據進行了修改,而這種修改還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然後使用了這個數據。

  • 不可重複讀(同樣的條件,你讀取過的數據,再次讀取出來發現值不一樣了

是指在一個事務內,多次讀同一數據。在這個事務還沒有結束時,另外一個事務也訪問該同一數據。那麼,在第一個事務中的兩次讀數據之間,由於第二個事務的修改,那麼第一個事務兩次讀到的的數據可能是不一樣的。這樣在一個事務內兩次讀到的數據是不一樣的,因此稱爲是不可重複讀。

  • 幻讀 ( 幻讀的重點在於新增或者刪除)

是指當事務不是獨立執行時發生的一種現象,例如第一個事務對一個表中的數據進行了修改,這種修改涉及到表中的全部數據行。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入一行新數據。那麼,以後就會發生操作第一個事務的用戶發現表中還有沒有修改的數據行,就好象發生了幻覺一樣。

事務的隔離級別

MySQL 8.0 查看事務的默認隔離級別

show variables  like 'transaction_isolation';
  • Read Uncommitted(未提交讀簡稱RU) --未解決併發問題

事務未提交對其他事務也是可見的,也被稱之爲髒讀(Dirty Read)。

  • Read Committed(提交讀簡稱RC) --解決髒讀問題

事務成功提交後纔可以被查詢到,也被稱爲不可重複讀(Nonrepeatable Read)。

  • Repeatable Read (可重複讀簡稱RR) --解決不可重複讀問題

在同一個事務中多次讀取同樣的數據結果是一樣的,這種隔離級別未定義解決幻讀的問題MySQL默認級別;Innodb引擎通過MVCC來解決幻讀問題

  • Serializable(串行化) --解決所有問題

最高的隔離級別,通過強制事務的串行執行

Innodb對隔離級別的支持程度

Innodb事務的隔離級別是通過鎖+MVCC實現的

| 事務的隔離級別 | 髒讀 | 不可重複讀 |幻讀|
| :------: | :------: | :------: |
| 未提交讀(Read Uncommitted) | 可能 |可能|可能|
| 已提交讀(Read Committed) | 不可能 |可能|可能|
| 可重複讀(Repeatable Read) | 不可能 |不可能|對Innodb不可能(具體看MVCC)|
| 可串行化(Serializable) | 不可能 |不可能|不可能|

鎖是用於管理不同事務對共享資源的併發訪問

表鎖與行鎖的區別:
鎖定粒度:表鎖 > 行鎖 
加鎖效率:表鎖 > 行鎖 
衝突概率:表鎖 > 行鎖
併發性能:表鎖 < 行鎖

InnoDB存儲引擎支持行鎖和表鎖(整個表所有行加鎖)

行鎖

InnoDB的行鎖是通過給索引上的索引項加鎖來實現的。只有通過索引條件進行數據檢索,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖(鎖住索引的所有記錄)

lock tables xx read/write;// 鎖定表分別是表的讀鎖和寫鎖
UNLOCK TABLES;// 釋放鎖
共享鎖(Shared Locks)
又稱爲讀鎖,簡稱S鎖,顧名思義,共享鎖就是多個事務對於同一數據可以共享一把鎖,都能訪問到數據,但是隻能讀不能修改;
加鎖釋鎖方式:
select * from users WHERE id=1 LOCK IN SHARE MODE;
commit/rollback //提交或者回滾
排他鎖(Exclusive Locks)
又稱爲寫鎖,簡稱X鎖,排他鎖不能與其他鎖並存,如一個事務獲取了一個數據行的排他鎖,其他事務就不能再獲取該行的鎖(共享鎖、排他鎖),
只有該獲取了排他鎖的事務是可以對數據行進行讀取和修改,(其他事務要讀取數據可來自於快照):
加鎖釋鎖方式:
delete / update / insert 默認加上X鎖
SELECT * FROM table_name WHERE ... FOR UPDATE
commit/rollback 
意向共享鎖(IS)與意向排它鎖(IX)

意向鎖(IS、IX)是InnoDB數據操作之前自動加的,不需要用戶干預,但是要理解有這麼一個流程
意義:當事務想去進行鎖表時,可以先判斷意向鎖是否存在,存在時則可快速返回該表不能啓用表鎖。

意向共享鎖(IS)

表示事務準備給數據行加入共享鎖,即一個數據行加共享鎖前必須先取得該表的IS鎖,意向共享鎖之間是可以相互兼容的

意向排它鎖(IX)

表示事務準備給數據行加入排他鎖,即一個數據行加排他鎖前必須先取得該表的IX鎖,意向排它鎖之間是可以相互兼容的

自增鎖

針對自增列自增長的一個特殊的表級別鎖;
開啓事務,添加數據時,然後回滾了,那麼這個id就永久消失了;

show variables like 'innodb_autoinc_lock_mode';
MySQL8.0 默認取值 2
0:traditonal (每次都會產生表鎖)
1:consecutive (會產生一個輕量鎖,simple insert會獲得批量的鎖,保證連續插入)
2:interleaved (不會鎖表,來一個處理一個,併發最高)
// 這塊沒有深入理解
記錄鎖(Record)間隙鎖(Gap)臨鍵鎖(Next-key)

首先來看看測試的數據庫表結構

Next-key locks臨鍵鎖(Innodb)
鎖住記錄+區間(左開右閉) 當sql執行按照索引進行數據的檢索時,查詢條件爲範圍查找(between and、<、>等)並有數據命中則此時SQL語句加上的鎖爲Next-key locks,鎖住索引的記錄+區間(左開右閉) ###### Gap locks間隙鎖: 鎖住數據不存在的區間(左開右開) 當sql執行按照索引進行數據的檢索時,查詢條件的數據不存在,這時SQL語句加上的鎖即爲Gap locks,鎖住索引不存在的區間(左開右開) ###### Record locks記錄鎖: 記錄鎖可以說是最好的性能了:只鎖了一條記錄:這就是我們爲什麼要鍵索引,索引要建立好的原因。 鎖住具體的索引項 當sql執行按照唯一性(Primary key、Unique key)索引進行數據的檢索時,查詢條件等值匹配且查詢的數據是存在,這時SQL語句加上的鎖即爲記錄鎖Record locks,鎖住具體的索引項。

利用鎖解決髒讀、不可重複讀、幻讀

髒讀:可以通多寫數據時給數據加上X排它鎖解決
不可重複讀:可以通過讀取時加上S共享鎖來解決
幻讀:可以通過臨鍵鎖來解決

死鎖

多個併發事務(2個或者以上),事務之間產生加鎖的循環等待,形成死鎖。

怎樣避免死鎖
  1. 類似的業務邏輯以固定的順序訪問表和行。
  2. 大事務拆小。大事務更傾向於死鎖,如果業務允許,將大事務拆小。
  3. 在同一個事務中,儘可能做到一次鎖定所需要的所有資源,減少死鎖概
    率。
  4. 降低隔離級別,如果業務允許,將隔離級別調低也是較好的選擇
  5. 爲表添加合理的索引。可以看到如果不走索引將會爲表的每一行記錄添加上鎖(或者說是表鎖)

一但不走索引,innodb就會提升爲表鎖,這樣就會增加死鎖衝突機率

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章