Transaction事務是指一個邏輯單元,執行一系列操做的SQL語句。html
事務中一組的SQL語句,要麼所有執行,要麼所有回退。在Oracle數據庫中有個名字,叫作transaction IDsql
在關係型數據庫中,事務必須ACID的特性。數據庫
目前重點討論隔離性。數據庫一共有四個隔離級別安全
未提交讀(RU,Read Uncommitted)。它能讀到一個事物的中間狀態,不符合業務中安全性的保證,違背 了ACID特性,存在髒讀的問題,基本不會用到,能夠忽略session
提交讀(RC,Read Committed)。顧名思義,事務提交以後,那麼咱們能夠看到。這是一種最廣泛的適用的事務級別。咱們生產環境經常使用的使用級別。併發
可重複讀(RR,Repeatable Read)。是目前被使用得最多的一種級別。其特色是有GAP鎖,目前仍是默認級別,這個級別下會常常發生死鎖,低併發等問題。高併發
可串行化,這種實現方式,其實已是不是多版本了,而是單版本的狀態,由於它全部的實現都是經過鎖來實現的。性能
所以目前數據庫主流經常使用的是RC
和RR
隔離級別。spa
隔離性的實現方式,咱們一般用Read View表示一個事務的可見性。版本控制
RC級別,事務可見性比較高,它能夠看到已提交的事務的全部修改。所以在**提交讀(RC,Read Committed)**隔離級別下,每一次select語句,都會獲取一次Read View,獲得數據庫最新的事務提交狀態。所以對於數據庫,併發性能也最好。
RR級別,則不是。它爲了不幻讀和不可重複讀。保證在一個事務內先後數據讀取的一致。其可見性視圖Read View只有在本身當前事務提交以後,纔會更新。
那如何保證數據的一致性?其核心是經過redo log和undo log來保證的。
而在數據庫中,爲了實現這種高併發訪問,就須要對數據庫進行多版本控制,經過事務的可見性來保證事務看到本身想看到的那個數據版本(或者是最新的Read View亦或者是老的Read View)。這種技術叫作MVCC
多版本是如何實現的?經過undo日誌來保證。每一次數據庫的修改,undo日誌會存儲以前的修改記錄值。若是事務未提交,會回滾至老版本的數據。其MVCC的核心原理,之後詳談
舉例論證:
## 開啓事務 MariaDB [scott]> begin; Query OK, 0 rows affected (0.000 sec) ##查看當前的數據 MariaDB [scott]> select * from dept; +--------+------------+----------+ | deptno | dname | loc | +--------+------------+----------+ | 10 | ACCOUNTING | beijing | | 20 | RESEARCH | DALLAS | | 30 | SALES | CHICAGO | | 40 | OPERATIONS | beijing | | 50 | security | beijing | | 60 | security | nanchang | +--------+------------+----------+ 6 rows in set (0.001 sec) ##更新數據 MariaDB [scott]> update dept set loc ='beijing' where deptno = 20; Query OK, 1 row affected (0.001 sec) ## 其行記錄| 20 | RESEARCH | DALLAS |已經被放置在undo日誌中,目前最新的記錄被改成'beijing': MariaDB [scott]> select * from dept; +--------+------------+----------+ | deptno | dname | loc | +--------+------------+----------+ | 10 | ACCOUNTING | beijing | | 20 | RESEARCH | beijing | | 30 | SALES | CHICAGO | | 40 | OPERATIONS | beijing | | 50 | security | beijing | | 60 | security | nanchang | +--------+------------+----------+ ##事務不提交,回滾。數據回滾至老版本的數據。 MariaDB [scott]> rollback; Query OK, 0 rows affected (0.004 sec) MariaDB [scott]> select * from dept; +--------+------------+----------+ | deptno | dname | loc | +--------+------------+----------+ | 10 | ACCOUNTING | beijing | | 20 | RESEARCH | DALLAS | | 30 | SALES | CHICAGO | | 40 | OPERATIONS | beijing | | 50 | security | beijing | | 60 | security | nanchang | +--------+------------+----------+ 6 rows in set (0.000 sec)
由於MVCC,讓數據庫有了很強的併發能力。隨着數據庫併發事務處理能力大大加強,從而提升了數據庫系統的事務吞吐量,能夠支持更多的用戶併發訪問。但併發訪問,會出現帶來一系列問題。以下:
數據庫併發帶來的問題 | 概述解釋 |
---|---|
髒讀(Dirty Reads) | 當一個事務A正在訪問數據,而且對數據進行了修改,而這種修改尚未提交到數據庫中,這時,另一個事務B也訪問這同一個數據,如不控制,事務B會讀取這些"髒"數據,並可能作進一步的處理。這種現象被稱爲"髒讀"(Dirty Reads) |
不可重複讀(Non-Repeatable Reads) | 指在一個事務A內,屢次讀同一數據。在這個事務尚未結束時,另一個事務B也訪問該同一數據。那麼,在事務A的兩次讀數據之間,因爲第二個事務B的修改,那麼第一個事務兩次讀到的的數據多是不同的 。出現了"不可重複讀"(Non-Repeatable Reads)的現象 |
幻讀(Phantom Reads) | 指在一個事務A內,按相同的查詢條件從新檢索之前檢索過的數據,同時發現有其餘事務插入了數據,其插入的數據知足事務A的查詢條件。所以查詢出了新的數據,這種現象就稱爲"幻讀"(Phantom Reads) |
隔離級別和上述現象之間的聯繫。
隔離級別有:未提交讀(RU,Read Uncommitted),提交讀(RC,Read Committed),可重複讀(RR,Repeatable Read),可串行化(Serializable)
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
未提交讀(RU,Read Uncommitted) | 可能 | 可能 | 可能 |
提交讀(RC,Read Committed) | 不可能 | 可能 | 可能 |
可重複讀(RR,Repeatable Read) | 不可能 | 不可能 | 可能<br />(間隙鎖解決) |
可串行化(Serializable) | 不可能 | 不可能 | 不可能 |
舉例在隔離級別RR
和RC
下,說明「不可重複讀」問題。
MySQL的默認級別是Repeatable Read
,以下:
MariaDB [(none)]> select @@global.tx_isolation; +-----------------------+ | @@global.tx_isolation | +-----------------------+ | REPEATABLE-READ | +-----------------------+ 1 row in set (0.000 sec)
這裏修改當前會話級別爲Read Committed
MariaDB [scott]> set session transaction isolation level read committed; Query OK, 0 rows affected (0.001 sec) MariaDB [scott]> select @@tx_isolation; +----------------+ | @@tx_isolation | +----------------+ | READ-COMMITTED | +----------------+ 1 row in set (0.000 sec)
在隔離級別已**提交讀(RC,Read Committed)**下,出現了不可重複讀的現象。在事務A中能夠讀取事務B中的數據。
在隔離級別可重複讀(RR,Repeatable Read),不會出現不可重複讀現象,舉例以下:
舉例說明「幻讀」的現象。
行鎖能夠防止不一樣事務版本的數據在修改(update)提交時形成數據衝突的問題。可是插入數據如何避免呢?
在RC隔離級別下,其餘事務的插入數據,會出現**幻讀(Phantom Reads)**的現象。
而在RR隔離級別下,會經過Gap鎖,鎖住其餘事務的insert操做,避免"幻讀"的發生。
所以,在MySQL事務中,鎖的實現方式與隔離級別有關,如上述實驗所示。在RR隔離級別下,MySQL爲了解決幻讀的問題,已犧牲並行度爲代價,經過Gap鎖來防止數據的寫入。這種鎖,並行度差,衝突多。容易引起死鎖。
目前流行的Row模式能夠避免不少衝突和死鎖問題,所以建議數據庫使用**ROW+RC(Read Committed)**模式隔離級別,很大程度上提升數據庫的讀寫並行度,提升數據庫的性能。
原文出處:https://www.cnblogs.com/zhangshengdong/p/11912229.html