數據庫事務的方方面面

事務是關係型數據的一個重要特性,但不多有人能對事務有全面性的瞭解,這篇文章就把事務的方方面面講給你。sql

事務的概念

什麼是事務

數據庫事務(事務)是數據庫管理系統執行過程當中的一個邏輯單位,由一個有限的數據庫操做序列構成。數據庫

併發問題

五種併發問題分別是:併發

  • 第一類丟失更新
  • 第二類丟失更新
  • 髒讀
  • 不可重複讀
  • 幻讀

下面依次舉例講解一下。ide

更新丟失(Lost Update)

一個事務覆蓋另外一個事務已提交的更新數據叫丟失更新。post

第一類丟失更新:性能

時間 draw money事務 deposit money事務
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲10,000
T4 查詢帳戶餘額爲10,000
T5 存入1,000並修改餘額爲11,000
T6 提交事務
T7 取出1,000並修改餘額爲9,000
T8 撤銷事務並回滾餘額爲10,000

最終餘額少了1,000。優化

第二類丟失更新:spa

時間 draw money事務 deposit money事務
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲10,000
T4 查詢帳戶餘額爲10,000
T5 取出1,000並修改餘額爲9,000
T6 提交事務
T7 存入1,000並修改餘額爲11,000
T8 提交事務

最終餘額多了1,000。操作系統

髒讀(Dirty Read)

一個事務讀取到另外一個事務還沒提交的數據叫髒讀。日誌

例如,事務A修改了一行數據,但沒有提交,事務 B讀取了被事務A修改後的數據,以後事務A由於某種緣由Rollback了,那麼事務B讀取的數據就是髒的。

時間 draw money事務 deposit money事務
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲10,000
T4 取出1,000並修改餘額爲9,000
T5 查詢帳戶餘額爲9,000 (髒讀)
T6 撤銷事務並回滾餘額爲10,000
T7 存入1,000並修改餘額爲11,000
T8 提交事務

不可重複讀(NonRepeatable Read)

一個事務前後讀到另外一個事務提交以前的數據和已提交的更新數據。

A和B事務併發執行,A事務查詢數據,而後B事務更新該數據,A再次查詢該數據時,發現該數據變化了。

不可重複讀常常發生在updatedelete操做。

時間 draw money事務 deposit money事務
T1 開始事務
T2 開始事務
T3 查詢帳戶餘額爲10,000
T4 查詢帳戶餘額爲10,000
T5 取出1,000並修改餘額爲9,000
T6 提交事務
T7 查詢帳戶餘額爲9,000
T8 同一個事務兩次查詢查到的結果不一樣

幻讀(Phantom Read)

事務在操做過程當中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的數據或者缺乏了第一次查詢中出現的數據。

例如,A和B事務併發執行,A事務查詢數據,B事務插入或者刪除數據,A事務再次查詢發現結果集中有之前沒有的數據,或者之前有的數據消失了,彷彿出現了幻覺。

幻讀常常發生在insert操做。

時間 draw money事務 deposit money事務
T1 開始事務
T2 開始事務
T3 查詢帳號數爲100,000
T4 註冊新帳號
T5 提交事務
T6 查詢帳號數爲100,001
T7 同一個事務兩次查詢查到的結果不一樣

事務的特性

事務有4個特性,被稱爲ACID,分別是:

  • 持久性 (Durability)
  • 隔離性 (Isolation)
  • 一致性 (Consistency)
  • 原子性 (Atomicity)

原子性

一個事務(transaction)中的全部操做,要麼所有完成,要麼所有不完成,不會結束在中間某個環節。

事務在執行過程當中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務歷來沒有執行過同樣。

一致性

在事務開始以前和事務結束之後,數據庫的完整性沒有被破壞。

即事務先後,數據庫的狀態都知足全部的完整性約束。

隔離性

數據庫容許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性能夠防止多個事務併發執行時因爲交叉執行而致使數據的不一致。

事務隔離分爲不一樣級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)。

持久性

事務處理結束後,對數據的修改就是永久的,即使系統故障也不會丟失。

事務的隔離級別

在介紹事務的隔離性的適合提到了事務的4個隔離級別:

  • 未提交讀(Read Uncommitted)
  • 已提交讀(Read Committed)
  • 可重複讀(Repeatable Read)
  • 可串行化(Serializable)

同時事務的隔離級別也與前面提到的5中併發問題有關。隔離級別越高,越能保證數據的完整性和一致性,可是對併發性能的影響也越大。

隔離級別與併發問題:

隔離級別 髒讀 不可重複讀 幻讀
未提交讀 可能 可能 可能
已提交讀 不可能 可能 可能
可重複讀 不可能 不可能 可能
可串行化 不可能 不可能 不可能

對於多數應用程序,能夠優先考慮把數據庫系統的隔離級別設爲Read Committed。它可以避免更新丟失、髒讀,並且具備較好的併發性能。儘管它會致使不可重複讀、幻讀這些併發問題,在可能出現這類問題的個別場合,能夠由應用程序採用悲觀鎖或樂觀鎖來控制。

MySQL InnoDB 默認隔離級別是可重複讀(Repeatable read) 。Oracle等數據庫默認都是已提交讀(Read Committed),即只能讀取到已經提交的數據。

讀未提交(Read Uncommitted)

讀事務不阻塞其餘讀事務和寫事務,未提交的寫事務阻塞其餘寫事務但不阻塞讀事務。

此隔離級別能夠防止更新丟失,但不能防止髒讀、不可重複讀、幻讀。

讀已提交(Read Committed)

讀事務容許其餘讀事務和寫事務,未提交的寫事務禁止其餘讀事務和寫事務。

讀未提交能夠防止更新丟失、髒讀,但不能防止不可重複讀、幻讀。

可重複讀(Repeatable Read)

以操做同一行數據爲前提,讀事務禁止其餘寫事務但不阻塞讀事務,未提交的寫事務禁止其餘讀事務和寫事務。

此隔離級別能夠防止更新丟失、髒讀、不可重複讀,但不能防止幻讀。

可串行化(Serializable)

提供嚴格的事務隔離,它要求事務序列化執行,事務只能一個接着一個地執行,不能併發執行。

此隔離級別能夠防止更新丟失、髒讀、不可重複讀、幻讀。

若是僅僅經過「行級鎖」是沒法實現事務序列化的,必須經過其餘機制保證新插入的數據不會被剛執行查詢操做的事務訪問到。

事務操做

BEGIN

BEGINSTART TRANSACTION :顯式開啓一個事務。

COMMIT

COMMITCOMMIT WORK : 提交事務,並使已對數據庫進行的全部修改爲爲永久性的。

ROLLBACK

ROLLBACKROLLBACK WORK : 回滾並撤銷正在進行的全部未提交的修改。

SAVEPOINT

SAVEPOINT identifier : SAVEPOINT 容許在事務中建立一個保存點,一個事務中能夠有多個 SAVEPOINT。

RELEASE SAVEPOINT identifier : 刪除一個事務的保存點,當沒有指定的保存點時,執行該語句會拋出一個異常。

ROLLBACK

ROLLBACK : 回滾事務。

ROLLBACK TO identifier : 把事務回滾到保存點。

TRANSACTION

SET TRANSACTION : 設置事務的隔離級別。

InnoDB 存儲引擎提供事務的隔離級別有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE。

AUTOCOMMIT

select @@autocommit : 查看事務自動提交設置。

set autocommit=0 : 設置事務不自動提交。

set autocommit=1 : 設置事務自動提交。

-- 查看事務自動提交設置
select @@autocommit;

-- 設置事務不自動提交
set autocommit=0;

-- 設置事務自動提交
set autocommit=1;
複製代碼

事務日誌

事務的機制實現很大一部依賴事務日誌文件。

事務日誌是一個與數據庫文件分開的文件。它存儲對數據庫進行的全部更改,並所有記錄插入、更新、刪除、提交、回退和數據庫模式變化。事務日誌還稱做前滾日誌或重作日誌。事務日誌是備份和恢復的重要組件。

數據庫鎖

是數據庫事務很重要的一個話題,因爲篇幅緣由,咱們這裏不展開講了,下面我會專門提供一篇文章講解。


Wechat-westcall

相關資源

Wechat-westcall

MySQL系列文章:

相關文章
相關標籤/搜索