本篇內(nèi)容主要講解“MySQL幻讀指的是什么”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“mysql幻讀指的是什么”吧!
創(chuàng)新互聯(lián)專注于和碩網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供和碩營銷型網(wǎng)站建設(shè),和碩網(wǎng)站制作、和碩網(wǎng)頁設(shè)計(jì)、和碩網(wǎng)站官網(wǎng)定制、成都小程序開發(fā)服務(wù),打造和碩網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供和碩網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
在mysql中,幻讀指當(dāng)用戶讀取某一范圍的數(shù)據(jù)行時(shí),另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行,當(dāng)用戶再讀取該范圍的數(shù)據(jù)行時(shí),會發(fā)現(xiàn)有新的“幻影”行。所謂的幻讀,就是通過SELECT查詢出來的數(shù)據(jù)集并不是真實(shí)存在的數(shù)據(jù)集,用戶通過SELECT語句查詢出某條記錄是不存在的,但是它有可能在真實(shí)的表中是存在的。
先來看看事務(wù)的隔離級別
然后,談幻讀之前,我先說說我對幻讀的理解:
所謂幻讀,重點(diǎn)在于“幻”這個(gè)詞,很夢幻,很玄乎,真假不定,就像蒙上了一層霧一樣,你不能真真切切的看到對方,給人以幻的感覺,這便是“幻”。而所謂的幻讀,也就是你通過SELECT查詢出來的數(shù)據(jù)集并不是真實(shí)存在的數(shù)據(jù)集,你通過SELECT語句查詢出某條記錄是不存在的,但是它有可能在真實(shí)的表中是存在的。
我是這么理解幻讀與不可重復(fù)讀的:
幻讀
說的是存不存在的問題:原來不存在的,現(xiàn)在存在了,則是幻讀
不可重復(fù)讀
說的是變沒變化的問題:原來是A,現(xiàn)在卻變?yōu)榱薆,則為不可重復(fù)讀
幻讀,目前我了解的有兩種說法:
說法一:事務(wù) A 根據(jù)條件查詢得到了 N 條數(shù)據(jù),但此時(shí)事務(wù) B 刪除或者增加了 M 條符合事務(wù) A 查詢條件的數(shù)據(jù),這樣當(dāng)事務(wù) A 再次進(jìn)行查詢的時(shí)候真實(shí)的數(shù)據(jù)集已經(jīng)發(fā)生了變化,但是A卻查詢不出來這種變化,因此產(chǎn)生了幻讀。
這一種說法強(qiáng)調(diào)幻讀在于某一個(gè)范圍內(nèi)的數(shù)據(jù)行變多或者是變少了,側(cè)重說明的是數(shù)據(jù)集不一樣導(dǎo)致了產(chǎn)生了幻讀。
說法二:幻讀并不是說兩次讀取獲取的結(jié)果集不同,幻讀側(cè)重的方面是某一次的 select 操作得到的結(jié)果所表征的數(shù)據(jù)狀態(tài)無法支撐后續(xù)的業(yè)務(wù)操作。更為具體一些:A事務(wù)select 某記錄是否存在,結(jié)果為不存在,準(zhǔn)備插入此記錄,但執(zhí)行 insert 時(shí)發(fā)現(xiàn)此記錄已存在,無法插入,此時(shí)就發(fā)生了幻讀。產(chǎn)生這樣的原因是因?yàn)橛辛硪粋€(gè)事務(wù)往表中插入了數(shù)據(jù)。
我個(gè)人更贊成第一種說法。
說法二這種情況也屬于幻讀,說法二歸根到底還是數(shù)據(jù)集發(fā)生了改變,查詢得到的數(shù)據(jù)集與真實(shí)的數(shù)據(jù)集不匹配。
對于說法二:當(dāng)進(jìn)行INSERT的時(shí)候,也需要隱式的讀取,比如插入數(shù)據(jù)時(shí)需要讀取有沒有主鍵沖突,然后再決定是否能執(zhí)行插入。如果這時(shí)發(fā)現(xiàn)已經(jīng)有這個(gè)記錄了,就沒法插入。所以,SELECT 顯示不存在,但是INSERT的時(shí)候發(fā)現(xiàn)已存在,說明符合條件的數(shù)據(jù)行發(fā)生了變化,也就是幻讀的情況,而不可重復(fù)讀指的是同一條記錄的內(nèi)容被修改了。
舉例來說明:說法二說的是如下的情況:
有兩個(gè)事務(wù)A和B,A事務(wù)先開啟,然后A開始查詢數(shù)據(jù)集中有沒有id = 30的數(shù)據(jù),查詢的結(jié)果顯示數(shù)據(jù)中沒有id = 30的數(shù)據(jù)。緊接著又有一個(gè)事務(wù)B開啟了,B事務(wù)往表中插入了一條id = 30的數(shù)據(jù),然后提交了事務(wù)。然后A再開始往表中插入id = 30的數(shù)據(jù),由于B事務(wù)已經(jīng)插入了id = 30的數(shù)據(jù),自然是不能插入,緊接著A又查詢了一次,結(jié)果發(fā)現(xiàn)表中沒有id = 30的數(shù)據(jù)呀,A事務(wù)就很納悶了,怎么會插入不了數(shù)據(jù)呢。當(dāng)A事務(wù)提交以后,再次查詢,發(fā)現(xiàn)表中的確存在id = 30的數(shù)據(jù)。但是A事務(wù)還沒提交的時(shí)候,卻查不出來?
其實(shí),這便是可重復(fù)讀
的作用。
過程如下圖所示:
上圖中操作的t表的創(chuàng)建語句如下:
CREATE TABLE `t` ( `id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `c` (`c`) -- 創(chuàng)建索引 ) ENGINE=InnoDB; INSERT INTO t VALUES(0,0,0),(5,5,5), (10,10,10),(15,15,15),(20,20,20),(25,25,25);
MySQL使用的InnoDB引擎默認(rèn)的隔離級別是可重復(fù)讀
,也就是說在同一個(gè)事務(wù)中,兩次執(zhí)行同樣的查詢,得到的效果應(yīng)該是一樣的。因此,盡管B事務(wù)在A事務(wù)還未結(jié)束的時(shí)候,增加了表中的數(shù)據(jù),但是為了維護(hù)可重復(fù)讀,A事務(wù)中不管怎么查詢,是查詢不了新增的數(shù)據(jù)的。但是對于真實(shí)的表而言,表中的數(shù)據(jù)是的的確確增加了。
A查詢不到這個(gè)數(shù)據(jù),不代表這個(gè)數(shù)據(jù)不存在
。查詢得到了某條數(shù)據(jù),不代表它真的存在。這樣是是而非的查詢,就像是幻覺一樣,似真似假,故為幻讀
。
產(chǎn)生幻讀的原因歸根到底是由于查詢得到的結(jié)果與真實(shí)的結(jié)果不匹配。
幻讀 VS 不可重復(fù)讀
幻讀重點(diǎn)在于數(shù)據(jù)是否存在
。原本不存在的數(shù)據(jù)卻真實(shí)的存在了,這便是幻讀。在同一個(gè)事務(wù)中,第一次讀取到結(jié)果集和第二次讀取到的結(jié)果集不同。(對比上面的例子,當(dāng)B事務(wù)INSERT以后,A事務(wù)中再進(jìn)行插入,此次插入相當(dāng)于一次隱式查詢)。引起幻讀的原因在于另一個(gè)事務(wù)進(jìn)行了INSERT
操作。
不可重復(fù)讀重點(diǎn)在于數(shù)據(jù)是否被改變了
。在一個(gè)事務(wù)中對同一條記錄進(jìn)行查詢,第一次讀取到的數(shù)據(jù)和第二次讀取到的數(shù)據(jù)不一致,這便是可重復(fù)讀。引起不可重復(fù)讀的原因在于另一個(gè)事務(wù)進(jìn)行了UPDATE
或者是DELETE
操作。
簡單來說:幻讀是說數(shù)據(jù)的條數(shù)發(fā)生了變化,原本不存在的數(shù)據(jù)存在了。不可重復(fù)讀是說數(shù)據(jù)的內(nèi)容發(fā)生了變化,原本存在的數(shù)據(jù)的內(nèi)容發(fā)生了改變
。
在可重復(fù)讀隔離級別下,普通的查詢是快照讀,是不會看到別的事務(wù)插入的數(shù)據(jù)的。因此,幻讀在 當(dāng)前讀下才會出現(xiàn)。
什么是快照讀,什么是當(dāng)前讀?
快照讀讀取的是快照數(shù)據(jù)。不加鎖的簡單的 SELECT都屬于快照讀,比如這樣:
SELECT * FROM player WHERE ...
當(dāng)前讀就是讀取最新數(shù)據(jù),而不是歷史版本的數(shù)據(jù)。加鎖的 SELECT,或者對數(shù)據(jù)進(jìn)行增刪改都會進(jìn)行當(dāng)前讀。這有點(diǎn)像是 Java 中的 volatile 關(guān)鍵字,被 volatile 修飾的變量,進(jìn)行修改時(shí),JVM 會強(qiáng)制將其寫回內(nèi)存,而不是放在 CPU 緩存中,進(jìn)行讀取時(shí),JVM 會強(qiáng)制從內(nèi)存讀取,而不是放在 CPU 緩存中。這樣就能保證其可見行,保證每次讀取到的都是最新的值。如果沒有用 volatile 關(guān)鍵字修飾,變量的值可能會被放在 CPU 緩存中,這就導(dǎo)致讀取到的值可能是某次修改的值,不能保證是最新的值。
說多了,我們繼續(xù)來看,如下的操作都會進(jìn)行 當(dāng)前讀。
SELECT * FROM player LOCK IN SHARE MODE; SELECT * FROM player FOR UPDATE; INSERT INTO player values ... DELETE FROM player WHERE ... UPDATE player SET ...
說白了,快照讀就是普通的讀操作,而當(dāng)前讀包括了 加鎖的讀取和 DML(DML只是對表內(nèi)部的數(shù)據(jù)操作,不涉及表的定義,結(jié)構(gòu)的修改。主要包括insert、update、deletet) 操作。
比如在可重復(fù)讀的隔離條件下,我開啟了兩個(gè)事務(wù),在另一個(gè)事務(wù)中進(jìn)行了插入操作,當(dāng)前事務(wù)如果使用當(dāng)前讀是可以讀到最新的數(shù)據(jù)的。
當(dāng)隔離級別為可重復(fù)讀的時(shí)候,事務(wù)只在第一次 SELECT 的時(shí)候會獲取一次 Read View
,而后面所有的 SELECT 都會復(fù)用這個(gè) Read View。也就是說:對于A事務(wù)而言,不管其他事務(wù)怎么修改數(shù)據(jù),對于A事務(wù)而言,它能看到的數(shù)據(jù)永遠(yuǎn)都是第一次SELECT時(shí)看到的數(shù)據(jù)。這顯然不合理,如果其它事務(wù)插入了數(shù)據(jù),A事務(wù)卻只能看到過去的數(shù)據(jù),讀取不了當(dāng)前的數(shù)據(jù)。
既然都說到 Read View 了,就不得不說 MVCC (多版本并發(fā)控制) 機(jī)制了。MVCC 其實(shí)字面意思還比較好理解,為了防止數(shù)據(jù)產(chǎn)生沖突,我們可以使用時(shí)間戳之類的來進(jìn)行標(biāo)識,不同的時(shí)間戳對應(yīng)著不同的版本。比如你現(xiàn)在有1000元,你借給了張三 500 元, 之后李四給了你 500 元,雖然你的錢的總額都是 1000元,但是其實(shí)已經(jīng)和最開始的 1000元不一樣了,為了判斷中途是否有修改,我們就可以采用版本號來區(qū)分你的錢的變動。
如下,在數(shù)據(jù)庫的數(shù)據(jù)表中,id,name,type 這三個(gè)字段是我自己建立的,但是除了這些字段,其實(shí)還有些隱藏字段是 MySQL 偷偷為我們添加的,我們通常是看不到這樣的隱藏字段的。
我們重點(diǎn)關(guān)注這兩個(gè)隱藏的字段:
db_trx_id:操作這行數(shù)據(jù)的事務(wù) ID,也就是最后一個(gè)對該數(shù)據(jù)進(jìn)行插入或更新的事務(wù) ID。我們每開啟一個(gè)事務(wù),都會從數(shù)據(jù)庫中獲得一個(gè)事務(wù) ID(也就是事務(wù)版本號),這個(gè)事務(wù) ID 是自增長的,通過 ID 大小,我們就可以判斷事務(wù)的時(shí)間順序。
db_roll_ptr:回滾指針,指向這個(gè)記錄的 Undo Log信息。什么是 Undo Log 呢?可以這么理解,當(dāng)我們需要修改某條記錄時(shí),MySQL 擔(dān)心以后可能會撤銷該修改,回退到之前的狀態(tài),所以在修改之前,先把當(dāng)前的數(shù)據(jù)存?zhèn)€檔,然后再進(jìn)行修改,Undo Log 就可以理解為是這個(gè)存檔文件。這就像是我們打游戲一樣,打到某個(gè)關(guān)卡先存?zhèn)€檔,然后繼續(xù)往下一關(guān)挑戰(zhàn),如果下一關(guān)挑戰(zhàn)失敗,就回到之前的存檔點(diǎn),不至于從頭開始。
在 MVCC(多版本并發(fā)控制) 機(jī)制中,多個(gè)事務(wù)對同一個(gè)行記錄進(jìn)行更新會產(chǎn)生多個(gè)歷史快照,這些歷史快照保存在 Undo Log里。如下圖所示,當(dāng)前行記錄的 回滾指針指向的是它的上一個(gè)狀態(tài),它的上一個(gè)狀態(tài)的 回滾指針 又指向了上一個(gè)狀態(tài)的上一個(gè)狀態(tài)。這樣,理論上我們通過遍歷 回滾指針,就能找到該行數(shù)據(jù)的任意一個(gè)狀態(tài)。
Undo Log 示意圖
我們沒有想到,我們看到的或許只是一條數(shù)據(jù),但是MySQL卻在背后為該條數(shù)據(jù)存儲多個(gè)版本,為這條數(shù)據(jù)存了非常多的檔。那問題來了,當(dāng)我們開啟事務(wù)時(shí),我們在事務(wù)中想要查詢某條數(shù)據(jù),但是每一條數(shù)據(jù),都對應(yīng)了非常多的版本,這時(shí),我們需要讀取哪個(gè)版本的行記錄呢?
這時(shí)就需要用到 Read View
機(jī)制了,它幫我們解決了行的可見性問題。Read View 保存了當(dāng)前事務(wù)開啟時(shí)所有活躍(還沒有提交)的事務(wù)列表。
在 Read VIew 中有幾個(gè)重要的屬性:
trx_ids,系統(tǒng)當(dāng)前正在活躍的事務(wù) ID 集合
low_limit_id,活躍的事務(wù)中最大的事務(wù) ID
up_limit_id,活躍的事務(wù)中最小的事務(wù) ID
creator_trx_id,創(chuàng)建這個(gè) Read View 的事務(wù) ID
在前面我們說過了,在每一行記錄中有一個(gè)隱藏字段 db_trx_id,表示操作這行數(shù)據(jù)的事務(wù) ID ,而且 事務(wù) ID 是自增長的,通過 ID 大小,我們就可以判斷事務(wù)的時(shí)間順序。
當(dāng)我們開啟事務(wù)以后,準(zhǔn)備查詢某條記錄,發(fā)現(xiàn)該條記錄的 db_trx_id < up_limit_id,這說明什么呢?說明該條記錄一定是在本次事務(wù)開啟之前就已經(jīng)提交的,對于當(dāng)前事務(wù)而言,這屬于歷史數(shù)據(jù),可見,因此,我們通過 select 一定能查出這一條記錄。
但是如果發(fā)現(xiàn),要查詢的這條記錄的 db_trx_id > up_limit_id。這說明什么呢,說明我在開啟事務(wù)的時(shí)候,這條記錄肯定是還沒有的,是在之后這條記錄才被創(chuàng)建的,不應(yīng)該被當(dāng)前事務(wù)看見,這時(shí)候我們就可以通過 回滾指針 + Undo Log去找一下該記錄的歷史版本,返回給當(dāng)前事務(wù)。在本文 什么是幻讀 ?這一章節(jié)中舉的一個(gè)例子。A 事務(wù)開啟時(shí),數(shù)據(jù)庫中還沒有(30, 30, 30)這條記錄。A事務(wù)開啟以后,B事務(wù)往數(shù)據(jù)庫中插入了(30, 30, 30)這條記錄,這時(shí)候,A事務(wù)使用 不加鎖的 select 進(jìn)行 快照讀時(shí)是查詢不出這條新插入的記錄的,這符合我們的預(yù)期。對于 A事務(wù)而言,(30, 30, 30)這條記錄的 db_trx_id 一定大于 A事務(wù)開啟時(shí)的 up_limit_id,所以這條記錄不應(yīng)該被A事務(wù)看見。
如果需要查詢的這條記錄的 trx_id 滿足 up_limit_id < trx_id < low_limit_id 這個(gè)條件,說明該行記錄所在的事務(wù) trx_id 在目前 creator_trx_id 這個(gè)事務(wù)創(chuàng)建的時(shí)候,可能還處于活躍的狀態(tài),因此我們需要在 trx_ids 集合中進(jìn)行遍歷,如果 trx_id 存在于 trx_ids 集合中,證明這個(gè)事務(wù) trx_id 還處于活躍狀態(tài),不可見,如果該記錄有 Undo Log,我們可以通過回滾指針進(jìn)行遍歷,查詢該記錄的歷史版本數(shù)據(jù)。如果 trx_id 不存在于 trx_ids 集合中,證明事務(wù) trx_id 已經(jīng)提交了,該行記錄可見。
從圖中你能看到回滾指針將數(shù)據(jù)行的所有快照記錄都通過鏈表的結(jié)構(gòu)串聯(lián)了起來,每個(gè)快照的記錄都保存了當(dāng)時(shí)的 db_trx_id,也是那個(gè)時(shí)間點(diǎn)操作這個(gè)數(shù)據(jù)的事務(wù) ID。這樣如果我們想要找歷史快照,就可以通過遍歷回滾指針的方式進(jìn)行查找。
最后,再來強(qiáng)調(diào)一遍:事務(wù)只在第一次 SELECT 的時(shí)候會獲取一次 Read View
因此,如下圖所示,在 可重復(fù)讀的隔離條件下,在該事務(wù)中不管進(jìn)行多少次 以WHERE heigh > 2.08為條件的查詢,最終結(jié)果得到都是一樣的,盡管可能會有其它事務(wù)對這個(gè)結(jié)果集進(jìn)行了更改。
即便是給每行數(shù)據(jù)都加上行鎖,也無法解決幻讀,行鎖只能阻止修改,無法阻止數(shù)據(jù)的刪除。而且新插入的數(shù)據(jù),自然是數(shù)據(jù)庫中不存在的數(shù)據(jù),原本不存在的數(shù)據(jù)自然無法對其加鎖,因此僅僅使用行鎖是無法阻止別的事務(wù)插入數(shù)據(jù)的。
為了解決幻讀問題,InnoDB 只好引入新的鎖,也就是間隙鎖 (Gap Lock)
。顧名思義,間隙鎖,鎖的就是兩個(gè)值之間的空隙。比如文章開頭的表 t,初始化插入了 6 個(gè)記錄,這就產(chǎn)生了 7 個(gè)間隙。
表 t 主鍵索引上的行鎖和間隙鎖
也就是說這時(shí)候,在一行行掃描的過程中,不僅將給行加上了行鎖,還給行兩邊的空隙,也加上了間隙鎖?,F(xiàn)在你知道了,數(shù)據(jù)行是可以加上鎖的實(shí)體,數(shù)據(jù)行之間的間隙,也是可以加上鎖的實(shí)體。但是間隙鎖跟我們之前碰到過的鎖都不太一樣。
間隙鎖和行鎖合稱 next-key lock,每個(gè) next-key lock 是前開后閉區(qū)間。也就是說,我們的表 t 初始化以后,如果用 SELECT * FEOM t FOR UPDATE
要把整個(gè)表所有記錄鎖起來,就形成了 7 個(gè) next-key lock,分別是 (負(fù)無窮,0]、(0,5]、(5,10]、(10,15]、(15,20]、(20, 25]、(25, 正無窮]。
間隙鎖是在可重復(fù)讀隔離級別下才會生效的
怎么加間隙鎖呢?使用寫鎖(又叫排它鎖,X鎖)時(shí)自動生效,也就是說我們執(zhí)行 SELECT * FEOM t FOR UPDATE
時(shí)便會自動觸發(fā)間隙鎖。會給主鍵加上上圖所示的鎖。
如下圖所示,如果在事務(wù)A中執(zhí)行了SELECT * FROM t WHERE d = 5 FOR UPDATE
以后,事務(wù)B則無法插入數(shù)據(jù)了,因此就避免了產(chǎn)生幻讀。
數(shù)據(jù)表的創(chuàng)建語句如下
CREATE TABLE `t` ( `id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `c` (`c`) -- 創(chuàng)建索引 ) ENGINE=InnoDB; INSERT INTO t VALUES(0,0,0),(5,5,5), (10,10,10),(15,15,15),(20,20,20),(25,25,25);
需要注意的是,由于創(chuàng)建數(shù)據(jù)表的時(shí)候僅僅只在c字段上創(chuàng)建了索引,因此使用條件WHERE id = 5
查找時(shí)是會掃描全表的。因此,SELECT * FROM t WHERE d = 5 FOR UPDATE
實(shí)際上鎖住了整個(gè)表,如上圖所示,產(chǎn)生了七個(gè)間隙,這七個(gè)間隙都不允許數(shù)據(jù)的插入。
因此當(dāng)B想插入一條數(shù)據(jù)(1, 1, 1)時(shí)就會被阻塞住,因?yàn)樗闹麈I位于位于(0, 5]這個(gè)區(qū)間,被禁止插入。
還需要注意的一點(diǎn)是,間隙鎖和間隙鎖是不會產(chǎn)生沖突的
。讀鎖(又稱共享鎖,S鎖)和寫鎖會沖突,寫鎖和寫鎖也會產(chǎn)生沖突。但是間隙鎖和間隙鎖是不會產(chǎn)生沖突的
如下:
A事務(wù)對id = 5的數(shù)據(jù)加了讀鎖,B事務(wù)再對id = 5的數(shù)據(jù)加寫鎖則會失敗,若B事務(wù)加讀鎖則會成功。讀鎖和讀鎖可以兼容,讀鎖和寫鎖則不能兼容。
A事務(wù)對id = 5的數(shù)據(jù)加了寫鎖,B事務(wù)再對id = 5的數(shù)據(jù)加寫鎖則會失敗,若B事務(wù)加讀鎖同樣也會失敗。
在加了間隙鎖以后,當(dāng)A事務(wù)開啟以后,并對(5, 10]這個(gè)區(qū)間加了間隙鎖,那么B事務(wù)則無法插入數(shù)據(jù)了。
但是當(dāng)A事務(wù)對(5, 10]加了間隙鎖以后,B事務(wù)也可以對這個(gè)區(qū)間加間隙鎖。
間隙鎖的目的是阻止往這個(gè)區(qū)間插入數(shù)據(jù),因此A事務(wù)加了以后B事務(wù)繼續(xù)加間隙鎖,這并不矛盾。但是對于寫鎖和讀鎖就不一樣了。
寫鎖是不允許其它事務(wù)讀,也不允許寫,而讀鎖則是允許寫,語義上就存在沖突。自然無法同時(shí)加這兩個(gè)鎖。
而寫鎖和寫鎖也是,寫鎖不允許讀,也不允許寫,想想,A事務(wù)對數(shù)據(jù)加了寫鎖,就是完全不想讓其它事務(wù)操作該數(shù)據(jù),那其它數(shù)據(jù)若能為這個(gè)數(shù)據(jù)加寫鎖,就相當(dāng)于是對該數(shù)據(jù)實(shí)施了操作,違背了寫鎖的涵義,自然不被允許。
到此,相信大家對“mysql幻讀指的是什么”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
本文標(biāo)題:mysql幻讀指的是什么
網(wǎng)頁地址:http://jinyejixie.com/article34/gpehse.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、面包屑導(dǎo)航、定制開發(fā)、虛擬主機(jī)、靜態(tài)網(wǎng)站、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)