mysql事務與鎖基礎

事務基礎理論


  1. 事務即 transaction,是數據庫系統區別於文件系統的重要特性之一。
  2. 在文件系統中,如果我們正在寫文件,但是操作系統突然崩潰了或者斷電了等突發事件,那麼寫的文件數據有可能會丟失,但是數據庫系統通過事務來保證這一點。

事務必要性

1. 假設有兩個用戶,不妨記爲 a 和 b,假設 a 要給 b 轉賬 1000 元,那麼只需要在表中把 a 對應的記錄的相應字段減去 1000,給 b 對應的記錄的相應 字段增加 1000 即可。
2. 但是當我們給 a 對應的記錄減去 1000,但是當執行給 b 對應的記錄增加 1000 的時候,服務器突然出現了一些問題,導致該 SQL 並未順利執行就宕機 了。
3. 如果不啓用事務,那麼結果就是 a 對應的記錄減少了 1000,但是 b 對應的記錄並沒有增加 1000,這是不符合常理的,於是,我們引入了事務機制來保 證它的可靠性。

引入事務的目的

事務 會把數據庫從一種狀態轉換爲另外一種狀態,在事務提交之前可以保證要麼所有提交都保存,要麼所有提交都不保存。從而保證數據的完整性:要麼一起成功,要麼一起失敗。

事務四大特性(ACID)

  1. 事務ACID特性:原子性,一致性,隔離性,持久性
  2. 原子性: 是指數據庫中每個事務都是不可分割的最小單位。只有事務中所有SQL語句執行成功纔算整個事務的成功,事務纔會被提交。如果事務中有SQL執行失敗,那麼整個事務會進行回滾
  3. 一致性: 是指將數據庫狀態從一種轉換爲另一種狀態,不允許出現新舊兩種數據,要麼都是新的數據,要麼都是舊的數據。即:數據的完整性約束沒有被破壞。
  4. 隔離性: 是指一個事務在提交之前對其他事務都是不可見,實現機制通過實現。
  5. 持久性: 是指數據一旦被提交,其結果會被永久保存。即使服務發生宕機,數據也能被恢復。

事務基本語法

  1. MYSQL 命令行操作的默認設置事務是自動提交的。即當我們執行了SQL語句之後會馬上執行commit操作,我們可以設置set autocommit=0禁用當前回話的自動提交。
  2. 還可以使用begin, start transaction來顯示開啓一個事務。
  3. commit在默認設置情況下等價commit work,表示提交事務。
  4. rollback在默認設置下等價於rollback work表示事務回滾。
  5. savepoint xxx表示定義一個保存點,在一個事務當中可以有多個保存點。
  6. release savepoint xxx表示刪除一個保存點,當沒有該保存點執行該語句,會拋出一個異常。
    7.rollback to [savepoint] xxx表示回滾到某個保存點。

事務簡單操作

查詢事務自動提交狀態

--- 查詢事務自動提交狀態
show variables like '%commit%';

修改事務提交方式

--- 全局修改
set global autocommit=0;
show global variables like 'autocommit';
--- 局部修改
set session autocommit=0;
show session variables like 'autocommit';

簡單示例1

session1:用於新增數據

--- 開啓事務
start transaction; 
--- 關閉當前回話自動提交
set session autocommit=0;
insert into `table` (...) values(...);

session2:用於查詢session1未提交數據

select * from `table` where ---條件---;

簡單示例2

session1:用於新增數據並執行提交

--- 開啓事務
start transaction; 
--- 關閉當前回話自動提交
set session autocommit=0;
--- 插入數據
insert into `table` (...) values(...);
--- 提交
commit;

session2:用於查詢session1已提交數據

select * from `table` where ---條件---;

鎖基礎

鎖的概念

  1. 在開發多用戶,數據庫驅動的應用時,比較大的一個難點就是解決併發問題,目前比較常用的方式就是使用鎖。
  2. 鎖機制也是數據庫系統區別於文件系統的一個關鍵特點之一。
  3. MYSQL 不同的存儲引擎使用的策略也有不同,不要混淆。

鎖類型

  1. 相對於其他數據庫而言,MYSQL鎖機制比較簡單,而且不同的存儲引擎支持不同的鎖機制。
  2. MyISAM和Memory存儲引擎使用的是表級鎖。
  3. InnoDB存儲引擎支持行級鎖,也支持表級鎖,默認使用的是行級鎖。
  4. 表級鎖: 直接鎖住一張表,開銷小,加鎖快,不會出現死鎖情況,鎖定粒度比較大,發生鎖衝突的的概率更高。併發程度最低。
  5. 行級鎖:直接鎖住一條記錄開銷大,加鎖慢,發生鎖衝突的概率較低,併發程度高。
  6. 頁級鎖:直接鎖住一個頁面,在InnoDB中一個頁面大小爲16KB,開銷介於表級鎖和行級鎖之間,會出現死鎖情況,鎖定粒度和併發程度介於表級鎖和行級鎖之間。
  7. 僅從鎖的角度來說,表級鎖更加適用於查詢爲主情況,只有少量按照索引條件更新數據的應用,比如大多數web應用。
  8. 行級鎖更適合大量按照索引條件併發更新數據,併發查詢的應用,比如在線事務處理系統。

innoDB鎖

  1. innoDB和MyISAM相當大的兩點不同:支持事務,採用行級鎖
  2. 行級鎖本身與表級鎖實現差別就很大,而且事物的引入也帶來很多問題,尤其事物的隔離性,與鎖的機制息息相關。
  3. 對於事務的基本操作,對於不同的隔離級別可能引發髒讀,幻讀,不可重複讀讀等問題。
  4. 數據庫實現事務隔離的方式,基本上可以分爲兩種:
    (1)在操作數據之前,先對其進行加鎖,防止其他事務對數據進行修改,這就需要各個事務串行化操作纔可實現。
    (2)不加鎖。通過生成一系列特定請求時間點的一致性數據快照,並通過這個快照來進行一致性讀取。
  5. 上面的第二種方式就是數據多版本併發控制,也就是多版本數據庫,一般稱爲MVCC,是 Multi Version Concurrency Control 的縮寫。
  6. 數據庫的事務隔離越嚴格,併發的副作用就越小,當然付出的代價也就越大,因爲事務的隔離機制實質上是使得事務在一定程度上“串行化”這與並行是矛盾的。

innoDB鎖類型

  1. innoDB實現了下面兩種類型的鎖:
    (1)共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同數據集的排它鎖。
    (2)排它鎖(X):允許獲得排它鎖的事務更新數據,阻止其他事務獲得相同數據集的共享讀鎖和排他寫鎖。
  2. innoDB還有兩種意向鎖:這兩種鎖是表鎖,是innoDB內部加的,不用我們外部干預。

SQL語句加鎖

— 排它鎖

---給`table`表加排它鎖 
start transaction; --開啓事務 
select * from `table` where ---條件--- for update;--排它鎖 
commit;--提交事務 
rollback;--回滾事務

— 共享鎖

start transaction;--開啓事務 
select * from `table` where---條件--- lock in share mode;--給id爲1的數據加共享鎖 
commit;--提交事務 
rollback;--回滾事務
當前事務給一行數據 共享鎖,那麼其他事務可以加共享鎖,單不能加排它鎖,即:**能讀不能寫,可以與共享鎖一起使用,但不能與排它鎖一起使用。**

事務生命週期

innoDB事務日誌是指redo log保存在日誌文件ib_logfile中。
innoDB還有另一個undo log,存放在共享表空間裏面的(ibdata*文件中)

事務 重做日誌和回滾日誌

— 查看事務日誌

--- 查看事務日誌
show engine innodb status\G;
--- 查看日誌文件設置狀態
show bariables like 'innodb_%';

innodb_log_files_in_group:DB中設置幾組事務日誌,默認是2; innodb_log_group_home_dir:事務日誌存放目錄,不設置,ib_logfile0…存在在數據文件目錄下 Innodb存儲引擎可將所有數據存放於ibdata*的共享表空間,也可將每張表存放於獨立的.ibd文件的獨立表空間

MYSQL對於數據來說,最重要的是日誌文件

redo log => iblogfile0
undo log => ibdata

重做日誌

持久化

  1. 事務被提交,數據一定會被寫到數據庫中並持久化存儲起來,通常來說當事務已經被提交之後,就無法再次回滾了。
  2. 重做日誌實現持久化。事務的持久性也是通過日誌來實現的,MySQL 使用重做日誌(redo log)實現事務的持久性,重做日誌由兩部分組成,一是內存中的重做日誌緩 衝區,因爲重做日誌緩衝區在內存中,所以它是易失的,另一個就是在磁盤上的重做日誌文件,它是持久的
  3. 在mysql中事務執行commit提交了之後,但是服務器掛了,數據還沒有寫入磁盤,在mysql重啓服務之後會重新執行這個重做日誌寫入數據。

回滾日誌

  1. 原子性。要麼都成功,要麼都失敗。
  2. 回滾日誌實現原子性。想要保證事務的原子性,就需要在異常發生時,對已經執行的操作進行回滾,而在 MySQL 中,恢復機制是通過回滾日誌(undo log)實現的,所有事務進行的 修改都會先記錄到這個回滾日誌中,然後在對數據庫中的對應行進行寫入。 注意:系統發生崩潰、數據庫進程直接被殺死後,當用戶再次啓動數據庫進程時, 還能夠立刻通過查詢回滾日誌將之前未完成的事務進行回滾,這也就需要回滾 日誌必須先於數據持久化到磁盤上,是我們需要先寫日誌後寫數據庫的主要原 因。 在日誌文件中:在事務中使用的每一條 INSERT都對應了一條 DELETE,每一條 UPDATE也都對應一條相反的 UPDATE語句。

到現在爲止我們瞭解了 MySQL 中的兩種日誌,回滾日誌(undo log)和重做日誌(redo log);在數據庫系統中,事務的原子性和持久性是由事務日誌 (transaction log)保證的,在實現時也就是上面提到的兩種日誌,前者用於對事務的影響進行撤銷,後者在錯誤處理時對已經提交的事務進行重做,它們能保 證兩點:

  1. 發生錯誤或者需要回滾的事務能夠成功回滾(原子性);
  2. 在事務提交後,數據沒來得及寫入磁盤就宕機時,在下次重新啓動後能夠成功恢復數據(持久性); 在數據庫中,這兩種日誌經常都是一起工作的,我們 可以將它們整體看做一條事務日誌,其中包含了事務的 ID、修改的行元素以及修改前後的值。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章