天天看點

資料庫事務詳解什麼是事務事務特性(ACID特性)事務的隔離級别什麼時候會出現幻讀?如何檢視目前事務的隔離級别如何設定事務的隔離級别送出事務復原事務髒讀虛讀(幻讀)不可重複讀

資料庫事務詳解

  • 什麼是事務
  • 事務特性(ACID特性)
    • 原子性、一緻性、隔離性、持久性
  • 事務的隔離級别
    • Read uncommitted:讀未送出
    • Read committed:讀送出
    • Repeatable read:可重複讀
    • Serializable:序列化
  • 什麼時候會出現幻讀?
  • 如何檢視目前事務的隔離級别
  • 如何設定事務的隔離級别
  • 送出事務
  • 復原事務
  • 髒讀
    • 怎麼解決髒讀?
  • 虛讀(幻讀)
    • 怎麼解決幻讀?
  • 不可重複讀
    • 怎麼解決不可重複讀?

什麼是事務

事務是應用程式中一系列嚴密的操作,所有操作必須成功完成,否則在每個操作中所作的所有更改都會被撤消。也就是事務具有原子性,一個事務中的一系列的操作要麼全部成功,要麼一個都不做。

事務特性(ACID特性)

原子性、一緻性、隔離性、持久性

  • 原子性:整個事務中的所有操作,要麼全部完成,要麼全部不完成,不可能停滞在中間某個環節。事務在執行過程中發生錯誤,會被復原(Rollback)到事務開始前的狀态,就像這個事務從來沒有執行過一樣。
  • 一緻性:在事務開始之前和事務結束以後,資料庫的完整性限制沒有被破壞。
  • 隔離性:隔離狀态執行事務,使它們好像是系統在給定時間内執行的唯一操作。如果有兩個事務,運作在相同的時間内,執行 相同的功能,事務的隔離性将確定每一事務在系統中認為隻有該事務在使用系統。這種屬性有時稱為串行化,為了防止事務操作間的混淆, 必須串行化或序列化請 求,使得在同一時間僅有一個請求用于同一資料。
  • 持久性:在事務完成以後,該事務所對資料庫所作的更改便持久的儲存在資料庫之中(并不會被復原)

事務的隔離級别

資料庫事務的隔離級别有4種,由低到高分别為Read uncommitted 、Read committed 、Repeatable read 、Serializable 。

在事務的并發操作中可能會出現髒讀,不可重複讀,幻讀。

Read uncommitted:讀未送出

Read uncommitted:讀未送出,就是一個事務可以讀取另一個未送出事務的資料。

事例:老闆要給程式員發工資,程式員的工資是3.6萬/月。但是發工資時老闆不小心按錯了數字,按成3.9萬/月,該錢已經打到程式員的戶口,但是事務還沒有送出,就在這時,程式員去檢視自己這個月的工資,發現比往常多了3千元,以為漲工資了非常高興。但是老闆及時發現了不對,馬上復原差點就送出了的事務,将數字改成3.6萬再送出。

分析:實際程式員這個月的工資還是3.6萬,但是程式員看到的是3.9萬。他看到的是老闆還沒送出事務時的資料。這就是髒讀。

Read committed:讀送出

Read committed:讀送出,就是一個事務要等另一個事務送出後才能讀取資料。

事例:程式員拿着信用卡去享受生活(卡裡當然是隻有3.6萬),當他埋單時(程式員事務開啟),收費系統事先檢測到他的卡裡有3.6萬,就在這個時候!!程式員的妻子要把錢全部轉出充當家用,并送出。當收費系統準備扣款時,再檢測卡裡的金額,發現已經沒錢了(第二次檢測金額當然要等待妻子轉出金額事務送出完)。程式員就會很郁悶,明明卡裡是有錢的…

分析:這就是讀送出,若有事務對資料進行更新(UPDATE)操作時,讀操作事務要等待這個更新操作事務送出後才能讀取資料,可以解決髒讀問題。但在這個事例中,出現了一個事務範圍内兩個相同的查詢卻傳回了不同資料,這就是不可重複讀。

Repeatable read:可重複讀

Repeatable read:可重複讀

在可重複讀中,該sql第一次讀取到資料後,就将這些資料加鎖(悲觀鎖),其它事務無法修改這些資料,就可以實作可重複讀了。但這種方法卻無法鎖住insert新增的資料,是以當事務A先前讀取了資料,或者修改了全部資料,事務B還是可以進行insert資料送出,這時事務A就會發現莫名其妙多了一條之前沒有的資料,這就是幻讀,不能通過行鎖來避免。需要Serializable隔離級别 ,讀用讀鎖,寫用寫鎖,讀鎖和寫鎖互斥,這麼做可以有效的避免幻讀、不可重複讀、髒讀等問題,但會極大的降低資料庫的并發能力。

解決了更新丢失、髒讀、不可重複讀、但是還會出現幻讀。

Serializable:序列化

Serializable 是最高的事務隔離級别,在該級别下,事務串行化順序執行,可以避免髒讀、不可重複讀與幻讀。但是這種事務隔離級别效率低下,比較耗資料庫性能,一般不使用。

在MYSQL資料庫中,支援上面四種隔離級别,預設的為Repeatable read(可重複讀);而在Oracle資料庫中,隻支援Serializeble(串行化)級别和Read committed(讀已送出)這兩種級别,其中預設的為Read committed級别。

什麼時候會出現幻讀?

事例:程式員某一天去消費,花了2千元,然後他的妻子去檢視他今天的消費記錄(全表掃描FTS,妻子事務開啟),看到确實是花了2千元,就在這個時候,程式員花了1萬買了一部電腦,即新增INSERT了一條消費記錄,并送出。當妻子列印程式員的消費記錄清單時(妻子事務送出),發現花了1.2萬元,似乎出現了幻覺,這就是幻讀。

如何檢視目前事務的隔離級别

SELECT @@tx_isolation;

如何設定事務的隔離級别

set tx_isolation=‘隔離級别名稱;’

set session transaction isolation level 隔離級别名稱

送出事務

commit:送出事務

檢視事務狀态:select @@autocommit; show variables like ‘%autocommit%’;

1或者ON表示自動送出;0或者OFF表示手動送出:需要commit指令送出事務

設定手動送出:set autocommit=0; set autocommit=OFF;

復原事務

rollback:復原事務

Rollback就是與commit相反,不送出事務,可以了解成撤回的意思

髒讀

髒讀是指在一個事務處理過程裡讀取了另一個未送出的事務中的資料。

當一個事務正在多次修改某個資料,而在這個事務中這多次的修改都還未送出,這時一個并發的事務來通路該資料,就會造成兩個事務得到的資料不一緻

怎麼解決髒讀?

Read committed!讀送出能解決髒讀問題。

虛讀(幻讀)

幻讀是事務非獨立執行時發生的一種現象。例如事務T1對一個表中所有的行的某個資料項做了從“1”修改為“2”的操作,這時事務T2又對這個表中插入了一行資料項,而這個資料項的數值還是為“1”并且送出給資料庫。而操作事務T1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務T2中添加的,就好像産生幻覺一樣,這就是發生了幻讀。

幻讀和不可重複讀都是讀取了另一條已經送出的事務(這點就髒讀不同),所不同的是不可重複讀查詢的都是同一個資料項,而幻讀針對的是一批資料整體(比如資料的個數)

怎麼解決幻讀?

Serializable!序列化

不可重複讀

不可重複讀是指在對于資料庫中的某個資料,一個事務範圍内多次查詢卻傳回了不同的資料值,這是由于在查詢間隔,被另一個事務修改并送出了。

例如事務T1在讀取某一資料,而事務T2立馬修改了這個資料并且送出事務給資料庫,事務T1再次讀取該資料就得到了不同的結果,發送了不可重複讀。

不可重複讀和髒讀的差別是,髒讀是某一事務讀取了另一個事務未送出的髒資料,而不可重複讀則是讀取了前一事務送出的資料。

在某些情況下,不可重複讀并不是問題,比如我們多次查詢某個資料當然以最後查詢得到的結果為主。但在另一些情況下就有可能發生問題,例如對于同一個資料A和B依次查詢就可能不同,A和B就可能打起來了……

怎麼解決不可重複讀?

Repeatable read 重複讀