理解MySQL數據庫事務-隔離性

Transaction事務是指一個邏輯單元,執行一系列操做的SQL語句。html

事務中一組的SQL語句,要麼所有執行,要麼所有回退。在Oracle數據庫中有個名字,叫作transaction IDsql

在關係型數據庫中,事務必須ACID的特性。數據庫

  • **原子性,**事務中的操做,要不所有執行,要不都不執行
  • **一致性,**事務完成先後,數據的必須保持一致。
  • **隔離性,**多個用戶併發訪問數據庫時,每個用戶開啓的事務,相互隔離,不被其餘事務的操做所幹擾。
  • **持久性,**事務一旦commit,它對數據庫的改變是持久性的。

目前重點討論隔離性。數據庫一共有四個隔離級別安全

  • 未提交讀(RU,Read Uncommitted)。它能讀到一個事物的中間狀態,不符合業務中安全性的保證,違背 了ACID特性,存在髒讀的問題,基本不會用到,能夠忽略session

  • 提交讀(RC,Read Committed)。顧名思義,事務提交以後,那麼咱們能夠看到。這是一種最廣泛的適用的事務級別。咱們生產環境經常使用的使用級別。併發

  • 可重複讀(RR,Repeatable Read)。是目前被使用得最多的一種級別。其特色是有GAP鎖,目前仍是默認級別,這個級別下會常常發生死鎖,低併發等問題。高併發

  • 可串行化,這種實現方式,其實已是不是多版本了,而是單版本的狀態,由於它全部的實現都是經過鎖來實現的。性能

所以目前數據庫主流經常使用的是RCRR隔離級別。spa

隔離性的實現方式,咱們一般用Read View表示一個事務的可見性。版本控制

RC級別,事務可見性比較高,它能夠看到已提交的事務的全部修改。所以在**提交讀(RC,Read Committed)**隔離級別下,每一次select語句,都會獲取一次Read View,獲得數據庫最新的事務提交狀態。所以對於數據庫,併發性能也最好。

RR級別,則不是。它爲了不幻讀和不可重複讀。保證在一個事務內先後數據讀取的一致。其可見性視圖Read View只有在本身當前事務提交以後,纔會更新。

那如何保證數據的一致性?其核心是經過redo logundo 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) 不可能 不可能 不可能

實驗環節

舉例在隔離級別RRRC下,說明「不可重複讀」問題。

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中的數據。

RC隔離級別的現象

在隔離級別可重複讀(RR,Repeatable Read),不會出現不可重複讀現象,舉例以下:

RR隔離級別的現象

舉例說明「幻讀」的現象。

行鎖能夠防止不一樣事務版本的數據在修改(update)提交時形成數據衝突的問題。可是插入數據如何避免呢?

在RC隔離級別下,其餘事務的插入數據,會出現**幻讀(Phantom Reads)**的現象。

RC幻讀

而在RR隔離級別下,會經過Gap鎖,鎖住其餘事務的insert操做,避免"幻讀"的發生。

RR幻讀GAP

所以,在MySQL事務中,鎖的實現方式與隔離級別有關,如上述實驗所示。在RR隔離級別下,MySQL爲了解決幻讀的問題,已犧牲並行度爲代價,經過Gap鎖來防止數據的寫入。這種鎖,並行度差,衝突多。容易引起死鎖。

目前流行的Row模式能夠避免不少衝突和死鎖問題,所以建議數據庫使用**ROW+RC(Read Committed)**模式隔離級別,很大程度上提升數據庫的讀寫並行度,提升數據庫的性能。

原文出處:https://www.cnblogs.com/zhangshengdong/p/11912229.html

相關文章
相關標籤/搜索