事務隔離 保證一系列操作的完整性

2022-05-23 02:09:08 字數 2888 閱讀 6378

你要給朋友轉100塊錢,而此時你的銀行卡只有100塊錢。

轉賬過程具體到程式裡會有一系列的操作,比如查詢餘額、做加減法、更新餘額等,這些操作必須保證是一體的,不然等程式查完之後,還沒做減法之前,你這100塊錢,完全可以藉著這個時間差再查一次,然後再給另外乙個朋友轉賬,如果銀行這麼整,不就亂了麼?這時就要用到"事務"這個概念了。

事務就是要保證一組資料庫操作,要麼全部成功,要麼全部失敗。

在mysql中,事務支援是在引擎層實現的。

mysql是乙個支援多引擎的系統,並不是所有的引擎都支援事務。比如mysql原生的myisam引擎就不支援事務,這也是myisam被innodb取代的重要原因之一

注意:只有innodb引擎才支援資料庫或表的事務

atomicity、原子性

consistency、一致性

isolation、隔離性

durability,永續性

乙個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。

在事務開始之前和事務結束以後,資料庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續資料庫可以自發性地完成預定的工作

資料庫允許多個併發事務同時對其資料進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致資料的不一致。事務隔離分為不同級別,包括讀未提交(read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和序列化(serializable)

事務處理結束後,對資料的修改就是永久的,即便系統故障也不會丟失

在 mysql 命令列的預設設定下,事務都是自動提交的,即執行 sql 語句後就會馬上執行 commit 操作。因此要顯式地開啟乙個事務務須使用命令 begin 或 start transaction,或者執行命令 set autocommit=0,用來禁止使用當前會話的自動提交。

當資料庫上有多個事務同時執行的時候,就可能出現髒讀(dirty read)、不可重複讀(non-repeatable read)、幻讀(phantom read)的問題,為了解決這些問題,就有了"隔離級別"的概念。

髒讀:在乙個事務處理過程裡讀取了另乙個未提交的事務中的資料

當乙個事務正在多次修改某個資料,而在這個事務中這多次的修改都還未提交,這時乙個併發的事務來訪問該資料,就會造成兩個事務得到的資料不一致

不可重複讀:不可重複讀是指在對於資料庫中的某個資料,乙個事務範圍內多次查詢卻返回了不同的資料值,這是由於在查詢間隔,被另乙個事務修改並提交了。

例如事務t1在讀取某一資料,而事務t2立馬修改了這個資料並且提交事務給資料庫,事務t1再次讀取該資料就得到了不同的結果,傳送了不可重複讀。

不可重複讀和髒讀的區別是,髒讀是某一事務讀取了另乙個事務未提交的髒資料,而不可重複讀則是讀取了前一事務提交的資料

虛讀:幻讀是事務非獨立執行時發生的一種現象。例如事務t1對乙個表中所 有 的行的某個資料項做了從"1"修改為"2"的操作,這時事務t2又對這個表中插入了一行資料項,而這個資料項的數值還是為"1"並且提交給資料庫。而操作事務t1的使用者如果再檢視剛剛修改的資料,會發現還有一行沒有修改,其實這行是從事務t2中新增的,就好像產生幻覺一樣,這就是發生了幻讀。

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

在談隔離級別之前,首先要知道,你隔離得越嚴實,效率就會越低。因此很多時候,我們都要在二者之間尋找乙個平衡點。sql標準的事務隔離級別包括:讀未提交(read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和序列化(serializable )。下面我逐一為你解釋:

讀未提交:乙個事務還沒提交時,它的變更就能被別的事務看到。

讀提交是指,乙個事務提交之後,它做的變更才會被其他事務看到。

可重複讀是指,乙個事務執行過程中看到的資料,總是跟這個事務在啟動時看到的資料是一致的。當然在可重複讀隔離級別下,未提交變更對其他事務也是不可見的。

序列化,顧名思義是對於同一行記錄,"寫"會加"寫鎖","讀"會加"讀鎖"。當現 讀寫鎖衝突的時候,後訪問的事務必須等前乙個事務執行完成,才能繼續執行。

在實現上,資料庫裡面會建立乙個檢視,訪問的時候以檢視的邏輯結果為準。

在"可重複讀"隔離級別下,這個檢視是在事務啟動時建立的,整個事務存在期間都用這個檢視。

在"讀提交"隔離級別下,這個檢視是在每個sql語句開始執行的時候建立的。這裡需要注意的是,"讀未提交"隔離級別下直接返回記錄上的最新值,沒有檢視概念;

"序列化"隔離級別下直接用加鎖的方式來避免並行訪問

在mysql中,實際上每條記錄在更新的時候都會同時記錄一條回滾操作。記錄上的最新值,通過回滾操作,都可以得到前乙個狀態的值。

假設乙個值從1被按順序改成了2、3、4,在回滾日誌裡面就會有類似下面記錄

當前值是4,但是在查詢這條記錄的時候,不同時刻啟動的事務會有不同的read-view。如圖中看到的,在檢視a、b、c裡面,這乙個記錄的值分別是1、2、4,同一條記錄在系統中可以存在多個版本,就是資料庫的多版本併發控制(mvcc)。對於read-view a,要得到1,就必須將當前值依次執行圖中所有的回滾操作得到。

同時你會發現,即使現在有另外乙個事務正在將4改成5,這個事務跟read-view a、b、c對應的事務是不會衝突的

在不需要的時候才刪除。也就是說,系統會判斷,當沒有事務再需要用到這些回滾日誌時,回滾日誌會被刪除。

什麼時候才不需要了呢?就是當系統裡沒有比這個回滾日誌更早的read-view的時候

長事務意味著系統裡面會存在很老的事務檢視。由於這些事務隨時可能訪問資料庫裡面的任何資料,所以這個事務提交之前,資料庫裡面它可能用到的回滾記錄都必須保留,這就會導致大量占用儲存空間

樹狀陣列的一系列操作

1 樹狀陣列求逆序對 include include include using namespace std const int maxn 100010 int n,a maxn b maxn c maxn s maxn int lowbit int x void add int x int get...

SQL JOIN的一系列操作 嘎 嘎 嘎

誰訂購了產品,並且他們訂購了什麼產品?除了我們在上面的例子中使用的 inner join 內連線 我們還可以使用其他幾種連線。下面列出了您可以使用的 join 型別,以及它們之間的差異。right join 關鍵字會右表 table name2 那裡返回所有的行,即使在左表 table name1 ...

string字串的一系列操作

indexof 查詢字串中指定字元或字串首次出現的位置,返首索引值,如 str1.indexof 字 查詢 字 在str1中的索引值 位置 str1.indexof 字串 查詢 字串 的第乙個字元在str1中的索引值 位置 str1.indexof 字 start,end 從str1第start 1...