真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

mysql怎么實(shí)現(xiàn)樂(lè)觀鎖,樂(lè)觀鎖 mysql

mysql事務(wù)隔離級(jí)別 以及 悲觀鎖-樂(lè)觀鎖

以上不是重點(diǎn),重點(diǎn)是 對(duì)事務(wù)控制語(yǔ)句不熟悉。

創(chuàng)新互聯(lián)建站專(zhuān)業(yè)為企業(yè)提供鞍山網(wǎng)站建設(shè)、鞍山做網(wǎng)站、鞍山網(wǎng)站設(shè)計(jì)、鞍山網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、鞍山企業(yè)網(wǎng)站模板建站服務(wù),10余年鞍山做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。

SAVEPOINT identifier : 在事務(wù)中 創(chuàng)建保存點(diǎn)。一個(gè)事務(wù)中 允許有多個(gè)保存點(diǎn)。

RELEASE SAVEPOINT identifier : 刪除保存點(diǎn)。當(dāng)事務(wù)中 沒(méi)有指定的 保存點(diǎn),執(zhí)行該語(yǔ)句 會(huì)拋異常。

ROLLBACK TO identifier : 把事務(wù)回滾到 保存點(diǎn)。

Say you have a table T with a column C with one row in it, say it has the value '1'. And consider you have a simple task like following:

That is a simple task that issue two reads from table T, with a delay of 1 minute between them.

If you follow the logic above you can quickly realize that SERIALIZABLE transactions, while they may make life easy for you, are always completely blocking every possible concurrent operation, since they require that nobody can modify, delete nor insert any row. The default transaction isolation level of the .Net System.Transactions scope is serializable, and this usually explains the abysmal performance that results.

在Repeatable Read隔離級(jí)別下,一個(gè)事務(wù)可能會(huì)遇到幻讀(Phantom Read)的問(wèn)題。

幻讀是指,在一個(gè)事務(wù)中,第一次查詢某條記錄,發(fā)現(xiàn)沒(méi)有,但是,當(dāng)試圖更新這條不存在的記錄時(shí),竟然能成功,并且,再次讀取同一條記錄,它就神奇地出現(xiàn)了。

我們?nèi)匀幌葴?zhǔn)備好students表的數(shù)據(jù):

然后,分別開(kāi)啟兩個(gè)MySQL客戶端連接,按順序依次執(zhí)行事務(wù)A和事務(wù)B:

事務(wù)B在第3步第一次讀取id=99的記錄時(shí),讀到的記錄為空,說(shuō)明不存在id=99的記錄。隨后,事務(wù)A在第4步插入了一條id=99的記錄并提交。事務(wù)B在第6步再次讀取id=99的記錄時(shí),讀到的記錄仍然為空,但是,事務(wù)B在第7步試圖更新這條不存在的記錄時(shí),竟然成功了,并且,事務(wù)B在第8步再次讀取id=99的記錄時(shí),記錄出現(xiàn)了。

可見(jiàn),幻讀就是沒(méi)有讀到的記錄,以為不存在,但其實(shí)是可以更新成功的,并且,更新成功后,再次讀取,就出現(xiàn)了。

在沖突較少的情況下,使用樂(lè)觀鎖。樂(lè)觀鎖 因?yàn)闆](méi)有 加鎖 釋放鎖,也減少了 加鎖 釋放鎖的開(kāi)銷(xiāo)。

沖突較多時(shí),如果使用樂(lè)觀鎖 需要不停地嘗試,所以 使用悲觀鎖。

如果樂(lè)觀鎖 進(jìn)行嘗試時(shí) 的花銷(xiāo)較大,也是使用悲觀鎖。

mysql 核心內(nèi)容-上

1、SQL語(yǔ)句執(zhí)行流程

MySQL大體上可分為Server層和存儲(chǔ)引擎層兩部分。

Server層:

連接器:TCP握手后服務(wù)器來(lái)驗(yàn)證登陸用戶身份,A用戶創(chuàng)建連接后,管理員對(duì)A用戶權(quán)限修改了也不會(huì)影響到已經(jīng)創(chuàng)建的鏈接權(quán)限,必須重新登陸。

查詢緩存:查詢后的結(jié)果存儲(chǔ)位置,MySQL8.0版本以后已經(jīng)取消,因?yàn)椴樵兙彺媸l繁,得不償失。

分析器:根據(jù)語(yǔ)法規(guī)則,判斷你輸入的這個(gè)SQL語(yǔ)句是否滿足MySQL語(yǔ)法。

優(yōu)化器:多種執(zhí)行策略可實(shí)現(xiàn)目標(biāo),系統(tǒng)自動(dòng)選擇最優(yōu)進(jìn)行執(zhí)行。

執(zhí)行器:判斷是否有權(quán)限,將最終任務(wù)提交到存儲(chǔ)引擎。

存儲(chǔ)引擎層

負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)和提取。其架構(gòu)模式是插件式的,支持InnoDB、MyISAM、Memory等多個(gè)存儲(chǔ)引擎?,F(xiàn)在最常用的存儲(chǔ)引擎是InnoDB,它從MySQL 5.5.5版本開(kāi)始成為了默認(rèn)存儲(chǔ)引擎(經(jīng)常用的也是這個(gè))。

SQL執(zhí)行順序

2、BinLog、RedoLog、UndoLog

BinLog

BinLog是記錄所有數(shù)據(jù)庫(kù)表結(jié)構(gòu)變更(例如create、alter table)以及表數(shù)據(jù)修改(insert、update、delete)的二進(jìn)制日志,主從數(shù)據(jù)庫(kù)同步用到的都是BinLog文件。BinLog日志文件有三種模式。

STATEMENT 模式

內(nèi)容:binlog 記錄可能引起數(shù)據(jù)變更的 sql 語(yǔ)句

優(yōu)勢(shì):該模式下,因?yàn)闆](méi)有記錄實(shí)際的數(shù)據(jù),所以日志量很少 IO 都消耗很低,性能是最優(yōu)的

劣勢(shì):但有些操作并不是確定的,比如 uuid() 函數(shù)會(huì)隨機(jī)產(chǎn)生唯一標(biāo)識(shí),當(dāng)依賴 binlog 回放時(shí),該操作生成的數(shù)據(jù)與原數(shù)據(jù)必然是不同的,此時(shí)可能造成無(wú)法預(yù)料的后果。

ROW 模式

內(nèi)容:在該模式下,binlog 會(huì)記錄每次操作的源數(shù)據(jù)與修改后的目標(biāo)數(shù)據(jù),StreamSets就要求該模式。

優(yōu)勢(shì):可以絕對(duì)精準(zhǔn)的還原,從而保證了數(shù)據(jù)的安全與可靠,并且復(fù)制和數(shù)據(jù)恢復(fù)過(guò)程可以是并發(fā)進(jìn)行的

劣勢(shì):缺點(diǎn)在于 binlog 體積會(huì)非常大,同時(shí),對(duì)于修改記錄多、字段長(zhǎng)度大的操作來(lái)說(shuō),記錄時(shí)性能消耗會(huì)很?chē)?yán)重。閱讀的時(shí)候也需要特殊指令來(lái)進(jìn)行讀取數(shù)據(jù)。

MIXED 模式

內(nèi)容:是對(duì)上述STATEMENT 跟 ROW 兩種模式的混合使用。

細(xì)節(jié):對(duì)于絕大部分操作,都是使用 STATEMENT 來(lái)進(jìn)行 binlog 沒(méi)有記錄,只有以下操作使用 ROW 來(lái)實(shí)現(xiàn):表的存儲(chǔ)引擎為 NDB,使用了uuid() 等不確定函數(shù),使用了 insert delay 語(yǔ)句,使用了臨時(shí)表

主從同步流程:

1、主節(jié)點(diǎn)必須啟用二進(jìn)制日志,記錄任何修改了數(shù)據(jù)庫(kù)數(shù)據(jù)的事件。

2、從節(jié)點(diǎn)開(kāi)啟一個(gè)線程(I/O Thread)把自己扮演成 mysql 的客戶端,通過(guò) mysql 協(xié)議,請(qǐng)求主節(jié)點(diǎn)的二進(jìn)制日志文件中的事件 。

3、主節(jié)點(diǎn)啟動(dòng)一個(gè)線程(dump Thread),檢查自己二進(jìn)制日志中的事件,跟對(duì)方請(qǐng)求的位置對(duì)比,如果不帶請(qǐng)求位置參數(shù),則主節(jié)點(diǎn)就會(huì)從第一個(gè)日志文件中的第一個(gè)事件一個(gè)一個(gè)發(fā)送給從節(jié)點(diǎn)。

4、從節(jié)點(diǎn)接收到主節(jié)點(diǎn)發(fā)送過(guò)來(lái)的數(shù)據(jù)把它放置到中繼日志(Relay log)文件中。并記錄該次請(qǐng)求到主節(jié)點(diǎn)的具體哪一個(gè)二進(jìn)制日志文件內(nèi)部的哪一個(gè)位置(主節(jié)點(diǎn)中的二進(jìn)制文件會(huì)有多個(gè))。

5、從節(jié)點(diǎn)啟動(dòng)另外一個(gè)線程(sql Thread ),把 Relay log 中的事件讀取出來(lái),并在本地再執(zhí)行一次。

mysql默認(rèn)的復(fù)制方式是異步的,并且復(fù)制的時(shí)候是有并行復(fù)制能力的。主庫(kù)把日志發(fā)送給從庫(kù)后不管了,這樣會(huì)產(chǎn)生一個(gè)問(wèn)題就是假設(shè)主庫(kù)掛了,從庫(kù)處理失敗了,這時(shí)候從庫(kù)升為主庫(kù)后,日志就丟失了。由此產(chǎn)生兩個(gè)概念。

全同步復(fù)制

主庫(kù)寫(xiě)入binlog后強(qiáng)制同步日志到從庫(kù),所有的從庫(kù)都執(zhí)行完成后才返回給客戶端,但是很顯然這個(gè)方式的話性能會(huì)受到嚴(yán)重影響。

半同步復(fù)制

半同步復(fù)制的邏輯是這樣,從庫(kù)寫(xiě)入日志成功后返回ACK確認(rèn)給主庫(kù),主庫(kù)收到至少一個(gè)從庫(kù)的確認(rèn)就認(rèn)為寫(xiě)操作完成。

還可以延伸到由于主從配置不一樣、主庫(kù)大事務(wù)、從庫(kù)壓力過(guò)大、網(wǎng)絡(luò)震蕩等造成主備延遲,如何避免這個(gè)問(wèn)題?主備切換的時(shí)候用可靠性優(yōu)先原則還是可用性優(yōu)先原則?如何判斷主庫(kù)Crash了?互為主備的情況下如何避免主備循環(huán)復(fù)制?被刪庫(kù)跑路了如何正確恢復(fù)?( o )… 感覺(jué)越來(lái)越扯到DBA的活兒上去了。

RedoLog

可以先通過(guò)下面demo理解:

飯點(diǎn)記賬可以把賬單寫(xiě)在賬本上也可以寫(xiě)在粉板上。有人賒賬或者還賬的話,一般有兩種做法:

1、直接把賬本翻出來(lái),把這次賒的賬加上去或者扣除掉。

2、先在粉板上記下這次的賬,等打烊以后再把賬本翻出來(lái)核算。

生意忙時(shí)選后者,因?yàn)榍罢咛闊┝恕5迷诿苊苈槁榈挠涗浿姓业竭@個(gè)人的賒賬總額信息,找到之后再拿出算盤(pán)計(jì)算,最后再將結(jié)果寫(xiě)回到賬本上。

同樣在MySQL中如果每一次的更新操作都需要寫(xiě)進(jìn)磁盤(pán),然后磁盤(pán)也要找到對(duì)應(yīng)的那條記錄,然后再更新,整個(gè)過(guò)程IO成本、查找成本都很高。而粉板和賬本配合的整個(gè)過(guò)程就是MySQL用到的是Write-Ahead Logging 技術(shù),它的關(guān)鍵點(diǎn)就是先寫(xiě)日志,再寫(xiě)磁盤(pán)。此時(shí)賬本 = BinLog,粉板 = RedoLog。

1、 記錄更新時(shí),InnoDB引擎就會(huì)先把記錄寫(xiě)到RedoLog(粉板)里面,并更新內(nèi)存。同時(shí),InnoDB引擎會(huì)在空閑時(shí)將這個(gè)操作記錄更新到磁盤(pán)里面。

2、 如果更新太多RedoLog處理不了的時(shí)候,需先將RedoLog部分?jǐn)?shù)據(jù)寫(xiě)到磁盤(pán),然后擦除RedoLog部分?jǐn)?shù)據(jù)。RedoLog類(lèi)似轉(zhuǎn)盤(pán)。

RedoLog有write pos 跟checkpoint

write pos :是當(dāng)前記錄的位置,一邊寫(xiě)一邊后移,寫(xiě)到第3號(hào)文件末尾后就回到0號(hào)文件開(kāi)頭。

check point:是當(dāng)前要擦除的位置,也是往后推移并且循環(huán)的,擦除記錄前要把記錄更新到數(shù)據(jù)文件。

write pos和check point之間的是粉板上還空著的部分,可以用來(lái)記錄新的操作。如果write pos追上checkpoint,表示粉板滿了,這時(shí)候不能再執(zhí)行新的更新,得停下來(lái)先擦掉一些記錄,把checkpoint推進(jìn)一下。

有了redo log,InnoDB就可以保證即使數(shù)據(jù)庫(kù)發(fā)生異常重啟,之前提交的記錄都不會(huì)丟失,這個(gè)能力稱為crash-safe。 redolog兩階段提交:為了讓binlog跟redolog兩份日志之間的邏輯一致。提交流程大致如下:

1 prepare階段 -- 2 寫(xiě)binlog -- 3 commit

當(dāng)在2之前崩潰時(shí),重啟恢復(fù)后發(fā)現(xiàn)沒(méi)有commit,回滾。備份恢復(fù):沒(méi)有binlog 。一致

當(dāng)在3之前崩潰時(shí),重啟恢復(fù)發(fā)現(xiàn)雖沒(méi)有commit,但滿足prepare和binlog完整,所以重啟后會(huì)自動(dòng)commit。備份:有binlog. 一致

binlog跟redolog區(qū)別:

redo log是InnoDB引擎特有的;binlog是MySQL的Server層實(shí)現(xiàn)的,所有引擎都可以使用。

redo log是物理日志,記錄的是在某個(gè)數(shù)據(jù)頁(yè)上做了什么修改;binlog是邏輯日志,記錄的是這個(gè)語(yǔ)句的原始邏輯,比如給ID=2這一行的c字段加1。

redo log是循環(huán)寫(xiě)的,空間固定會(huì)用完;binlog是可以追加寫(xiě)入的。追加寫(xiě)是指binlog文件寫(xiě)到一定大小后會(huì)切換到下一個(gè),并不會(huì)覆蓋以前的日志。

UndoLog

UndoLog 一般是邏輯日志,主要分為兩種:

insert undo log

代表事務(wù)在insert新記錄時(shí)產(chǎn)生的undo log, 只在事務(wù)回滾時(shí)需要,并且在事務(wù)提交后可以被立即丟棄

update undo log

事務(wù)在進(jìn)行update或delete時(shí)產(chǎn)生的undo log; 不僅在事務(wù)回滾時(shí)需要,在快照讀時(shí)也需要;所以不能隨便刪除,只有在快速讀或事務(wù)回滾不涉及該日志時(shí),對(duì)應(yīng)的日志才會(huì)被purge線程統(tǒng)一清除

3、MySQL中的索引

索引的常見(jiàn)模型有哈希表、有序數(shù)組和搜索樹(shù)。

哈希表:一種以KV存儲(chǔ)數(shù)據(jù)的結(jié)構(gòu),只適合等值查詢,不適合范圍查詢。

有序數(shù)組:只適用于靜態(tài)存儲(chǔ)引擎,涉及到插入的時(shí)候比較麻煩??梢詤⒖糐ava中的ArrayList。

搜索樹(shù):按照數(shù)據(jù)結(jié)構(gòu)中的二叉樹(shù)來(lái)存儲(chǔ)數(shù)據(jù),不過(guò)此時(shí)是N叉樹(shù)(B+樹(shù))。廣泛應(yīng)用在存儲(chǔ)引擎層中。

B+樹(shù)比B樹(shù)優(yōu)勢(shì)在于:

B+ 樹(shù)非葉子節(jié)點(diǎn)存儲(chǔ)的只是索引,可以存儲(chǔ)的更多。B+樹(shù)比B樹(shù)更加矮胖,IO次數(shù)更少。

B+ 樹(shù)葉子節(jié)點(diǎn)前后管理,更加方便范圍查詢。同時(shí)結(jié)果都在葉子節(jié)點(diǎn),查詢效率穩(wěn)定。

B+樹(shù)中更有利于對(duì)數(shù)據(jù)掃描,可以避免B樹(shù)的回溯掃描。

索引的優(yōu)點(diǎn):

1、唯一索引可以保證每一行數(shù)據(jù)的唯一性

2、提高查詢速度

3、加速表與表的連接

4、顯著的減少查詢中分組和排序的時(shí)間

5、通過(guò)使用索引,可以在查詢的過(guò)程中,使用優(yōu)化隱藏器,提高系統(tǒng)的性能。

索引的缺點(diǎn):

1、創(chuàng)建跟維護(hù)都需要耗時(shí)

2、創(chuàng)建索引時(shí),需要對(duì)表加鎖,在鎖表的同時(shí),可能會(huì)影響到其他的數(shù)據(jù)操作

3、 索引需要磁盤(pán)的空間進(jìn)行存儲(chǔ),磁盤(pán)占用也很快。

4、當(dāng)對(duì)表中的數(shù)據(jù)進(jìn)行CRUD的時(shí),也會(huì)觸發(fā)索引的維護(hù),而維護(hù)索引需要時(shí)間,可能會(huì)降低數(shù)據(jù)操作性能

索引設(shè)計(jì)的原則不應(yīng)該:

1、索引不是越多越好。索引太多,維護(hù)索引需要時(shí)間跟空間。

2、 頻繁更新的數(shù)據(jù),不宜建索引。

3、數(shù)據(jù)量小的表沒(méi)必要建立索引。

應(yīng)該:

1、重復(fù)率小的列建議生成索引。因?yàn)橹貜?fù)數(shù)據(jù)少,索引樹(shù)查詢更有效率,等價(jià)基數(shù)越大越好。

2、數(shù)據(jù)具有唯一性,建議生成唯一性索引。在數(shù)據(jù)庫(kù)的層面,保證數(shù)據(jù)正確性

3、頻繁group by、order by的列建議生成索引。可以大幅提高分組和排序效率

4、經(jīng)常用于查詢條件的字段建議生成索引。通過(guò)索引查詢,速度更快

索引失效的場(chǎng)景

1、模糊搜索:左模糊或全模糊都會(huì)導(dǎo)致索引失效,比如'%a'和'%a%'。但是右模糊是可以利用索引的,比如'a%' 。

2、隱式類(lèi)型轉(zhuǎn)換:比如select * from t where name = xxx , name是字符串類(lèi)型,但是沒(méi)有加引號(hào),所以是由MySQL隱式轉(zhuǎn)換的,所以會(huì)讓索引失效 3、當(dāng)語(yǔ)句中帶有or的時(shí)候:比如select * from t where name=‘sw’ or age=14

4、不符合聯(lián)合索引的最左前綴匹配:(A,B,C)的聯(lián)合索引,你只where了C或B或只有B,C

關(guān)于索引的知識(shí)點(diǎn):

主鍵索引:主鍵索引的葉子節(jié)點(diǎn)存的是整行數(shù)據(jù)信息。在InnoDB里,主鍵索引也被稱為聚簇索引(clustered index)。主鍵自增是無(wú)法保證完全自增的哦,遇到唯一鍵沖突、事務(wù)回滾等都可能導(dǎo)致不連續(xù)。

唯一索引:以唯一列生成的索引,該列不允許有重復(fù)值,但允許有空值(NULL)

普通索引跟唯一索引查詢性能:InnoDB的數(shù)據(jù)是按數(shù)據(jù)頁(yè)為單位來(lái)讀寫(xiě)的,默認(rèn)每頁(yè)16KB,因此這兩種索引查詢數(shù)據(jù)性能差別微乎其微。

change buffer:普通索引用在更新過(guò)程的加速,更新的字段如果在緩存中,如果是普通索引則直接更新即可。如果是唯一索引需要將所有數(shù)據(jù)讀入內(nèi)存來(lái)確保不違背唯一性,所以盡量用普通索引。

非主鍵索引:非主鍵索引的葉子節(jié)點(diǎn)內(nèi)容是主鍵的值。在InnoDB里,非主鍵索引也被稱為二級(jí)索引(secondary index)

回表:先通過(guò)數(shù)據(jù)庫(kù)索引掃描出數(shù)據(jù)所在的行,再通過(guò)行主鍵id取出索引中未提供的數(shù)據(jù),即基于非主鍵索引的查詢需要多掃描一棵索引樹(shù)。

覆蓋索引:如果一個(gè)索引包含(或者說(shuō)覆蓋)所有需要查詢的字段的值,我們就稱之為覆蓋索引。

聯(lián)合索引:相對(duì)單列索引,組合索引是用多個(gè)列組合構(gòu)建的索引,一次性最多聯(lián)合16個(gè)。

最左前綴原則:對(duì)多個(gè)字段同時(shí)建立的組合索引(有順序,ABC,ACB是完全不同的兩種聯(lián)合索引) 以聯(lián)合索引(a,b,c)為例,建立這樣的索引相當(dāng)于建立了索引a、ab、abc三個(gè)索引。另外組合索引實(shí)際還是一個(gè)索引,并非真的創(chuàng)建了多個(gè)索引,只是產(chǎn)生的效果等價(jià)于產(chǎn)生多個(gè)索引。

索引下推:MySQL 5.6引入了索引下推優(yōu)化,可以在索引遍歷過(guò)程中,對(duì)索引中包含的字段先做判斷,過(guò)濾掉不符合條件的記錄,減少回表字?jǐn)?shù)。

索引維護(hù):B+樹(shù)為了維護(hù)索引有序性涉及到頁(yè)分裂跟頁(yè)合并。增刪數(shù)據(jù)時(shí)需考慮頁(yè)空間利用率。

自增主鍵:一般會(huì)建立與業(yè)務(wù)無(wú)關(guān)的自增主鍵,不會(huì)觸發(fā)葉子節(jié)點(diǎn)分裂。

延遲關(guān)聯(lián):通過(guò)使用覆蓋索引查詢返回需要的主鍵,再根據(jù)主鍵關(guān)聯(lián)原表獲得需要的數(shù)據(jù)。

InnoDB存儲(chǔ): * .frm文件是一份定義文件,也就是定義數(shù)據(jù)庫(kù)表是一張?jiān)趺礃拥谋怼?.ibd文件則是該表的索引,數(shù)據(jù)存儲(chǔ)文件,既該表的所有索引樹(shù),所有行記錄數(shù)據(jù)都存儲(chǔ)在該文件中。

MyISAM存儲(chǔ):* .frm文件是一份定義文件,也就是定義數(shù)據(jù)庫(kù)表是一張?jiān)趺礃拥谋怼? .MYD文件是MyISAM存儲(chǔ)引擎表的所有行數(shù)據(jù)的文件。* .MYI文件存放的是MyISAM存儲(chǔ)引擎表的索引相關(guān)數(shù)據(jù)的文件。MyISAM引擎下,表數(shù)據(jù)和表索引數(shù)據(jù)是分開(kāi)存儲(chǔ)的。

MyISAM查詢:在MyISAM下,主鍵索引和輔助鍵索引都屬于非聚簇索引。查詢不管是走主鍵索引,還是非主鍵索引,在葉子結(jié)點(diǎn)得到的都是目的數(shù)據(jù)的地址,還需要通過(guò)該地址,才能在數(shù)據(jù)文件中找到目的數(shù)據(jù)。

PS:InnoDB支持聚簇索引,MyISAM不支持聚簇索引

4、SQL事務(wù)隔離級(jí)別

ACID的四個(gè)特性

原子性(Atomicity):把多個(gè)操作放到一個(gè)事務(wù)中,保證這些操作要么都成功,要么都不成功

一致性(Consistency):理解成一串對(duì)數(shù)據(jù)進(jìn)行操作的程序執(zhí)行下來(lái),不會(huì)對(duì)數(shù)據(jù)產(chǎn)生不好的影響,比如憑空產(chǎn)生,或消失

隔離性(Isolation,又稱獨(dú)立性):隔離性的意思就是多個(gè)事務(wù)之間互相不干擾,即使是并發(fā)事務(wù)的情況下,他們只是兩個(gè)并發(fā)執(zhí)行沒(méi)有交集,互不影響的東西;當(dāng)然實(shí)現(xiàn)中,也不一定需要這么完整隔離性,即不一定需要這么的互不干擾,有時(shí)候還是允許有部分干擾的。所以MySQL可以支持4種事務(wù)隔離性

持久性(Durability):當(dāng)某個(gè)操作操作完畢了,那么結(jié)果就是這樣了,并且這個(gè)操作會(huì)持久化到日志記錄中

PS:ACID中C與CAP定理中C的區(qū)別

ACID的C著重強(qiáng)調(diào)單數(shù)據(jù)庫(kù)事務(wù)操作時(shí),要保證數(shù)據(jù)的完整和正確性,數(shù)據(jù)不會(huì)憑空消失跟增加。CAP 理論中的C指的是對(duì)一個(gè)數(shù)據(jù)多個(gè)備份的讀寫(xiě)一致性

事務(wù)操作可能會(huì)出現(xiàn)的數(shù)據(jù)問(wèn)題

1、臟讀(dirty read):B事務(wù)更改數(shù)據(jù)還未提交,A事務(wù)已經(jīng)看到并且用了。B事務(wù)如果回滾,則A事務(wù)做錯(cuò)了

2、 不可重復(fù)讀(non-repeatable read):不可重復(fù)讀的重點(diǎn)是修改: 同樣的條件, 你讀取過(guò)的數(shù)據(jù), 再次讀取出來(lái)發(fā)現(xiàn)值不一樣了,只需要鎖住滿足條件的記錄

3、 幻讀(phantom read):事務(wù)A先修改了某個(gè)表的所有紀(jì)錄的狀態(tài)字段為已處理,未提交;事務(wù)B也在此時(shí)新增了一條未處理的記錄,并提交了;事務(wù)A隨后查詢記錄,卻發(fā)現(xiàn)有一條記錄是未處理的造成幻讀現(xiàn)象,幻讀僅專(zhuān)指新插入的行。幻讀會(huì)造成語(yǔ)義上的問(wèn)題跟數(shù)據(jù)一致性問(wèn)題。

4、 在可重復(fù)讀RR隔離級(jí)別下,普通查詢是快照讀,是不會(huì)看到別的事務(wù)插入的數(shù)據(jù)的。因此,幻讀在當(dāng)前讀下才會(huì)出現(xiàn)。要用間隙鎖解決此問(wèn)題。

在說(shuō)隔離級(jí)別之前,你首先要知道,你隔離得越嚴(yán)實(shí),效率就會(huì)越低。因此很多時(shí)候,我們都要在二者之間尋找一個(gè)平衡點(diǎn)。SQL標(biāo)準(zhǔn)的事務(wù)隔離級(jí)別由低到高如下: 上圖從上到下的模式會(huì)導(dǎo)致系統(tǒng)的并行性能依次降低,安全性依次提高。

讀未提交:別人改數(shù)據(jù)的事務(wù)尚未提交,我在我的事務(wù)中也能讀到。

讀已提交(Oracle默認(rèn)):別人改數(shù)據(jù)的事務(wù)已經(jīng)提交,我在我的事務(wù)中才能讀到。

可重復(fù)讀(MySQL默認(rèn)):別人改數(shù)據(jù)的事務(wù)已經(jīng)提交,我在我的事務(wù)中也不去讀,以此保證重復(fù)讀一致性。

串行:我的事務(wù)尚未提交,別人就別想改數(shù)據(jù)。

標(biāo)準(zhǔn)跟實(shí)現(xiàn):上面都是關(guān)于事務(wù)的標(biāo)準(zhǔn),但是每一種數(shù)據(jù)庫(kù)都有不同的實(shí)現(xiàn),比如MySQL InnDB 默認(rèn)為RR級(jí)別,但是不會(huì)出現(xiàn)幻讀。因?yàn)楫?dāng)事務(wù)A更新了所有記錄的某個(gè)字段,此時(shí)事務(wù)A會(huì)獲得對(duì)這個(gè)表的表鎖,因?yàn)槭聞?wù)A還沒(méi)有提交,所以事務(wù)A獲得的鎖沒(méi)有釋放,此時(shí)事務(wù)B在該表插入新記錄,會(huì)因?yàn)闊o(wú)法獲得該表的鎖,則導(dǎo)致插入操作被阻塞。只有事務(wù)A提交了事務(wù)后,釋放了鎖,事務(wù)B才能進(jìn)行接下去的操作。所以可以說(shuō) MySQL的RR級(jí)別的隔離是已經(jīng)實(shí)現(xiàn)解決了臟讀,不可重復(fù)讀和幻讀的。

5、MySQL中的鎖

無(wú)論是Java的并發(fā)編程還是數(shù)據(jù)庫(kù)的并發(fā)操作都會(huì)涉及到鎖,研發(fā)人員引入了悲觀鎖跟樂(lè)觀鎖這樣一種鎖的設(shè)計(jì)思想。

悲觀鎖:

優(yōu)點(diǎn):適合在寫(xiě)多讀少的并發(fā)環(huán)境中使用,雖然無(wú)法維持非常高的性能,但是在樂(lè)觀鎖無(wú)法提更好的性能前提下,可以做到數(shù)據(jù)的安全性

缺點(diǎn):加鎖會(huì)增加系統(tǒng)開(kāi)銷(xiāo),雖然能保證數(shù)據(jù)的安全,但數(shù)據(jù)處理吞吐量低,不適合在讀書(shū)寫(xiě)少的場(chǎng)合下使用

樂(lè)觀鎖:

優(yōu)點(diǎn):在讀多寫(xiě)少的并發(fā)場(chǎng)景下,可以避免數(shù)據(jù)庫(kù)加鎖的開(kāi)銷(xiāo),提高DAO層的響應(yīng)性能,很多情況下ORM工具都有帶有樂(lè)觀鎖的實(shí)現(xiàn),所以這些方法不一定需要我們?nèi)藶榈娜?shí)現(xiàn)。

缺點(diǎn):在寫(xiě)多讀少的并發(fā)場(chǎng)景下,即在寫(xiě)操作競(jìng)爭(zhēng)激烈的情況下,會(huì)導(dǎo)致CAS多次重試,沖突頻率過(guò)高,導(dǎo)致開(kāi)銷(xiāo)比悲觀鎖更高。

實(shí)現(xiàn):數(shù)據(jù)庫(kù)層面的樂(lè)觀鎖其實(shí)跟CAS思想類(lèi)似, 通數(shù)據(jù)版本號(hào)或者時(shí)間戳也可以實(shí)現(xiàn)。

數(shù)據(jù)庫(kù)并發(fā)場(chǎng)景主要有三種:

讀-讀:不存在任何問(wèn)題,也不需要并發(fā)控制

讀-寫(xiě):有隔離性問(wèn)題,可能遇到臟讀,幻讀,不可重復(fù)讀

寫(xiě)-寫(xiě):可能存更新丟失問(wèn)題,比如第一類(lèi)更新丟失,第二類(lèi)更新丟失

兩類(lèi)更新丟失問(wèn)題:

第一類(lèi)更新丟失:事務(wù)A的事務(wù)回滾覆蓋了事務(wù)B已提交的結(jié)果 第二類(lèi)更新丟失:事務(wù)A的提交覆蓋了事務(wù)B已提交的結(jié)果

為了合理貫徹落實(shí)鎖的思想,MySQL中引入了雜七雜八的各種鎖:

鎖分類(lèi)

MySQL支持三種層級(jí)的鎖定,分別為

表級(jí)鎖定

MySQL中鎖定粒度最大的一種鎖,最常使用的MYISAM與INNODB都支持表級(jí)鎖定。

頁(yè)級(jí)鎖定

是MySQL中鎖定粒度介于行級(jí)鎖和表級(jí)鎖中間的一種鎖,表級(jí)鎖速度快,但沖突多,行級(jí)沖突少,但速度慢。所以取了折衷的頁(yè)級(jí),一次鎖定相鄰的一組記錄。

行級(jí)鎖定

Mysql中鎖定粒度最細(xì)的一種鎖,表示只針對(duì)當(dāng)前操作的行進(jìn)行加鎖。行級(jí)鎖能大大減少數(shù)據(jù)庫(kù)操作的沖突。其加鎖粒度最小,但加鎖的開(kāi)銷(xiāo)也最大行級(jí)鎖不一定比表級(jí)鎖要好:鎖的粒度越細(xì),代價(jià)越高,相比表級(jí)鎖在表的頭部直接加鎖,行級(jí)鎖還要掃描找到對(duì)應(yīng)的行對(duì)其上鎖,這樣的代價(jià)其實(shí)是比較高的,所以表鎖和行鎖各有所長(zhǎng)。

MyISAM中的鎖

雖然MySQL支持表,頁(yè),行三級(jí)鎖定,但MyISAM存儲(chǔ)引擎只支持表鎖。所以MyISAM的加鎖相對(duì)比較開(kāi)銷(xiāo)低,但數(shù)據(jù)操作的并發(fā)性能相對(duì)就不高。但如果寫(xiě)操作都是尾插入,那還是可以支持一定程度的讀寫(xiě)并發(fā)

從MyISAM所支持的鎖中也可以看出,MyISAM是一個(gè)支持讀讀并發(fā),但不支持通用讀寫(xiě)并發(fā),寫(xiě)寫(xiě)并發(fā)的數(shù)據(jù)庫(kù)引擎,所以它更適合用于讀多寫(xiě)少的應(yīng)用場(chǎng)合,一般工程中也用的較少。

InnoDB中的鎖

該模式下支持的鎖實(shí)在是太多了,具體如下:

共享鎖和排他鎖 (Shared and Exclusive Locks)

意向鎖(Intention Locks)

記錄鎖(Record Locks)

間隙鎖(Gap Locks)

臨鍵鎖 (Next-Key Locks)

插入意向鎖(Insert Intention Locks)

主鍵自增鎖 (AUTO-INC Locks)

空間索引斷言鎖(Predicate Locks for Spatial Indexes)

舉個(gè)栗子,比如行鎖里的共享鎖跟排它鎖:lock in share modle 共享讀鎖:

為了確保自己查到的數(shù)據(jù)沒(méi)有被其他的事務(wù)正在修改,也就是說(shuō)確保查到的數(shù)據(jù)是最新的數(shù)據(jù),并且不允許其他人來(lái)修改數(shù)據(jù)。但是自己不一定能夠修改數(shù)據(jù),因?yàn)橛锌赡芷渌氖聞?wù)也對(duì)這些數(shù)據(jù)使用了 in share mode 的方式上了S 鎖。如果不及時(shí)的commit 或者rollback 也可能會(huì)造成大量的事務(wù)等待。

for update排它寫(xiě)鎖:

為了讓自己查到的數(shù)據(jù)確保是最新數(shù)據(jù),并且查到后的數(shù)據(jù)只允許自己來(lái)修改的時(shí)候,需要用到for update。相當(dāng)于一個(gè) update 語(yǔ)句。在業(yè)務(wù)繁忙的情況下,如果事務(wù)沒(méi)有及時(shí)的commit或者rollback 可能會(huì)造成其他事務(wù)長(zhǎng)時(shí)間的等待,從而影響數(shù)據(jù)庫(kù)的并發(fā)使用效率。

Gap Lock間隙鎖:

1、行鎖只能鎖住行,如果在記錄之間的間隙插入數(shù)據(jù)就無(wú)法解決了,因此MySQL引入了間隙鎖(Gap Lock)。間隙鎖是左右開(kāi)區(qū)間。間隙鎖之間不會(huì)沖突。

2、間隙鎖和行鎖合稱NextKeyLock,每個(gè)NextKeyLock是前開(kāi)后閉區(qū)間。

間隙鎖加鎖原則(學(xué)完忘那種):

1、加鎖的基本單位是 NextKeyLock,是前開(kāi)后閉區(qū)間。

2、查找過(guò)程中訪問(wèn)到的對(duì)象才會(huì)加鎖。

3、索引上的等值查詢,給唯一索引加鎖的時(shí)候,NextKeyLock退化為行鎖。

4、索引上的等值查詢,向右遍歷時(shí)且最后一個(gè)值不滿足等值條件的時(shí)候,NextKeyLock退化為間隙鎖。

5、唯一索引上的范圍查詢會(huì)訪問(wèn)到不滿足條件的第一個(gè)值為止。

mysql如何實(shí)現(xiàn)樂(lè)觀鎖

樂(lè)觀鎖與悲觀鎖不同的是,它是一種邏輯上的鎖,而不需要數(shù)據(jù)庫(kù)提供鎖機(jī)制來(lái)支持

當(dāng)數(shù)據(jù)很重要,回滾或重試一次需要很大的開(kāi)銷(xiāo)時(shí),需要保證操作的ACID性質(zhì),此時(shí)應(yīng)該采用悲觀鎖

而當(dāng)數(shù)據(jù)對(duì)即時(shí)的一致性要求不高,重試一次不太影響整體性能時(shí),可以采用樂(lè)觀鎖來(lái)保證最終一致性,同時(shí)有利于提高并發(fā)性

通常,樂(lè)觀鎖采用版本號(hào)/時(shí)間戳的形式實(shí)現(xiàn):給數(shù)據(jù)額外增加一個(gè)版本號(hào)字段進(jìn)行控制;更新時(shí),若提交的數(shù)據(jù)所帶的版本號(hào)與當(dāng)前記錄的版本號(hào)一致,則允許變更執(zhí)行并更新版本號(hào);若不一致,則意味著產(chǎn)生沖突,根據(jù)業(yè)務(wù)需求直接丟棄并返回失敗,或者嘗試合并

在MySQL的實(shí)踐中,常見(jiàn)的一種使用樂(lè)觀鎖的方法,是在需要使用樂(lè)觀鎖的表中,新增一個(gè)version字段

例如:

create table product_amount (

id int not null primary key auto_increment,

product_name varchar(64) not null,

selling_amount int not null,

storing_amount int not null,

version int not null

);

當(dāng)需要更新銷(xiāo)售中的商品數(shù)量(selling_amount)時(shí),使用如下的SQL語(yǔ)句:

update product_amount set selling_amount = #{selling_amount}, version = #{new_version} where id=#{id} and version = #{old_version};

若該語(yǔ)句返回1,則表示更新成功;若返回0,則表示前后的version不一致,產(chǎn)生沖突,更新失敗

對(duì)于更新倉(cāng)庫(kù)中的商品數(shù)據(jù)(storing_amount)時(shí),也是同理

不過(guò),這樣為每行記錄都統(tǒng)一設(shè)置一個(gè)version字段的樂(lè)觀鎖方式,存在一個(gè)問(wèn)題:上例中,如果同時(shí)需要單獨(dú)對(duì)selling_amount及storing_amount進(jìn)行update(兩條SQL語(yǔ)句分別單獨(dú)執(zhí)行),那么后執(zhí)行的一條會(huì)因?yàn)橄葓?zhí)行的一條更新了version字段而失敗,而這種失敗顯然是沒(méi)有必要的,白白浪費(fèi)了開(kāi)銷(xiāo)

一種比較好的方式是為每個(gè)需要樂(lè)觀鎖的字段單獨(dú)設(shè)置版本號(hào),例如對(duì)上例的改造:

create table product_amount (

id int not null primary key auto_increment,

product_name varchar(64) not null,

selling_amount int not null,

selling_version int not null,

storing_amount int not null,

storing_version int not null

);

selling_amount和storing_amount分別擁有自己的樂(lè)觀鎖版本號(hào)(selling_version和storing_version),更新時(shí)分別只關(guān)注自己的版本號(hào),這樣就不會(huì)因?yàn)榘姹咎?hào)被其它字段修改而失敗,提高了并發(fā)性


文章標(biāo)題:mysql怎么實(shí)現(xiàn)樂(lè)觀鎖,樂(lè)觀鎖 mysql
本文URL:http://weahome.cn/article/phhses.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部