事務( Transaction )
事務(Transaction)
事務或是交易
(Transaction
)是指資料庫中邏輯上的一系列操作(operation
),這組操作要就全部成功,要就全部不成功。
start transaction;
或是begin;
:為開啟事務,在這條SQL語句之後的SQL都將處於同一個事務中,這些SQL語句不會立刻執行。commit;
:為提交事務,一旦提交,事務中所有的SQL才會執行。rollback;
:回滾事務,回復在此事務內所有的動作。- 資料庫如果沒有自己去控制事務,預設是一條SQL就處在自己單獨的事務中。
事務的特性(ACID)
原子性(Atomicity)
:一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
- 例如:銀行帳戶存款和取款操作。每次存款或取款操作都應該是原子性的,即要麼全部成功,要麼全部失敗。
- 用戶A要取款300元。在這個操作中,銀行應該首先檢查用戶A的帳戶餘額是否足夠,然後從帳戶餘額上減去取款金額。這個操作是原子性的,要麼成功從用戶A的帳戶中扣除300元,要麼失敗,不會出現只減少部分金額的情況。
一致性(Consistency)
:在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞
。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續資料庫可以自發性地完成預定的工作。簡單來說就是在事務前後,資料必須保持一致
,但在過程中不一定會保持一致性
。
- 例如:A將1000元轉帳至B的帳戶,此事務包含兩個步驟,
- 銀行從A的帳戶中扣除1000元。
- 銀行將1000元存入B的帳戶中。
- 在事務前的A與B的帳戶金額總和一定會和事務後的A與B帳戶內的金額總相同 => 這就是
事務前後,資料必須保持一致
- 但是在各操作時,資料不一致,例如銀行從A的帳戶中扣除1000元這一個操作做完之後,銀行資料庫的金額會處於不一致狀態(少了1000元),等到第二操作(銀行將1000元存入B的帳戶)之後資料庫才會保持一致性的狀態。
隔離性(Isolation)
:資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致資料數據的不一致。事務隔離分為不同級別,包括
- 讀未提交(
Read uncommitted
):允許讀取其他事務尚未提交的資料。因此,可能發生髒讀
、不可重複讀
和幻讀
。 - 讀提交(
Read committed
):只能讀取已經提交的資料。因此,可能發生不可重複讀
和幻讀
,但不會發生髒讀
。 - 可重複讀(
Repeatable read
):在同一個事務中多次讀取相同資料時,保證資料的一致性。因此,可能發生幻讀
,但不會發生髒讀
和不可重複讀
。 - 串行化(
Serializable
):最高的隔離級別,確保並發事務之間的串行執行,避免任何並發問題。因此,不會發生髒讀
、不可重複讀
和幻讀
。
持久性(Durability)
:事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失。
事務隔離性導致的問題:
髒讀
:髒讀發生在一個事務允許讀取另一個事務修改但未提交的資料
時。
- 例如,當一個事務A正在讀取資料並且對資料進行了修改,但這個修改還沒有被提交到資料庫中。此時,另一個事務B可能會讀取到這個未提交的修改,這就是髒讀的情況。
不可重複讀
:在一次事務中,當一行資料獲取兩遍得到不同的結果表示發生了「不可重複讀」。例如,在一個事務A中多次讀取同一筆資料,在事務A還未結束時,另一個事務B也訪問了這個資料,並且修改這個資料並且commit,那麼事務A在多次讀取這筆資料時可能會讀到不同的資料。
不可重複讀
的重點是修改
:同樣的條件,你讀取過的資料,再次讀取出來發現值不一樣了- 例如:
- 在交易A中,使用SELECT語句讀取賬戶餘額為1000元,然後執行其他操作。
- 在交易B中,進行了一次轉賬操作,將賬戶餘額從1000元減少到900元。
- 再次在交易A中,使用相同的SELECT語句讀取賬戶餘額,發現餘額為900元,與之前的餘額不一致。
- 這是因為在兩次讀取之間,資料表中的資料已經被修改
幻讀
:在事務執行過程中,當兩個完全相同的查詢語句執行得到不同的結果集。這種現象稱為「幻讀(phantom read)」。
幻讀
的重點在於新增
或者刪除
:同樣的條件,第1次和第2次讀出來的記錄數目不一幻讀
。- 例如:目前工資為1000的員工有10人。
- 使用
SELECT count(*) FROM employee WHERE salary=1000;
SQL,讀取所有工資為1000的員工。
- 事務A,讀取所有工資為1000的員工,
共讀取到了10條記錄
。 - 這時事務B向employee表插入了一條員工記錄,工資也為1000
- 事務A,使用相同的SQL再次讀取所有工資為1000的員工,此時
共讀取到了11條記錄
。
- 使用
隔離級別 | 髒讀 | 不可重複讀 | 幻影讀 |
---|---|---|---|
未提交讀 | 可能發生 | 可能發生 | 可能發生 |
提交讀 | - | 可能發生 | 可能發生 |
可重複讀 | - | - | 可能發生 |
可序列化 | - | - | - |
一般情況下,大多數資料庫系統的預設隔離級別是可重複讀(Repeatable Read)
。這意味著在同一個事務中,多次讀取相同的資料時,保證資料的一致性
,並且防止不可重複讀取
的情況發生。