日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

mysql 隔离级别 快照_「数据库架构」三分钟搞懂事务隔离级别和脏读

發(fā)布時(shí)間:2024/9/19 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 隔离级别 快照_「数据库架构」三分钟搞懂事务隔离级别和脏读 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

重要要點(diǎn)

僅憑ACID或非ACID來思考,還需要知道數(shù)據(jù)庫(kù)支持的隔離級(jí)別。

標(biāo)榜為“最終一致”的某些數(shù)據(jù)庫(kù)可能返回與任何時(shí)間點(diǎn)不一致的結(jié)果。

一些數(shù)據(jù)庫(kù)提供的隔離級(jí)別比您要求的更高。

臟讀會(huì)導(dǎo)致您看到同一記錄的兩個(gè)版本,或者完全錯(cuò)過一條記錄。

在單個(gè)事務(wù)中多次重新運(yùn)行查詢時(shí),可能會(huì)出現(xiàn)幻像行。

最近,當(dāng)開發(fā)人員David Glasser了解MongoDB默認(rèn)執(zhí)行臟讀的糟糕方式時(shí),MongoDB再次成為Reddit的佼佼者。在本文中,我們將解釋什么是隔離級(jí)別和臟讀以及如何在流行的數(shù)據(jù)庫(kù)中實(shí)現(xiàn)它們。在ANSI SQL中,有四個(gè)標(biāo)準(zhǔn)隔離級(jí)別:可序列化,可重復(fù)讀取,已提交讀取和未提交讀取。

許多數(shù)據(jù)庫(kù)的默認(rèn)設(shè)置為“讀取已提交”,它僅保證在進(jìn)行該事務(wù)時(shí)您不會(huì)看到過渡中的數(shù)據(jù)。它通過在讀取期間短暫地獲取鎖來實(shí)現(xiàn)此目的,同時(shí)保持寫入鎖直到事務(wù)被提交。

如果您需要在一個(gè)事務(wù)中多次重復(fù)相同的讀取操作,并且想要合理地確定它總是返回相同的值,則需要在整個(gè)持續(xù)時(shí)間內(nèi)保持讀取鎖定。使用“可重復(fù)讀取”隔離級(jí)別時(shí),將自動(dòng)為您完成此操作。

我們說“可重復(fù)讀”是“合理肯定的”,因?yàn)榭赡艽嬖凇盎米x”。使用where子句(例如“ WHERE Status = 1”)執(zhí)行查詢時(shí),可能會(huì)發(fā)生幻像讀取。這些行將被鎖定,但是沒有什么阻止添加符合條件的新行。術(shù)語(yǔ)“幻像”適用于第二次執(zhí)行查詢時(shí)出現(xiàn)的行。

為了絕對(duì)確保同一事務(wù)中的兩次讀取返回相同的數(shù)據(jù),可以使用Serializable隔離級(jí)別。這使用“范圍鎖”,如果新行與打開的事務(wù)中的WHERE子句匹配,則可以防止添加這些行。

通常,隔離級(jí)別越高,由于鎖爭(zhēng)用而導(dǎo)致的性能越差。因此,為了提高讀取性能,某些數(shù)據(jù)庫(kù)還支持“讀取未提交”。此隔離級(jí)別忽略鎖(實(shí)際上在SQL Server中稱為NOLOCK)。結(jié)果,它會(huì)執(zhí)行臟讀。

臟讀問題

在討論臟讀之前,您必須了解表實(shí)際上并不存在于數(shù)據(jù)庫(kù)中。表只是一個(gè)邏輯構(gòu)造。實(shí)際上,您的數(shù)據(jù)存儲(chǔ)在一個(gè)或多個(gè)索引中。在大多數(shù)關(guān)系數(shù)據(jù)庫(kù)中,主索引被稱為“聚集索引”或“堆”。(對(duì)于NoSQL數(shù)據(jù)庫(kù),術(shù)語(yǔ)有所不同。)因此,在執(zhí)行插入操作時(shí),它需要在每個(gè)索引中插入一行。執(zhí)行更新時(shí),數(shù)據(jù)庫(kù)引擎僅需要觸摸引用正在更改的列的索引。但是,它通常必須對(duì)每個(gè)索引執(zhí)行兩次操作,即從舊位置刪除和向新位置插入。

在下圖中,您可以看到一個(gè)簡(jiǎn)單的表和一個(gè)執(zhí)行計(jì)劃,其中更新了兩個(gè)對(duì)象IX_Customer_State和PK_Customer。由于全名未更改,因此跳過了IX_Customer_FullName索引。

注意:在SQL Server中,PK前綴是指主鍵,它通常也是用于聚集索引的鍵。IX用于非聚集索引。其他數(shù)據(jù)庫(kù)有其自己的約定。

通過這種方式,讓我們看一下臟讀可能導(dǎo)致數(shù)據(jù)不一致的多種方式。未提交的讀取最容易理解。通過忽略寫鎖定,使用“讀未提交”的SELECT語(yǔ)句可以在事務(wù)完全提交之前看到新插入或更新的行。如果該轉(zhuǎn)換然后被回滾,那么從邏輯上講,SELECT操作將返回從不存在的數(shù)據(jù)。

在更新操作期間移動(dòng)數(shù)據(jù)時(shí),會(huì)發(fā)生兩次讀取。假設(shè)您正在按州讀取所有客戶記錄。如果上述更新語(yǔ)句是在您加州記錄的時(shí)間與您閱讀德克薩斯州記錄的時(shí)間之間執(zhí)行的,則您可以看到客戶1253兩次;一次使用舊值,一次使用新值。

漏讀的發(fā)生方式相同。如果我們將客戶1253移到德克薩斯州到阿拉斯加,再按州選擇數(shù)據(jù),則可能會(huì)完全錯(cuò)過該記錄。這就是David Glasser的MongoDB數(shù)據(jù)庫(kù)所發(fā)生的事情。通過在更新操作期間從索引讀取,查詢會(huì)丟失記錄。

根據(jù)數(shù)據(jù)庫(kù)的設(shè)計(jì)方式和特定的執(zhí)行計(jì)劃,臟讀也會(huì)干擾排序。例如,如果執(zhí)行引擎收集指向所有感興趣的行的一組指針,然后更新一行,然后執(zhí)行引擎實(shí)際上使用所述指針從原始位置復(fù)制數(shù)據(jù),則可能發(fā)生這種情況。

快照隔離或行級(jí)別版本控制

為了提供良好的性能同時(shí)避免臟讀問題,許多數(shù)據(jù)庫(kù)都支持快照隔離語(yǔ)義。在快照隔離下運(yùn)行時(shí),當(dāng)前事務(wù)無法查看在當(dāng)前事務(wù)之前啟動(dòng)的任何其他事務(wù)的結(jié)果。

這是通過制作要修改的行的臨時(shí)副本來完成的,而不是僅僅依靠鎖。這通常稱為“行級(jí)版本控制”。

當(dāng)請(qǐng)求讀取提交隔離時(shí),大多數(shù)支持快照隔離語(yǔ)義的數(shù)據(jù)庫(kù)都會(huì)自動(dòng)使用它。

SQL Server中的隔離級(jí)別

SQL Server支持所有四個(gè)ANSI SQL隔離級(jí)別以及一個(gè)顯式的快照級(jí)別。取決于使用READ_COMMITTED_SNAPSHOT選項(xiàng)配置數(shù)據(jù)庫(kù)的方式,“已提交讀”也可以使用快照語(yǔ)義。

在啟用此選項(xiàng)之前和之后,請(qǐng)徹底測(cè)試數(shù)據(jù)庫(kù)。雖然它可以提高讀取性能,但可能會(huì)減慢寫入速度。如果您的tempdb處于慢速驅(qū)動(dòng)器上,則尤其如此,因?yàn)檫@是行的舊版本存儲(chǔ)的地方。

臭名昭著的NOLOCK指令(可應(yīng)用于SELECT語(yǔ)句)與在設(shè)置為“讀取未提交”的事務(wù)中運(yùn)行具有相同的效果。由于SQL Server 2000和更早版本尚未提供行級(jí)版本控制,因此該版本已大量使用。盡管不再需要或不建議使用,但該習(xí)慣仍然存在。

有關(guān)更多信息,請(qǐng)參見SET TRANSACTION ISOLATION LEVEL(Transact-SQL)。

PostgreSQL中的隔離級(jí)別

雖然PostgreSQL正式支持所有四個(gè)ANSI隔離級(jí)別,但實(shí)際上它只有三個(gè)。每當(dāng)查詢請(qǐng)求“讀取未提交”時(shí),PostgreSQL都會(huì)以靜默方式將其升級(jí)為“讀取已提交”。因此PostgreSQL不允許臟讀。當(dāng)選擇級(jí)別Read Uncommitted時(shí),您實(shí)際上會(huì)獲得Read Committed,并且在Repeatable Read的PostgreSQL實(shí)現(xiàn)中不可能進(jìn)行幻像讀取,因此實(shí)際的隔離級(jí)別可能比您選擇的嚴(yán)格。這是SQL標(biāo)準(zhǔn)所允許的:四個(gè)隔離級(jí)別僅定義了哪些現(xiàn)象一定不能發(fā)生,它們沒有定義哪些現(xiàn)象必須發(fā)生。

PostgreSQL沒有明確提供快照隔離。而是在使用“讀取已提交”時(shí)自動(dòng)發(fā)生。這是因?yàn)镻ostgreSQL從一開始就設(shè)計(jì)為具有多版本并發(fā)控制。

在9.1版之前,PostgreSQL不提供可序列化的事務(wù),并且會(huì)靜默地將它們降級(jí)為“可重復(fù)讀”。當(dāng)前沒有支持的PostgreSQL版本仍然具有此限制。

有關(guān)更多信息,請(qǐng)參見13.2。事務(wù)隔離。

MySQL中的隔離級(jí)別

InnoDB默認(rèn)為“可重復(fù)讀取”,但提供所有四個(gè)ANSI SQL隔離級(jí)別。讀取已提交使用快照隔離語(yǔ)義。

有關(guān)InnoDB的更多信息,請(qǐng)參見15.3.2.1事務(wù)隔離級(jí)別。

使用MyISAM存儲(chǔ)引擎時(shí),根本不支持事務(wù)。相反,它在表級(jí)別使用一個(gè)讀寫器鎖。(盡管在某些情況下,插入操作可以繞過鎖。)

Oracle中的隔離級(jí)別

Oracle僅支持3個(gè)事務(wù)級(jí)別:讀已提交,可序列化和只讀。在Oracle中,“默認(rèn)值為讀已提交”,它使用快照語(yǔ)義。

像PostgreSQL一樣,Oracle不提供“讀未提交”。絕對(duì)不允許臟讀。

列表中還缺少“可重復(fù)讀取”。如果您在Oracle中需要這種行為,則需要將隔離級(jí)別設(shè)置為Serializable。

Oracle唯一的隔離級(jí)別是只讀。它沒有很好的文檔記錄,手冊(cè)只說:只讀事務(wù)僅查看那些在事務(wù)開始時(shí)提交的更改,并且不允許INSERT,UPDATE和DELETE語(yǔ)句。

有關(guān)其他兩個(gè)隔離級(jí)別的更多信息,請(qǐng)參閱13數(shù)據(jù)并發(fā)性和一致性。

DB 2中的隔離級(jí)別

DB 2具有4個(gè)隔離級(jí)別,分別稱為重復(fù)讀取,讀取穩(wěn)定性,游標(biāo)穩(wěn)定性和未提交讀取。但是,它們并不直接映射到ANSI術(shù)語(yǔ)。

可重復(fù)讀是ANSI SQL稱為可序列化的。也就是說,幻像讀取是不可能的。

讀取穩(wěn)定性映射到ANSI SQL的可重復(fù)讀取。

默認(rèn)情況下,“游標(biāo)穩(wěn)定性”用于“讀取已提交”。從9.7版開始,快照語(yǔ)義已生效。以前,它將使用類似于SQL Server的鎖。

未提交讀允許進(jìn)行臟讀,就像SQL Server的未提交讀一樣。該手冊(cè)僅建議將其用于只讀表,或者“在查看其他應(yīng)用程序未提交的數(shù)據(jù)沒有問題時(shí)”。

有關(guān)更多信息,請(qǐng)參見隔離級(jí)別。

MongoDB中的隔離級(jí)別

如前所述,MongoDB不支持事務(wù)。從手冊(cè)中由于MongoDB僅單文檔操作是原子操作,因此兩階段提交只能提供類似于事務(wù)的語(yǔ)義。在兩階段提交或回滾期間,應(yīng)用程序有可能在中間點(diǎn)返回中間數(shù)據(jù)。

實(shí)際上,這意味著MongoDB使用臟讀語(yǔ)義,其中包括記錄可能翻倍或丟失的可能性。

CouchDB中的隔離級(jí)別

CouchDB也不支持交易。但是與MongoDB不同,它確實(shí)使用多版本并發(fā)控制來防止臟讀。讀取請(qǐng)求在請(qǐng)求開始時(shí)始終會(huì)看到您數(shù)據(jù)庫(kù)的最新快照。

這使CouchDB等效于具有Snapshot語(yǔ)義的Read Committed隔離級(jí)別。

有關(guān)更多信息,請(qǐng)參見最終一致性。

Couchbase服務(wù)器中的隔離級(jí)別

盡管經(jīng)常與CouchDB混淆,但Couchbase Server是一個(gè)非常不同的產(chǎn)品。對(duì)于索引,它沒有隔離的概念。

在執(zhí)行更新時(shí),它僅更新主索引,如果您愿意,也可以更新“真實(shí)表”。所有二級(jí)索引均會(huì)延遲更新。

該文檔尚不清楚,但在建立索引時(shí)似乎使用快照。如果是這樣,臟讀應(yīng)該不是問題。但是由于延遲索引更新,您仍然無法獲得真正的“讀取已提交”隔離級(jí)別。

與許多NoSQL數(shù)據(jù)庫(kù)一樣,它不直接支持事務(wù)。但是,您確實(shí)可以使用顯式鎖。這些只能保留30秒,然后自動(dòng)丟棄。

有關(guān)更多信息,請(qǐng)參閱鎖定項(xiàng)目,您需要了解的有關(guān)Couchbase體系結(jié)構(gòu)的所有信息以及Couchbase View Engine內(nèi)部。

Cassandra的隔離級(jí)別

在Cassandra 1.0中,甚至沒有隔離寫入單個(gè)行。字段是一一更新的,因此您最終可能會(huì)讀取包含新舊值的記錄。

從1.1版開始,Cassandra提供“行級(jí)隔離”。這使其達(dá)到與其他數(shù)據(jù)庫(kù)稱為“讀取未提交”的相同隔離級(jí)別。更高級(jí)別的隔離是不可能的。

有關(guān)更多信息,請(qǐng)參見關(guān)于事務(wù)和并發(fā)控制。

了解數(shù)據(jù)庫(kù)的隔離級(jí)別

從上面的示例中可以看到,僅將數(shù)據(jù)庫(kù)視為ACID或非ACID是不夠的。您確實(shí)需要知道它支持什么隔離級(jí)別以及在什么情況下。

總結(jié)

以上是生活随笔為你收集整理的mysql 隔离级别 快照_「数据库架构」三分钟搞懂事务隔离级别和脏读的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。