MySQL事務與鎖

一、事務與事務特性

在關係型數據庫內,事務是由一個SQL或一組SQL語句組成的邏輯處理單元。也就是說事務就相當於一個盛放SQL的容器,事務中的SQL要麼全部執行成功,要麼所有已經修改的操作都回滾到原來的操作,即一條SQL也不能執行成功。

事務的四大特性(ACID):

  1. 原子性:

    事務作為一個整體被執行,包含在其中的對數據庫的操作要麼全部被執行,要麼都不執行,當在執行過程中出現錯誤,就會回滾到事務開始前的狀態。

  2. 一致性:

    事務的執行結果必須是從一個一致性狀態向另一個一致性狀態的變更。比如,A和B兩人共有100元,那麼不管A轉錢給B,或者B轉錢給A,A+B的金額永遠是100。

  3. 隔離性:

    多個事務並發執行時,一個事務的執行不應影響其他事務的執行。

  4. 持久性:

    一個事務一旦提交,他對數據庫的修改應該永久保存在數據庫中,任何事務或故障都不應導致數據丟失。

二、MySQL事務的3種運行模式

隱式==自動

顯式==手動

  1. 自動提交事務(隱式開啟、隱式提交)

    MySQL默認的事務運行模式,在每條SQL執行完畢之後自動commit提交。

  2. 隱式事務(隱式開啟、顯式提交)

    由於在MySQL中是默認每條SQL都開啟了事務的,並且每條SQL執行完畢之後都會自動提交,這樣的話就只需要將自動提交關閉就可以了。

    # 零時關閉		(關閉當前數據庫連接在從新連接就恢復了)
    set autocommit = 0;
    
    # 永久關閉		(修改配置文件my.cnf)
    autocommit = 0
    
    
  3. 顯示事務(顯示開啟、顯示提交)

    這就是我們手動開啟事務,將SQL語句放在我們手動開啟的事務中。

    start transaction;
    
    SQL語句;
    
    commit;		# 提交、或rollback回滾
    

    當使用了commit或者rollback後事務就結束了,在此進入需要從新開始。

三、數據庫讀現象

在高並發場景下,並發的多個事務去操作同一份數據,而產生的一些奇怪的現象,是數據不安全的一種體現。

  1. 臟讀

    一個事務在對一條數據進行了修改,在這個事務還沒有提交時,另一個事務也讀取了這條數據,如果沒有控制,那麼第二個事務讀到的就是一條臟數據,如果第二個事務還需要對這條數據進行操作,那麼這兩個事務之間就存在依賴關係,這就叫臟讀。總結一句話就是事務A讀取到了事務B已經修改了但未提交的數據。

  2. 不可重複讀

    同一個事務在讀取某個數據後,隔一段時間再次讀取該條數據,在這中間該數據被另一個事務給修改,導致兩次讀取的數據不一致。

  3. 幻讀

    幻讀就是不可重複讀的一種現象,同一個事務使用相同的查詢條件讀取以前檢索的數據,卻查詢到了其他事務插入的符合條件的數據,這種現象叫做幻讀。也就是說事務A讀取到了事務B提交的新增數據。

四、鎖機制

鎖是一種保障數據安全的機制,也就是協調多個進程或線程並發訪問某一資源的機制。

以互斥鎖為例,讓多個並發的任務同一時間只能有一個可以運行,犧牲了效率換來了數據安全。

鎖的優缺點:

  • 優點:保障並發場景下數據的安全。
  • 缺點:降低了效率。

所以在使用鎖的時候應該儘可能的縮小鎖的範圍,也就是鎖住的數據越小越好,並發能力越高。

鎖的分類:

按照粒度分類:行級鎖、表級鎖、頁級鎖。

按照級別分類:共享鎖、排他鎖。

按照使用方式分類:樂觀鎖(我在改數據的時候沒有人在跟我修改同一份數據,也可以說其實它本身並不是一種鎖,因為它是程序角度的一種寫程序的套路,本質來說並沒有加任何鎖)、悲觀鎖(在我的事務裏面,我在改數據的時候我總認為一定有人在跟我搶,悲觀鎖通常使用數據自帶鎖機制實現的)

行級鎖:

行級鎖它分為共享鎖,排他鎖,是MySQL中粒度最細的一種鎖,所以它的並發能力也是最高的。

對於insert、update、delete語句、innodb會自動給涉及的數據加鎖,而且是排他鎖;

對於普通的select語句,innodb不會加任何鎖,需要手動自己加,可以加兩種類型的鎖;

--共享鎖(s):能同時加到鎖和搶到鎖的是多個,保障讀的一致性
select * from 表名 where ... lock in share mode;
--排他鎖(x):同一時間只能有一個能搶到,保障寫數據的安全
select * from 表名 where ... for update;

鎖的使用:例如

1、事務A對id=3的行加了互斥鎖後,其他事務對id=3的行不能加任何鎖(寫不行,但是可以讀)

2、事務A對id=3的行加了共享鎖後,其他事務對id=3的行只能加共享鎖,或者不加鎖(寫不行,但可以讀)

表級鎖:

表級鎖是MySQL中粒度最大的一種鎖,整張表都被加鎖,當然並發能力也是最低的。

lock table 表名 read(write),表名 read(write),.........;

--SQL語句

unlock tables;	-->釋放當前會話持有的任何鎖

頁級鎖:

頁鎖是取於表鎖和行鎖之間的一種鎖,粒度界於表鎖和行鎖之間的,並發能力一般。