搜尋
首頁資料庫mysql教程MySQL的交易隔離等級實例教程

MySQL的交易隔離等級實例教程

Jun 20, 2017 pm 03:54 PM
mysql事務等級隔離

本文實驗的測試環境:Windows 10+cmd+MySQL5.6.36+InnoDB

一、事務的基本要素(ACID)

#  


1、原子性(Atomicity):事務開始後所有操作,要嘛全部做完,要嘛全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。

   

##2、一致性(Consistency):事務開始前和結束後,資料庫的完整性約束並沒有被破壞。例如A向B轉賬,不可能A扣了錢,B卻沒收到。

#   3、隔離(Isolation):同一時間,只允許一個交易請求同一數據,不同的事務之間彼此沒有任何干擾。例如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉帳。

   4、持久性(Durability):交易完成後,交易對資料庫的所有更新將被儲存到資料庫,不能回滾。   小結:原子性是事務隔離的基礎,隔離性和持久性是手段,最終目的是為了保持數據的一致性。

 

#二、交易的並發問題#################################################### ##########  1、髒讀:事務A讀取了事務B更新的數據,然後B回滾操作,那麼A讀取到的數據是髒數據######## ######################  2、不可重複讀取:事務A 多次讀取同一數據,事務B 在事務A多次讀取的過程中,對資料作了更新並提交,導致事務A多次讀取相同資料時,結果不一致。 ##############################  3、幻讀:系統管理員A將資料庫中所有學生的成績從特定分數改為ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。 ##############################  小結:不可重複讀取的和幻讀很容易混淆,不可重複讀取側重於## #修改###,幻讀著重於###新增或刪除###。解決不可重複讀取的問題只需###鎖定滿足條件的行###,解決幻讀需要###鎖定表################### # #########三、MySQL交易隔離等級#######讀取未提交(read-uncommitted)是是#無法重複讀取(read- committed)否是##可重複讀取(repeatable-read)
交易隔離等級 髒讀 無法重複讀取
#幻讀
######################否##################################################### #####是################################################################### #####否############否###############

 

 

 

 

mysql預設的交易隔離等級為repeatable-read

四、用範例說明各個隔離等級的情況

  1、讀取未提交:

    (1)開啟一個客戶端A,並設定目前交易模式為read uncommitted(未提交讀取),查詢表account的初始值:

 

    (2)在客戶端A的交易提交之前,開啟另一個客戶端B,更新表account:

 

 

    (3)這時,雖然客戶端B的事務還沒提交,但是客戶端A就可以查詢到B已經更新的資料:

 

# (4)一旦客戶端B的事務因為某些原因回滾,所有的操作都會被撤銷,那麼客戶端A查詢到的資料其實就是髒資料:

 

     (5)在客戶端A執行更新語句update account set balance = balance - 50 where id =1,lilei的balance沒有變成350,居然是400,是不是很奇怪,資料的一致性沒問啊,如果你這麼想就太天真了,在應用程式中,我們會用400-50=350,並不知道其他會話回滾了,要想解決這個問題可以採用讀已提交的隔離級別

 

  2、讀取已提交

    (1)開啟一個客戶端A,並設定目前事務模式為read committed(未提交讀取),查詢表account的初始值:

 

    (2)在客戶端A的交易提交之前,打開另一個客戶端B,更新表account:

 

    (3)這時,客戶端B的事務還沒提交,客戶端A不能查詢到B已經更新的數據,解決了髒讀問題:

 

    (4)客戶端B的交易提交

    (5)客戶端A執行與上一步相同的查詢,結果與上一步不一致,即產生了不可重複讀取的問題,在應用程式中,假設我們處於客戶端A的會話,查詢到lilei的balance為450,但是其他事務將lilei的balance值改為400,我們並不知道,如果用450這個值去做其他操作,是有問題的,不過這個概率真的很小哦,要想避免這個問題,可以採用可重複讀的隔離級別

 

   3、可重複讀取

     (1)開啟一個客戶端A,並設定目前事務模式為repeatable read ,查詢表account的初始值:

    (2)在客戶端A的交易提交之前,打開另一個客戶端B,更新表account並提交,客戶端B的事務居然可以修改客戶端A事務查詢到的行,也就是mysql的可重複讀不會鎖住事務查詢到的行,這一點出乎我的意料,sql標準中事務隔離級別為可重複讀取時,讀寫操作要鎖行的,mysql居然沒有鎖,我了個去。在應用程式中要注意為行加鎖,不然你會以步驟(1)中lilei的balance為400作為中間值去做其他操作

(3)在客戶端A執行步驟(1)的查詢:

    (4)執行步驟(1),lilei的balance仍然是400與步驟(1)查詢結果一致,沒有出現不可重複讀取的問題;接著執行update balance = balance - 50 where id = 1,balance沒有變成400-50=350,lilei的balance值用的是步驟(2)中的350來算的,所以是300,數據的一致性倒是沒有被破壞,這個有點神奇,也許是mysql的特色吧

mysql> select * from account;+------+--------+---------+| id   | name   | balance |+------+--------+---------+|    1 | lilei  |     400 ||    2 | hanmei |   16000 ||    3 | lucy   |    2400 |+------+--------+---------+3 rows in set (0.00 sec)

mysql> update account set balance = balance - 50 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> select * from account;+------+--------+---------+| id   | name   | balance |+------+--------+---------+|    1 | lilei  |     300 ||    2 | hanmei |   16000 ||    3 | lucy   |    2400 |+------+--------+---------+3 rows in set (0.00 sec)

    (5) 在客戶端A開啟事務,查詢表account的初始值

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;+------+--------+---------+| id | name | balance |+------+--------+---------+| 1 | lilei | 300 || 2 | hanmei | 16000 || 3 | lucy | 2400 |+------+--------+---------+3 rows in set (0.00 sec)

    (6)在客戶端B開啟事務,新增一條數據,其中balance字段值為600,並提交

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values(4,'lily',600);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

#    (7) 在客戶端A計算balance之和,值為300+16000+2400=18700,沒有把客戶端B的值算進去,客戶端A提交後再計算balance之和,居然變成了19300,這是因為把客戶端B的600算進去了

,站在客戶的角度,客戶是看不到客戶端B的,它會覺得是天下掉餡餅了,多了600塊,這就是幻讀,站在開發者的角度,資料的一致性並沒有破壞。但在應用程式中,我們得程式碼可能會把18700提交給使用者了,如果你一定要避免這情況小機率狀況的發生,那麼就要採取下面要介紹的事務隔離等級「串列化」

mysql> select sum(balance) from account;
+--------------+
| sum(balance) |
+-- ------------+
|        18700 |
+--------------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select sum(balance) from account;
#+-------- ------+
| sum(balance) |
+--------------+
|        19300 |
+----- ---------+
1 row in set (0.00 sec)

  

  4.串列化

    (1)開啟一個客戶端A,並設定目前事務模式為serializable,查詢表account的初始值:

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;+------+--------+---------+| id   | name   | balance |+------+--------+---------+|    1 | lilei  |   10000 ||    2 | hanmei |   10000 ||    3 | lucy   |   10000 ||    4 | lily   |   10000 |+------+--------+---------+4 rows in set (0.00 sec)

    (2)開啟一個客戶端B,並設定目前事務模式為serializable ,插入一條記錄報錯,表被鎖了插入失敗,mysql中事務隔離級別為serializable時會鎖表,因此不會出現幻讀的情況,這種隔離級別並發性極低,往往一個事務霸占了一張表,其他成千上萬個事務只有乾瞪眼,得等他用完提交才可以使用,開發中很少會用到。

mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account values(5,'tom',0);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
#

 

 

 

  補充:

##  1、SQL規格所規定的標準,不同的資料庫具體的實作可能會有些差異

##  2 、mysql中預設交易隔離等級是可重複讀取時並不會鎖定讀取到的行

#  3、交易隔離層級為串列化時,讀取資料會鎖住整張表

#  4、閱讀此文時,若站在開發者的角度,也許會覺得不可重複讀和幻讀,在邏輯上並沒有什麼問題,最終數據仍然是一致的,但是站在用戶的角度,他們通常只能看到一個事務(只能看到客戶端A,不知道客戶端B這個臥底的存在),而不會考慮事務並發執行的現象,一旦出現同一數據多次讀取結果不同,或者憑空出現新記錄,他們可能會產生疑慮,這是使用者體驗的問題。

  5.當事務在mysql中執行時,最終的結果不會出現資料的一致性的問題,因為在一個事務中,mysql執行某個操作未必會使用前一個操作的中間結果,它會根據其他並發事務的實際情況採來處理,看起來不合邏輯,但是保證了數據的一致性;但是事務在應用程序中執行時,一個操作的結果會被下一個操作用到,並進行其他的計算。這是我們得小心,可重複讀取的時候應該鎖行,串列化時 要鎖表,不然會破壞資料的一致性。

##################  6、事務在mysql中執行時,mysql會根據各個事務的實際情況綜合處理,導致資料的一致性沒有被破壞,但是應用程式時按照邏輯套路來出牌,並沒有mysql聰明,難免會出現數據的一致性問題。 ########################  7###、隔離等級越高,越能保證資料的完整性和一致性,但是對並發效能的影響也越大,魚和熊掌不可兼得啊。對於多數應用程序,可以優先考慮將資料庫系統的隔離等級設為Read Committed,它能夠避免髒讀取,而且具有較好的並發性能。儘管它會導致不可重複讀、幻讀這些並發問題,在可能出現這類問題的個別場合,可以由應用程式採用悲觀鎖或樂觀鎖來控制。 ################

以上是MySQL的交易隔離等級實例教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何使用MySQL的函數進行數據處理和計算如何使用MySQL的函數進行數據處理和計算Apr 29, 2025 pm 04:21 PM

MySQL函數可用於數據處理和計算。 1.基本用法包括字符串處理、日期計算和數學運算。 2.高級用法涉及結合多個函數實現複雜操作。 3.性能優化需避免在WHERE子句中使用函數,並使用GROUPBY和臨時表。

MySQL批量插入數據的高效方法MySQL批量插入數據的高效方法Apr 29, 2025 pm 04:18 PM

MySQL批量插入数据的高效方法包括:1.使用INSERTINTO...VALUES语法,2.利用LOADDATAINFILE命令,3.使用事务处理,4.调整批量大小,5.禁用索引,6.使用INSERTIGNORE或INSERT...ONDUPLICATEKEYUPDATE,这些方法能显著提升数据库操作效率。

給MySQL表添加和刪除字段的操作步驟給MySQL表添加和刪除字段的操作步驟Apr 29, 2025 pm 04:15 PM

在MySQL中,添加字段使用ALTERTABLEtable_nameADDCOLUMNnew_columnVARCHAR(255)AFTERexisting_column,刪除字段使用ALTERTABLEtable_nameDROPCOLUMNcolumn_to_drop。添加字段時,需指定位置以優化查詢性能和數據結構;刪除字段前需確認操作不可逆;使用在線DDL、備份數據、測試環境和低負載時間段修改表結構是性能優化和最佳實踐。

如何分析MySQL查詢的執行計劃如何分析MySQL查詢的執行計劃Apr 29, 2025 pm 04:12 PM

使用EXPLAIN命令可以分析MySQL查詢的執行計劃。 1.EXPLAIN命令顯示查詢的執行計劃,幫助找出性能瓶頸。 2.執行計劃包括id、select_type、table、type、possible_keys、key、key_len、ref、rows和Extra等字段。 3.根據執行計劃,可以通過添加索引、避免全表掃描、優化JOIN操作和使用覆蓋索引來優化查詢。

如何使用MySQL的子查詢提高查詢效率如何使用MySQL的子查詢提高查詢效率Apr 29, 2025 pm 04:09 PM

子查詢可以提升MySQL查詢效率。 1)子查詢簡化複雜查詢邏輯,如篩選數據和計算聚合值。 2)MySQL優化器可能將子查詢轉換為JOIN操作以提高性能。 3)使用EXISTS代替IN可避免多行返回錯誤。 4)優化策略包括避免相關子查詢、使用EXISTS、索引優化和避免子查詢嵌套。

MySQL的字符集和排序規則如何配置MySQL的字符集和排序規則如何配置Apr 29, 2025 pm 04:06 PM

在MySQL中配置字符集和排序規則的方法包括:1.設置服務器級別的字符集和排序規則:SETNAMES'utf8';SETCHARACTERSETutf8;SETCOLLATION_CONNECTION='utf8_general_ci';2.創建使用特定字符集和排序規則的數據庫:CREATEDATABASEexample_dbCHARACTERSETutf8COLLATEutf8_general_ci;3.創建表時指定字符集和排序規則:CREATETABLEexample_table(idINT

怎樣卸載MySQL並清理殘留文件怎樣卸載MySQL並清理殘留文件Apr 29, 2025 pm 04:03 PM

要安全、徹底地卸載MySQL並清理所有殘留文件,需遵循以下步驟:1.停止MySQL服務;2.卸載MySQL軟件包;3.清理配置文件和數據目錄;4.驗證卸載是否徹底。

如何在MySQL中重命名數據庫如何在MySQL中重命名數據庫Apr 29, 2025 pm 04:00 PM

MySQL中重命名數據庫需要通過間接方法實現。步驟如下:1.創建新數據庫;2.使用mysqldump導出舊數據庫;3.將數據導入新數據庫;4.刪除舊數據庫。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具