天天看點

資料庫事務(MySQL)

1、什麼是事務

* 事務(transaction)是一個最小的不可再分的工作單元

* 通常一個事務對應了一個完整的業務

* 而一個完整的業務,需要批量的DML語句(insert、update、delete)共同聯合完成

* 事務隻和DML語句有關系,即DML語句才有事務

典型執行個體: 銀行賬戶轉賬業務

銀行賬戶轉賬業務,該業務就是一個最小的工作單元,不可再分,即該業務是一個事務

t_act 賬戶表

actno balance
act-001 50000.0
act-002 20000.0

執行轉賬操作(10000):

update t_act set balance=40000.0 where actno='act-001';

update t_act set balance=30000.0 where actno='act-002';

以上的兩條DML語句要求必須同時成功或者同時失敗,最小單元,不可再分

當第一條DML語句執行成功之後,并不能将底層資料庫中第一個賬戶的資料修改;隻是将操作記錄了一下,這個記錄是在記憶體中完成的,若第二條DML語句執行成功,和底層資料庫檔案中的資料完成同步;若第二條DML語句執行失敗,清空所有的曆史操作記錄。

要完成以上的功能,必須借助事務

2、事務的四大特性(ACID)

原子性(A):事務是最小的工作單元,不可再分

一緻性(C):事務要求所有的DML語句操作的時候,必須保證同時成功或者同時失敗

隔離性(I):多事務并發執行時,事務之間互不影響

持久性(D):一旦事務送出,對資料的改變就是永久的(記憶體中的資料持久到硬碟檔案中)

3、與事務有關的術語

開始事務:Start Transaction

結束事務:End Transaction

送出事務:Commit Transaction

復原事務:Rollback Transaction

4、事務控制語句

手動開啟事務:begin/start transaction;

建立一個儲存點:savepoint 儲存點名; 

復原:rollback to 儲存點名;  或  rollback;

手動送出:commit;

5、事務開啟的标志與結束的标志

(1)開啟的标志

任何一條DML語句(insert、update、delete)執行,标志事務的開啟

(2)結束的标志

送出或者復原

送出:成功的結束,将所有的DML語句操作曆史記錄和底層硬碟檔案中的資料來一次同步

復原:失敗的結束,将所有的DML語句操作曆史記錄全部清空

6、事務的隔離級别

(1)read uncommitted 讀未送出

* 事務A和事務B,事務A未送出的資料,事務B可以讀取到

* 這裡讀取到的資料叫做"髒資料"或"Dirty Read"

* 這種隔離界别是最低級别,一般都是在理論上存在的,資料庫預設的隔離級别一般高于該隔離級别

(2)read committed 讀已送出

* 事務A和事務B,事務A送出的資料,事務B才能讀取到(對于事務送出之後的資料,目前事務才能讀取到)

* 該隔離級别高于讀未送出,可以避免髒資料,但會導緻"不可重複讀"

(3)repeatable read 可重複讀

* 事務A和事務B,事務A送出之後的資料,事務B讀取不到(對方送出之後的資料目前事務還是讀取不到)

* 事務B是可重複讀取資料

* 該隔離界别高于讀已送出,可避免"髒讀"和"不可重複讀",達到可重複讀取,但會導緻"幻讀"

* MySQL資料庫管理系統預設的隔離級别就是可重複讀

(4)serializable 串行化

* 事務A和事務B,事務A在操作資料庫表中資料的時候,事務B隻能排隊等待(等待隊列)

* 該隔離級别一般很少使用,吞吐量太低,使用者體驗不好

* 可以避免"幻讀",每一次讀取的都是資料庫表中真實的記錄

* 事務A和事務B不再并發

若無事務隔離級别,那麼多個事務在同一時間間隔内對同一事務的操作可能會影響最終的結果,通常會出現以下幾種問題:

(1)髒讀

事務A讀取了事務B還沒有送出的資料

解決辦法:将資料庫隔離級别修改為read committed

(2)不可重複讀

同一事務内,兩次相同的查詢傳回了不同結果

解決辦法:将資料庫隔離級别修改為repeatable read

(3)幻讀

事務A修改全部資料,事務B插入(或删除)資料;操作A事務的使用者在修改結束後發現表中還有未修改的行

解決辦法:将資料庫隔離級别修改為serializable

注:不可重複讀重點是修改;同樣的條件,讀取過的資料,再次讀取發現值不一樣了

       幻讀重點是新增或删除;同樣的條件,第一次和第二次讀出來的記錄數不同

7、隔離級别與一緻性問題的關系

隔離級别 髒讀 不可重複讀 幻讀 加鎖讀
讀未送出 可能 可能 可能 不加鎖
讀已送出 不可能 可能 可能 不加鎖
可重複讀 不可能 不可能 對InnoDB不可能 不加鎖
串行化 不可能 不可能 不可能 加鎖

8、其他 

  • 檢視目前隔離級别
select @@tx_isolation;
  • 設定事務的隔離級别

方式一:修改my.ini配置檔案

[mysqld]

transaction-isolation = READ-COMMITTED

方式二:使用指令方式

設定事務的隔離級别作用于全局

set global transaction isolation level read uncommitted;

設定事務的隔離級别作用于目前會話

set [session] transaction isolation level read uncommitted;

注:在事務進行過程中,未結束之前,DML語句是不會更改底層資料庫檔案中的資料的,隻是将曆史操作記錄一下,在記憶體中完成記錄,隻有在事務結束的時候,而且是成功的結束的時候才會修改底層硬碟檔案中的資料;在MySQL資料庫管理系統中,預設情況下,事務是自動送出的,即隻要執行一條DML語句,開啟了事務,并且送出了事務

關閉自動送出的方式:

第一種:手動開啟事務

第二種:set autocommit=off; 或 set session autocommit=on;

以上打開和關閉自動送出機制隻針對目前會話