事務
簡單的講就是保證一組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 中 事務的一致性是需要通過鎖實現,事務處理不好可能出現死鎖,鎖可以解決事務中數據不一致的情況