資料庫事務 ACID屬性、資料庫併發問題和四種隔離級別

wangruijie發表於2021-03-06

資料庫事務 ACID屬性、資料庫併發問題和四種隔離級別

資料庫事務

資料庫事務是一組邏輯操作單元,使資料從一種狀態變換到另一種狀態

一組邏輯操作單元;一個或多個DML操作

事務處理原則

保證所有事務都作為一個工作單元來執行,即使出現故障,都不能改變這種執行方式。
一個事務執行多次操作時,要麼所有事務都被提交,則永久儲存;要麼放棄所有修改,整個事務回滾到最初狀態

資料一旦提交,則不可回滾

那些操作會導致自動提交

DDL操作一旦執行,都會自動提交
DML預設情況下,一旦執行,就會自動提交
可以通過set autocommit = false的方式取消DML自動提交
預設在關閉連線時,會自動提交資料

ACID屬性

事務必須滿足四個屬性,即原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、永續性(Durability),即ACID四種屬性。

原子性

一個事務是一個不可分割的整體,為了保證事務的總體目標,事務必須具有原子性,即當資料修改時,要麼全都執行,要麼全都不執行。即,不允許事務部分地完成,避免了只執行這些操作的一部分而帶來的錯誤。

一致性

一個事務在執行之前和執行之後,資料庫資料必須保持一致性。資料庫的一致性狀態應該滿足模式鎖指定的約束條件,那麼在完整執行該事務後,資料庫仍然處於一致性狀態。

例如:銀行轉賬,轉賬前後兩個賬戶金額之和應保持不變。

隔離性

由併發事務所作的修改必須與任何其它併發事務所作的修改隔離。事務檢視資料庫時資料所處的狀態,要麼是另一併發事務修改它之前的狀態,要麼是另一事務修改它之後的狀態,事務不會檢視中間狀態的資料。

例如:對任何一對事務T1和T2,對T1而言,T2要麼在T1開始之前已經結束,要麼在T1完成之後再開始執行。

永續性

也被稱為永久性,事務完成以後,DBMS(資料庫管理系統)保證它對資料庫中資料的修改是永久性的,當系統或介質發生故障時,該修改也永久保持。永續性一般通過資料庫備份與恢復來保證。

  • 注意    嚴格而言,資料庫事務屬性都是由資料庫管理系統來進行保證的,在整個應用程式的執行過程中,應用程式無須去考慮資料庫的ACID實現。

一般情況下,通過執行COMMIT(提交)或ROLLBACK(回滾)語句來終止事務。當執行COMMIT語句時,自從事務啟動以來對資料庫所做的一切更改就成為永久性的,即被寫入到磁碟,而當執行ROLLBACK語句時,自從事務啟動以來對資料庫所做的一切更改都會被撤銷,並且資料庫中內容返回到事務開始之前所處的狀態。無論什麼情況,在事務完成時,都能保證回到一致性狀態。

資料庫併發問題

如果沒有鎖定且多個使用者同時訪問一個資料庫,則當他們的事務同時使用相同的資料時可能會發生問題。由於併發操作帶來的資料不一致性包括:丟失資料更新、讀“髒”資料(髒讀)、不可重複讀。

更新丟失

  • 兩個事務都同時更新一行資料,一個事務對資料的更新把另一個事務對資料的更新覆蓋了。這是因為系統沒有執行任何的鎖操作,因此併發並沒有被隔離開來。

髒讀

  • 一個事務讀取到了另一事務未提交的資料操作結果。這是相當危險的,因為很可能所有的操作都被回滾。

不可重複讀

  • 不可重複讀(Non-repeatable Reads):一個事務對同一行資料重複讀取兩次,但是卻得到了不同的結果。

包括以下情況:

  • 虛讀:事務T1讀取某一資料後,事務T2對其做了修改,當事務T1再次讀取該資料時得到與前一次不同的值。
  • 幻讀:事務在操作過程中進行兩次查詢,第二次查詢的結果包含了第一次查詢中未出現的資料或者缺少了第一次查詢中出現的資料。這是因為在兩次查詢過程中有另外一個事務插入資料造成的。

資料庫事務的四種隔離級別

資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted 、Read committed 、Repeatable read 、Serializable ,這四個級別可以逐個解決髒讀 、不可重複讀 、幻讀這幾類問題。
不同的隔離級別對事務的處理不同。

  • 讀未提交資料(Read Uncommitted):只處理更新丟失。如果一個事務已經開始寫資料,則不允許其他事務同時進行寫操作,但允許其他事務讀此行資料。可通過“排他寫鎖”實現。
  • 讀已提交資料(Read Committed):處理更新丟失、髒讀。讀取資料的事務允許其他事務繼續訪問改行資料,但是未提交的寫事務將會禁止其他事務訪問改行。可通過“瞬間共享讀鎖”和“排他寫鎖”實現。
  • 可重複讀取(Repeatable Read):處理更新丟失、髒讀和不可重複讀取。讀取資料的事務將會禁止寫事務,但允許讀事務,寫事務則禁止任何其他事務。可通過“共享讀鎖”和“排他寫鎖”實現。
  • 序列化(序列化)(Serializable):提供嚴格的事務隔離。要求失去序列化執行,事務只能一個接一個地執行,不能併發執行。僅僅通過“行級鎖”是無法實現事務序列化的,必須通過其他機制保證新插入的資料不會被剛執行查詢操作的事務訪問到。

隔離級別越高,越能保證資料的完整性和統一性,但是對併發效能的影響也越大。對於多數應用程式,可以優先考慮把資料庫系統的隔離級別設為Read Committed。它能夠避免髒讀,而且具有較好的併發效能。儘管它會導致不可重複讀、幻讀和第二類丟失更新這些併發問題,在可能出現這類問題的個別場合,可以由應用程式採用悲觀鎖或樂觀鎖來控制。

  • Oracle 支援的 2 種事務隔離級別:READ COMMITED, SERIALIZABLE. Oracle 預設的事務隔離級別為: READ COMMITED
  • Mysql 支援 4 中事務隔離級別. Mysql 預設的事務隔離級別為: REPEATABLE READ

事務隔離級別設定

//檢視當前事物級別:
SELECT @@tx_isolation;
//設定mysql的隔離級別:
//set session transaction isolation level 設定事務隔離級別

//設定read uncommitted級別:
set session transaction isolation level read uncommitted;

//設定read committed級別:
set session transaction isolation level read committed;

//設定repeatable read級別:
set session transaction isolation level repeatable read;

//設定serializable級別:
set session transaction isolation level serializable;

Java程式碼獲取和設定隔離級別(下文conn為Connection 物件,具體實現不做整理)

//獲取資料庫事務隔離級別
int transactionIsolation = conn.getTransactionIsolation();
//設定資料庫事務隔離級別;事務隔離級別:TRANSACTION_READ_COMMITTED
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

相關文章