Myql事務與鎖

事務

簡單的講就是保證一組sql 能同時成功 或者失敗

mysql 只有Innodb 支持事務

事務回滾原理通過undo-log 實現,大概意思就是,事務內執行的更新 刪除 新增sql 都會記錄一條類似逆向的sql 一旦需要回滾則執行逆向sql

事務特性:ACID

原子性: 事務內的sql執行狀態是統一的 要不都成功 要不都失敗;通過redo-log 日誌實現,只有提交後才持久化到磁盤,未提交的都記錄爲日誌

隔離性: 指多個事務併發訪問時,事務之間是隔離的,一個事務不應該影響其它事務運行效果;通過鎖技術實現

持久性: 指事務所提交後對數據庫所作的更改便持久的保存在數據庫之中,並不會被回滾;

一致性: 事務的最終追求,開啓事務執行sql 提交成功 與不開事務執行sql成功後的最後數據是一致的,不會因爲事務而改變結果,上面三個特性保證事務的一致性

mysql 事務隔離級別
Read uncommitted: 讀未提交,普通查詢不帶鎖,可以查詢到別的事務未提交的結果,簡稱髒讀;

Read Committed: 讀已提交,普通查詢不帶鎖,只能查詢到已提交的結果;

Repeatable Reads: 可重複讀,mysql默認級別,普通查詢不帶鎖,查尋到當前事務開始之前已提交的結果;

Serializable:串行化,多個併發事務會相互影響時,後面的事務操作必須等前面的事務完成後才能進行;(併發差就是等於普通查詢自帶讀鎖)

相關查詢sql

1.查看當前會話隔離級別
select @@tx_isolation;
2.查看系統當前隔離級別
select @@global.tx_isolation;
3.設置當前會話隔離級別 
set session transaction isolation level Serializable
4.設置系統當前隔離級別
set global transaction isolation level repeatable read;

不同隔離級別會出現的現象
在這裏插入圖片描述
髒讀: 讀取到別的事務未提交的數據,萬一別的事務執行失敗回滾,讀取的數據就不正確了;

不可重複讀:在一個事務內多次讀取同一個數據出現不一樣的結果;(在A事務內,B事務未提交時讀取一次數據與B提交成功後在讀取一次,兩次數據不一致,需要隔離級別爲讀已提交纔會出現)

幻讀: 在同一事務中,同一查詢多次進行時候,由於其他插入操作(insert)的事務提交,導致每次返回不同的結果集(mysql Innodb 在默認隔離級別不會出現幻讀,通過間隙鎖解決)

總結:mysql 只有Innodb 引擎支持事務,事務不同隔離級別會出現不同的數據讀取不一致現象,隔離實現方式是多版本控制(MVCC 快照方式)

鎖(Mysql5.644版本)

讀鎖 :又稱讀共享鎖,允許持有讀鎖的線程讀取對應數據
寫鎖 :鎖住後不允許其他帶鎖進程獲取數據;

不管讀鎖寫鎖 針對不帶鎖的查詢都是可以查到數據的,mysql只有在Serializable 隔離級別下並且autocommit=1時默認查詢纔會帶讀鎖

主動加鎖

 #增 刪 改 都會自動帶寫鎖 
 select .....  lock in share mode;  #主動加讀鎖
 select......  for update; #主動加寫鎖

表鎖 :直接鎖整張表,影響到表數據的更新都會阻塞,併發性能比較差;

頁面鎖 :鎖同一個數據頁的所有數據,就是讀取硬盤的最小單位,innodb 一般是16k;

行鎖: :
行鎖只針對innodb,通過鎖定索引實現,當查找數據沒有使用索引時,會加表鎖(其實是鎖住所有行主鍵索引)等到事務結束才釋放

行鎖又包含下面的具體實現

1:記錄鎖, 當查詢使用到索引並且能準確鎖定對應行,用 ‘’=" 或者 in() 精確查詢時會使用記錄鎖,只鎖住當前的行主鍵索引;

2:間隙鎖(只有在可重複讀隔離級別有,條件:查找數據爲空)間隙就是沒有數據的索引空間,當查詢使用到索引並且使用等值或者範圍索引時,如 ="= >= <="等並且查找數據爲空時則會使用間隙鎖,直接鎖住查找範圍左右臨近第一個有值的所有間隙,目的是防止新數據插入,出現幻讀

3:臨鍵鎖(next key lock範圍查找,有數據並且有間隙,會鎖索引,使用其他索引可以查找),鎖上查找到數據中最小索引值上一個左開右閉間隙間隙 至最大索引值下一個左開右閉間隙的所有行
臨鍵鎖是Innodb 默認的行鎖算法,只有條件符合上面2種情況纔會對應縮小鎖範圍

鎖什麼時候獲取什麼時候釋放?

Myisam: 開始執行sql 前會獲取所有需要的表鎖,執行完所有整條sql 後統一釋放所有鎖,所以Myisam 引擎不會出現死鎖

Innodb: 在Indb裏鎖必須是針對事務來說的,沒開啓事務的sql 則按自動提交(執行完sql 就提交)處理,在事務中順序獲取對應的鎖,只有在事務提交或者回滾後才統一釋放所有的鎖,所以Innodb 是可能出現死鎖的;

死鎖案例:

#事務A 執行下面的sql 暫未提交
BEGIN;
SET * FROM member WHERE uid=1 FOR UPDATE;  #先鎖住id=1

#事務B 執行面的sql 暫未提交
BEGIN;
SET * FROM member WHERE uid=2 FOR UPDATE;   #鎖住id=2
SET * FROM member WHERE uid=1 FOR UPDATE;   #等待id=1 的鎖

#此時事務A 又執行下面sql 就會出現死鎖
SET * FROM member WHERE uid=2 FOR UPDATE;   #等待id=2 的鎖

Innodb解決死鎖是通過檢測循環依賴實現,一旦檢測到死鎖會選擇影響行數比較少的事務直接回滾後拋出異常,並不會一直阻塞

鎖跟事務的聯繫:
僅在Innodb 中 事務的一致性是需要通過鎖實現,事務處理不好可能出現死鎖,鎖可以解決事務中數據不一致的情況

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