91网首页-91网页版-91网在线观看-91网站免费观看-91网站永久视频-91网站在线播放

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

MySQL插入是并發(fā)還是串行?

admin
2025年5月5日 23:37 本文熱度 74

最近和同事爭辯起來,MySQL插入是并發(fā)還是串行,我記得明明是串行插入,同事非要和我杠,說MySQL可以并發(fā)插入。

我要親自試驗一下,打他的臉!

定義表結構

MySQL 實驗版本 8.0,首先定義 用戶信息表userInfo,其中id為自增,name具有唯一索引。

驗證流程

默認情況下,在命令行中 MySQL會自動提交,每個SQL執(zhí)行會非???,無法驗證同時執(zhí)行的兩個事務之間是否存在阻塞情況,所以需要顯示開啟事務和提交事務 。

開始驗證

首先,我們開啟兩個事務。在事務1中,首先插入一條記錄,暫時不提交。然后,在事務2中開啟一個新的事務,并插入一條自增記錄。

如果MySQL的innodb插入是串行的,那么此時事務2的插入記錄將會被阻塞。如果沒有被阻塞,那就說明MySQL的innodb插入是并發(fā)執(zhí)行的。

時間序號
事務1
事務2
1
開啟事務 START TRANSACTION;

2
主鍵自增插入記錄(ID=1)

3

開啟事務 START TRANSACTION;
4

主鍵自增插入記錄(ID=2)
5

提交事務Commit
6
查詢當前用戶列表,居然有ID=2的記錄

7
提交事務Commit


實驗驗證

事務2 的執(zhí)行記錄 

如上圖所示,在事務1還未提交,事務2在事務1的間隙中插入一條記錄,插入操作立即成功,并且事務2的自增主鍵ID為2。這說明在MySQL中,當一個事務正在插入記錄時,并不會阻塞其他事務的插入。

在MySQL中,多個事務之間的插入操作是并發(fā)進行的,而不是串行進行的。

我感覺自己的臉熱熱的,小丑竟是我自己,趕緊給同事認了錯……

我的認知一直是錯誤的。

但是在底層存儲層面,MySQL會對數(shù)據(jù)頁加鎖。如果兩條記錄在同一個數(shù)據(jù)頁,實際寫入是串行的,但是事務層面是并發(fā)的。

想象一下,庫存扣減和新增庫存流水在同一個事務中,如果新增庫存流水是串行的,那將極大的降低庫存事務的并發(fā)度啊。

本以為驗證結束,打卡下班,結果發(fā)現(xiàn) MySQL插入似乎存在幻讀問題!

從下圖中可以觀察到,事務1在插入時似乎確實出現(xiàn)了幻讀問題!

事務 1 的執(zhí)行記錄顯示,事務1先于事務2開啟,但是事務1期間可以查詢到事務2提交的記錄。這說明有幻讀問題! 

為什么出現(xiàn)幻讀?

所謂幻讀,是指在一個事務讀取記錄時,另一個事務在此時插入或刪除了一條記錄,導致第一個事務再次讀取時發(fā)現(xiàn)記錄的數(shù)量發(fā)生了變化。

要想理解出現(xiàn)幻讀的原因,需要先了解MySQL是如何解決幻讀問題的。

為了解決幻讀問題,MySQL采用了間隙鎖和多版本并發(fā)控制(MVCC)的方法。間隙鎖會鎖定一段記錄的范圍,其他事務無法對這些記錄進行更新或刪除操作。這樣,當當前事務再次進行查詢時,就不會出現(xiàn)記錄數(shù)量的新增或減少的情況了。

MySQL 插入時加了什么鎖?

MySQL 插入時存在幻讀問題,說明MySQL 并沒有加間隙鎖,主要考慮也是為了提高插入時并發(fā)度,如果添加間隙鎖,勢必導致插入并發(fā)度降低!MySQL 在插入之前會申請 插入意向鎖,而記錄本身不沖突(無唯一鍵沖突)插入意向鎖就不會沖突。

MySQL 文檔中記錄了 插入意向鎖

插入意向鎖(insert intention lock)是一種由插入操作在插入行之前設置的鎖定類型。這種鎖定方式表示插入的意圖,使得在相同索引間隙上進行插入的多個事務在插入位置不沖突的情況下不需要互相等待。假設索引記錄中存在值為4和7的記錄。分別嘗試插入值為5和6的兩個不同事務,在獲得插入行的排他鎖之前,它們會先使用插入意向鎖鎖定位于4和7之間的間隙,并且由于插入行不沖突,它們不會互相阻塞。

插入場景MVCC 不生效?

除更新場景外,查詢場景也有幻讀的困惱。如果第一次查詢時只有3條記錄,再次查詢則變?yōu)?條,實在過于奇幻。

如果給普通的查詢語句添加間隙鎖,勢必極大的降低MySQL 的并發(fā)度,如果不能使用間隙鎖,還有哪些辦法解決幻讀呢?

MySQL 通過引入MVCC解決查詢場景的幻讀問題。MVCC是多版本并發(fā)控制(Multiversion Concurrency Control)的縮寫,在MVCC中,每個事務可以看到數(shù)據(jù)庫的一個穩(wěn)定的快照,而不會被其他并發(fā)事務的修改所干擾。當一個事務修改數(shù)據(jù)庫時,它會創(chuàng)建一個新的數(shù)據(jù)版本,而不是直接在原始數(shù)據(jù)上進行修改。而其他事務仍然可以讀取原始數(shù)據(jù)的舊版本或者已經(jīng)提交的新版本,這樣就避免了讀取到未提交的數(shù)據(jù)或者被其他事務的寫操作所阻塞。

MVCC的實現(xiàn)通常涉及對每個數(shù)據(jù)行或數(shù)據(jù)塊分配一個唯一的標識符,稱為"事務ID"。每個事務也有自己的唯一ID。當一個事務讀取數(shù)據(jù)時,系統(tǒng)會檢查該數(shù)據(jù)的事務ID與事務的ID是否兼容,以確定是否允許讀取。如果事務的ID大于數(shù)據(jù)的事務ID,那么說明數(shù)據(jù)是過期的,事務將無法讀取。這種機制保證了事務在讀取數(shù)據(jù)時的隔離性和一致性。

轉機出現(xiàn)了

當我在苦苦思考,為什么MVCC 沒有生效時,我隨手重新測試發(fā)現(xiàn),如果在 insert語句之前,使用select 查詢一下,就不會出現(xiàn)幻讀問題。

操作順序如下

我在事務1,開啟事務以后,新增了select 語句查詢,而后第六步,就不會再有幻讀問題……

這真的實在太奇幻了。一波三折……

由此可見 MySQL 插入并沒有幻讀問題,只是我的打開方式不對。我應該先 select一下 ……,終究還是我錯了,但是我想問為什么?我為什么錯了?

ReadView 是關鍵!

除MVCC 外,MySQL InnoDB 引擎設計了 ReadView(可讀視圖) 的概念。

ReadView 判斷記錄的可見性,ReadView 實際上是當前系統(tǒng)中所有活躍事務的列表,主要包含以下組成部分:

m_ids:在生成 ReadView 時當前系統(tǒng)中活躍的事務 ID 列表;

min_trx_id:在生成 ReadView 時當前系統(tǒng)中活躍的事務中最小的事務 ID,也就是 m_ids 中的最小值;

max_trx_id:在生成 ReadView 時系統(tǒng)中應該分配給下一個事務的 ID 值;

creator_trx_id:生成 ReadView 的事務對應的事務 ID,也就是當前事務 ID。 有了這個 ReadView 之后,在訪問某條記錄時,只需要按照下邊的步驟判斷該記錄的某個版本是否可見:

  1. 如果被訪問版本的 trx_id 屬性值與 ReadView 中的 creator_trx_id 值相同,意味著當前事務在訪問它自己修改過的記錄,所以該版本記錄可以被當前事務訪問。

  2. 如果被訪問版本的 trx_id 屬性值小于 ReadView 中的 min_trx_id 值,表明生成該版本的事務在當前事務生成 ReadView 前已經(jīng)提交,所以該版本記錄可以被當前事務訪問。

  3. 如果被訪問版本的 trx_id 屬性值大于或等于 ReadView 中的 max_trx_id 值,表明生成該版本的事務在當前事務生成 ReadView 后才開啟,所以該版本記錄不可以被當前事務訪問。

  4. 如果被訪問版本的 trx_id 屬性值在 ReadView 的 min_trx_id 和 max_trx_id 之間,那就需要判斷一下 trx_id 屬性值是不是在 m_ids 列表中,如果在,說明創(chuàng)建 ReadView 時生成該版本的事務還是活躍的,該版本不可以被訪問;如果不在,說明創(chuàng)建 ReadView 時生成該版本的事務已經(jīng)被提交,該版本記錄可以被訪問。 如果某個版本的記錄對當前事務不可見的話,那就順著版本鏈找到下一個版本的數(shù)據(jù),繼續(xù)按照上邊的步驟判斷可見性,依此類推,直到版本鏈中的最后一個版本。如果最后一個版本也不可見的話,那么就意味著該條記錄對該事務完全不可見,查詢結果就不包含該記錄。

總結一下就是: 如果當前事務id的生成時間發(fā)生在 記錄的更新之后,那么當前事務就可以看見這個記錄,否則看不見!避免幻讀問題

那 ReadView 又是何時生成的呢?

在 REPEATABLE READ 隔離級別下,每個事務執(zhí)行第一個 SELECT 語句時,會將當前系統(tǒng)中的所有的活躍事務拷貝到一個列表生成 ReadView,后續(xù)所有的 SELECT 都是復用這個 ReadView。

REPEATABLE READ 隔離級別下,只有第一次 SELECT 才會生成 ReadView,后續(xù) SELECT 都會復用這個 ReadView,也就不存在新提交事務對這個 ReadView 的影響了。

所以 當我在 事務 1 新增select語句,會生成一個ReadView,這個ReadView 生成時間要早于 事務2的時間,所以事務1 的后續(xù)所有查詢都不會看到事務2的記錄,從而避免幻讀問題發(fā)生。


總結

  1. MySQL innodb 插入記錄是并發(fā)的。
  2. MySQL innodb 插入記錄不存在幻讀問題,MySQL 通過 mvcc+ ReadView解決幻讀問題。


閱讀原文:原文鏈接


該文章在 2025/5/6 11:43:46 編輯過
關鍵字查詢
相關文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調度、堆場、車隊、財務費用、相關報表等業(yè)務管理,結合碼頭的業(yè)務特點,圍繞調度、堆場作業(yè)而開發(fā)的。集技術的先進性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

主站蜘蛛池模板: 青青草色导航 | 亲子乱子伦xxxx | 国产欧洲精品在线 | 九九热这里只 | 精品国产亚洲精品 | 日本欧美国产婷婷 | 日本高清天码一区 | 欧美日韩亚洲一区 | 国产中文另类二区 | 国产精品剧情在线 | 国产精品又粗又大 | 国内性色精品视频 | 国产一区二区在 | 国产精品毛 | 中文字幕日韩国产 | 欧美在线观看一区 | 国产亚洲视 | 韩国日本免费不 | 日本亚洲精品午夜 | 最新国产人妖ts视频 | 日本成人午夜 | 国产午夜艹逼 | 日本中文字幕乱码 | 91福利片| 欧美中文字幕无线 | 国产不卡牛在线观看 | 区三区夜色 | 3D成人免费网站 | 国产免费艾 | 日韩伦理剧在线观看 | 成人影院一区二区 | 无码精品尤物一区二区三区 | 精品理论片a约人 | 日韩在线一区卜 | 国产不卡一二三 | 国产综合网 | 91福利电影 | 国产白虎不卡在线 | 黑人大战亚洲 | 国产精品性 | 国产日韩高 |