国产成人精品18p,天天干成人网,无码专区狠狠躁天天躁,美女脱精光隐私扒开免费观看

MySql的行級鎖和表級鎖是怎樣的

發(fā)布時(shí)間:2021-09-27 17:43 來(lái)源:億速云 閱讀:0 作者:柒染 欄目: Mysql 歡迎投稿:712375056

的行級鎖和表級鎖是怎樣的,相信很多沒(méi)有經(jīng)驗的人對此束手無(wú)策,為此本文總結了問(wèn)題出現的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

MySql 行級鎖 表級鎖

如何保證數據并發(fā)訪(fǎng)問(wèn)的一致性、有效性是所有數據庫必須解決的一個(gè)問(wèn)題,鎖沖突也是影響數據庫并發(fā)訪(fǎng)問(wèn)性能的一個(gè)重要因素。從這個(gè)角度來(lái)說(shuō),鎖對數據庫而言顯得尤其重要,也更加復雜。

MySQL鎖概述

相對其他數據庫而言,MySQL的鎖機制比較簡(jiǎn)單,其最顯著(zhù)的特點(diǎn)是不同的存儲引擎支持不同的鎖機制。  
   比如

MyISAM和MEMORY存儲引擎采用的是表級鎖(table-level locking)。

InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是采用行級鎖。

MySQL這3種鎖的特性可大致歸納如下

表級鎖:開(kāi)銷(xiāo)小,加鎖快;不會(huì )出現死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。

行級鎖:開(kāi)銷(xiāo)大,加鎖慢;會(huì )出現死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。

頁(yè)面鎖:開(kāi)銷(xiāo)和加鎖時(shí)間界于表鎖和行鎖之間;會(huì )出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。

僅從鎖的角度來(lái)說(shuō):表級鎖更適合于以查詢(xún)?yōu)橹?,只有少量按索引條件更新數據的應用,如Web應用;而行級鎖則更適合于有大量按索引條件并發(fā)更新少量不同數據,同時(shí)又有并發(fā)查詢(xún)的應用,如一些在線(xiàn)事務(wù)處理(OLTP)系統。下面幾節我們重點(diǎn)介紹MySQL表鎖和 InnoDB行鎖的問(wèn)題。

MyISAM表鎖

MyISAM存儲引擎只支持表鎖,這也是MySQL開(kāi)始幾個(gè)版本中唯一支持的鎖類(lèi)型。隨著(zhù)應用對事務(wù)完整性和并發(fā)性要求的不斷提高,MySQL才開(kāi)始開(kāi)發(fā)基于事務(wù)的存儲引擎,后來(lái)慢慢出現了支持頁(yè)鎖的BDB存儲引擎和支持行鎖的InnoDB存儲引擎(實(shí)際 InnoDB是單獨的一個(gè)公司,現在已經(jīng)被Oracle公司收購)。但是MyISAM的表鎖依然是使用最為廣泛的鎖類(lèi)型。本節將詳細介紹MyISAM表鎖的使用。

查詢(xún)表級鎖爭用情況

可以通過(guò)檢查table_locks_waited和table_locks_immediate狀態(tài)變量來(lái)分析系統上的表鎖定爭奪:

mysql> show status like 'table%';

| Variable_name         | Value |

| Table_locks_immediate | 2979  |

| Table_locks_waited    | 0     |

2 rows in set (0.00 sec))

如果Table_locks_waited的值比較高,則說(shuō)明存在著(zhù)較嚴重的表級鎖爭用情況。

MySQL表級鎖的鎖模式

MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨占寫(xiě)鎖(Table Write Lock)。

MyISAM表的讀操作,不會(huì )阻塞其他用戶(hù)對同一表的讀請求,但會(huì )阻塞對同一表的寫(xiě)請求;  
   MyISAM表的寫(xiě)操作,則會(huì )阻塞其他用戶(hù)對同一表的讀和寫(xiě)操作;  
   MyISAM表的讀操作與寫(xiě)操作之間,以及寫(xiě)操作之間是串行的;  
   當一個(gè)線(xiàn)程獲得對一個(gè)表的寫(xiě)鎖后,只有持有鎖的線(xiàn)程可以對表進(jìn)行更新操作。其他線(xiàn)程的讀、寫(xiě)操作都會(huì )等待,直到鎖被釋放為止。

獲得表film_text的WRITE鎖定

mysql> lock table film_text write;

Query OK, 0 rows affected (0.00 sec)

當前session對鎖定表的查詢(xún)、更新、插入操作都可以執行:

mysql> select film_id,title from film_text where film_id = 1001;

| film_id | title       |

| 1001    | Update Test |

1 row in set (0.00 sec)

mysql> insert into film_text (film_id,title) values(1003,'Test');

Query OK, 1 row affected (0.00 sec)

mysql> update film_text set title = 'Test' where film_id = 1001;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

其他session對鎖定表的查詢(xún)被阻塞,需要等待鎖被釋放:

mysql> select film_id,title from film_text where film_id = 1001;

等待

釋放鎖:

mysql> unlock tables;

Query OK, 0 rows affected (0.00 sec)

等待

Session2獲得鎖,查詢(xún)返回:

mysql> select film_id,title from film_text where film_id = 1001;

| film_id | title |

| 1001    | Test  |

1 row in set (57.59 sec)

如何加表鎖?

MyISAM在執行查詢(xún)語(yǔ)句(SELECT)前,會(huì )自動(dòng)給涉及的所有表加讀鎖,在執行更新操作(UPDATE、DELETE、INSERT等)前,會(huì )自動(dòng)給涉及的表加寫(xiě)鎖,這個(gè)過(guò)程并不需要用戶(hù)干預,因此,用戶(hù)一般不需要直接用LOCK TABLE命令給MyISAM表顯式加鎖。在示例中,顯式加鎖基本上都是為了方便而已,并非必須如此。

給MyISAM表顯示加鎖,一般是為了在一定程度模擬事務(wù)操作,實(shí)現對某一時(shí)間點(diǎn)多個(gè)表的一致性讀取。例如,有一個(gè)訂單表orders,其中記錄有各訂單的總金額total,同時(shí)還有一個(gè)訂單明細表order_detail,其中記錄有各訂單每一產(chǎn)品的金額小計 subtotal,假設我們需要檢查這兩個(gè)表的金額合計是否相符,可能就需要執行如下兩條SQL:

Select sum(total) from orders;

Select sum(subtotal) from order_detail;

這時(shí),如果不先給兩個(gè)表加鎖,就可能產(chǎn)生錯誤的結果,因為第一條語(yǔ)句執行過(guò)程中,order_detail表可能已經(jīng)發(fā)生了改變。因此,正確的方法應該是:

Lock tables orders read local, order_detail read local;

Select sum(total) from orders;

Select sum(subtotal) from order_detail;

Unlock tables;

要特別說(shuō)明以下兩點(diǎn)內容。

上面的例子在LOCK TABLES時(shí)加了“l(fā)ocal”選項,其作用就是在滿(mǎn)足MyISAM表并發(fā)插入條件的情況下,允許其他用戶(hù)在表尾并發(fā)插入記錄,有關(guān)MyISAM表的并發(fā)插入問(wèn)題,后面還會(huì )進(jìn)一步介紹。

在用LOCK TABLES給表顯式加表鎖時(shí),必須同時(shí)取得所有涉及到表的鎖,并且MySQL不支持鎖升級。也就是說(shuō),在執行LOCK TABLES后,只能訪(fǎng)問(wèn)顯式加鎖的這些表,不能訪(fǎng)問(wèn)未加鎖的表;同時(shí),如果加的是讀鎖,那么只能執行查詢(xún)操作,而不能執行更新操作。其實(shí),在自動(dòng)加鎖的情況下也基本如此,MyISAM總是一次獲得SQL語(yǔ)句所需要的全部鎖。這也正是MyISAM表不會(huì )出現死鎖(Deadlock Free)的原因。

一個(gè)session使用LOCK TABLE命令給表film_text加了讀鎖,這個(gè)session可以查詢(xún)鎖定表中的記錄,但更新或訪(fǎng)問(wèn)其他表都會(huì )提示錯誤;同時(shí),另外一個(gè)session可以查詢(xún)表中的記錄,但更新就會(huì )出現鎖等待。

當使用LOCK TABLES時(shí),不僅需要一次鎖定用到的所有表,而且,同一個(gè)表在SQL語(yǔ)句中出現多少次,就要通過(guò)與SQL語(yǔ)句中相同的別名鎖定多少次,否則也會(huì )出錯!

舉例說(shuō)明如下。

(1)對actor表獲得讀鎖:

mysql> lock table actor read;

Query OK, 0 rows affected (0.00 sec)

(2)但是通過(guò)別名訪(fǎng)問(wèn)會(huì )提示錯誤:

mysql> select a.first_name,a.last_name,b.first_name,b.last_name from actor a,actor b where a.first_name = b.first_name and a.first_name = 'Lisa' and a.last_name = 'Tom' and a.last_name <> b.last_name;

ERROR 1100 (HY000): Table 'a' was not locked with LOCK TABLES

(3)需要對別名分別鎖定:

mysql> lock table actor as a read,actor as b read;

Query OK, 0 rows affected (0.00 sec)

(4)按照別名的查詢(xún)可以正確執行:

mysql> select a.first_name,a.last_name,b.first_name,b.last_name from actor a,actor b where a.first_name = b.first_name and a.first_name = 'Lisa' and a.last_name = 'Tom' and a.last_name <> b.last_name;

| first_name | last_name | first_name | last_name |

| Lisa       | Tom       | LISA       | MONROE    |

1 row in set (0.00 sec)

并發(fā)插入(Concurrent Inserts)

上文提到過(guò)MyISAM表的讀和寫(xiě)是串行的,但這是就總體而言的。在一定條件下,MyISAM表也支持查詢(xún)和插入操作的并發(fā)進(jìn)行。

MyISAM存儲引擎有一個(gè)系統變量concurrent_insert,專(zhuān)門(mén)用以控制其并發(fā)插入的行為,其值分別可以為0、1或2。

當concurrent_insert設置為0時(shí),不允許并發(fā)插入。

當concurrent_insert設置為1時(shí),如果MyISAM表中沒(méi)有空洞(即表的中間沒(méi)有被刪除的行),MyISAM允許在一個(gè)進(jìn)程讀表的同時(shí),另一個(gè)進(jìn)程從表尾插入記錄。這也是MySQL的默認設置。

當concurrent_insert設置為2時(shí),無(wú)論MyISAM表中有沒(méi)有空洞,都允許在表尾并發(fā)插入記錄。

可以利用MyISAM存儲引擎的并發(fā)插入特性,來(lái)解決應用中對同一表查詢(xún)和插入的鎖爭用。例如,將concurrent_insert系統變量設為2,總是允許并發(fā)插入;同時(shí),通過(guò)定期在系統空閑時(shí)段執行 OPTIMIZE TABLE語(yǔ)句來(lái)整理空間碎片,收回因刪除記錄而產(chǎn)生的中間空洞。有關(guān)OPTIMIZE TABLE語(yǔ)句的詳細介紹,可以參見(jiàn)第18章中“兩個(gè)簡(jiǎn)單實(shí)用的優(yōu)化方法”一節的內容。

MyISAM的鎖調度

前面講過(guò),MyISAM存儲引擎的讀鎖和寫(xiě)鎖是互斥的,讀寫(xiě)操作是串行的。那么,一個(gè)進(jìn)程請求某個(gè) MyISAM表的讀鎖,同時(shí)另一個(gè)進(jìn)程也請求同一表的寫(xiě)鎖,MySQL如何處理呢?答案是寫(xiě)進(jìn)程先獲得鎖。不僅如此,即使讀請求先到鎖等待隊列,寫(xiě)請求后到,寫(xiě)鎖也會(huì )插到讀鎖請求之前!這是因為MySQL認為寫(xiě)請求一般比讀請求要重要。這也正是MyISAM表不太適合于有大量更新操作和查詢(xún)操作應用的原因,因為,大量的更新操作會(huì )造成查詢(xún)操作很難獲得讀鎖,從而可能永遠阻塞。這種情況有時(shí)可能會(huì )變得非常糟糕!幸好我們可以通過(guò)一些設置來(lái)調節M(mǎn)yISAM 的調度行為。

通過(guò)指定啟動(dòng)參數low-priority-updates,使MyISAM引擎默認給予讀請求以?xún)?yōu)先的權利。

通過(guò)執行命令SET LOW_PRIORITY_UPDATES=1,使該連接發(fā)出的更新請求優(yōu)先級降低。

通過(guò)指定INSERT、UPDATE、DELETE語(yǔ)句的LOW_PRIORITY屬性,降低該語(yǔ)句的優(yōu)先級。

雖然上面3種方法都是要么更新優(yōu)先,要么查詢(xún)優(yōu)先的方法,但還是可以用其來(lái)解決查詢(xún)相對重要的應用(如用戶(hù)登錄系統)中,讀鎖等待嚴重的問(wèn)題。

另外,MySQL也提供了一種折中的辦法來(lái)調節讀寫(xiě)沖突,即給系統參數max_write_lock_count設置一個(gè)合適的值,當一個(gè)表的讀鎖達到這個(gè)值后,MySQL就暫時(shí)將寫(xiě)請求的優(yōu)先級降低,給讀進(jìn)程一定獲得鎖的機會(huì )。

上面已經(jīng)討論了寫(xiě)優(yōu)先調度機制帶來(lái)的問(wèn)題和解決辦法。這里還要強調一點(diǎn):一些需要長(cháng)時(shí)間運行的查詢(xún)操作,也會(huì )使寫(xiě)進(jìn)程“餓死”!因此,應用中應盡量避免出現長(cháng)時(shí)間運行的查詢(xún)操作,不要總想用一條SELECT語(yǔ)句來(lái)解決問(wèn)題,因為這種看似巧妙的SQL語(yǔ)句,往往比較復雜,執行時(shí)間較長(cháng),在可能的情況下可以通過(guò)使用中間表等措施對SQL語(yǔ)句做一定的“分解”,使每一步查詢(xún)都能在較短時(shí)間完成,從而減少鎖沖突。如果復雜查詢(xún)不可避免,應盡量安排在數據庫空閑時(shí)段執行,比如一些定期統計可以安排在夜間執行。

InnoDB鎖

InnoDB與MyISAM的最大不同有兩點(diǎn):一是支持事務(wù)(TRANSACTION);二是采用了行級鎖。行級鎖與表級鎖本來(lái)就有許多不同之處,另外,事務(wù)的引入也帶來(lái)了一些新問(wèn)題。下面我們先介紹一點(diǎn)背景知識,然后詳細討論InnoDB的鎖問(wèn)題。

1.事務(wù)(Transaction)及其ACID屬性

事務(wù)是由一組SQL語(yǔ)句組成的邏輯處理單元,事務(wù)具有以下4個(gè)屬性,通常簡(jiǎn)稱(chēng)為事務(wù)的ACID屬性。

(Atomicity)原子性:事務(wù)是一個(gè)原子操作單元,其對數據的修改,要么全都執行,要么全都不執行。

(Consistent)一致性:在事務(wù)開(kāi)始和完成時(shí),數據都必須保持一致?tīng)顟B(tài)。這意味著(zhù)所有相關(guān)的數據規則都必須應用于事務(wù)的修改,以保持數據的完整性;事務(wù)結束時(shí),所有的內部數據結構(如B樹(shù)索引或雙向鏈表)也都必須是正確的。

(Isolation)隔離性:數據庫系統提供一定的隔離機制,保證事務(wù)在不受外部并發(fā)操作影響的“獨立”環(huán)境執行。這意味著(zhù)事務(wù)處理過(guò)程中的中間狀態(tài)對外部是不可見(jiàn)的,反之亦然。

(Durable)持久性:事務(wù)完成之后,它對于數據的修改是永久性的,即使出現系統故障也能夠保持。

銀行轉帳就是事務(wù)的一個(gè)典型例子。

2.并發(fā)事務(wù)處理帶來(lái)的問(wèn)題

相對于串行處理來(lái)說(shuō),并發(fā)事務(wù)處理能大大增加數據庫資源的利用率,提高數據庫系統的事務(wù)吞吐量,從而可以支持更多的用戶(hù)。但并發(fā)事務(wù)處理也會(huì )帶來(lái)一些問(wèn)題,主要包括以下幾種情況。

更新丟失(Lost Update):當兩個(gè)或多個(gè)事務(wù)選擇同一行,然后基于最初選定的值更新該行時(shí),由于每個(gè)事務(wù)都不知道其他事務(wù)的存在,就會(huì )發(fā)生丟失更新問(wèn)題--最后的更新覆蓋了由其他事務(wù)所做的更新。例如,兩個(gè)編輯人員制作了同一文檔的電子副本。每個(gè)編輯人員獨立地更改其副本,然后保存更改后的副本,這樣就覆蓋了原始文檔。最后保存其更改副本的編輯人員覆蓋另一個(gè)編輯人員所做的更改。如果在一個(gè)編輯人員完成并提交事務(wù)之前,另一個(gè)編輯人員不能訪(fǎng)問(wèn)同一文件,則可避免此問(wèn)題。

臟讀(Dirty Reads):一個(gè)事務(wù)正在對一條記錄做修改,在這個(gè)事務(wù)完成并提交前,這條記錄的數據就處于不一致?tīng)顟B(tài);這時(shí),另一個(gè)事務(wù)也來(lái)讀取同一條記錄,如果不加控制,第二個(gè)事務(wù)讀取了這些“臟”數據,并據此做進(jìn)一步的處理,就會(huì )產(chǎn)生未提交的數據依賴(lài)關(guān)系。這種現象被形象地叫做"臟讀"。

不可重復讀(Non-Repeatable Reads):一個(gè)事務(wù)在讀取某些數據后的某個(gè)時(shí)間,再次讀取以前讀過(guò)的數據,卻發(fā)現其讀出的數據已經(jīng)發(fā)生了改變、或某些記錄已經(jīng)被刪除了!這種現象就叫做“不可重復讀”。

幻讀(Phantom Reads):一個(gè)事務(wù)按相同的查詢(xún)條件重新讀取以前檢索過(guò)的數據,卻發(fā)現其他事務(wù)插入了滿(mǎn)足其查詢(xún)條件的新數據,這種現象就稱(chēng)為“幻讀”。

3.事務(wù)隔離級別

在上面講到的并發(fā)事務(wù)處理帶來(lái)的問(wèn)題中,“更新丟失”通常是應該完全避免的。但防止更新丟失,并不能單靠數據庫事務(wù)控制器來(lái)解決,需要應用程序對要更新的數據加必要的鎖來(lái)解決,因此,防止更新丟失應該是應用的責任。

“臟讀”、“不可重復讀”和“幻讀”,其實(shí)都是數據庫讀一致性問(wèn)題,必須由數據庫提供一定的事務(wù)隔離機制來(lái)解決。數據庫實(shí)現事務(wù)隔離的方式,基本上可分為以下兩種。

一種是在讀取數據前,對其加鎖,阻止其他事務(wù)對數據進(jìn)行修改。

另一種是不用加任何鎖,通過(guò)一定機制生成一個(gè)數據請求時(shí)間點(diǎn)的一致性數據快照(Snapshot),并用這個(gè)快照來(lái)提供一定級別(語(yǔ)句級或事務(wù)級)的一致性讀取。從用戶(hù)的角度來(lái)看,好像是數據庫可以提供同一數據的多個(gè)版本,因此,這種技術(shù)叫做數據多版本并發(fā)控制(MultiVersion Concurrency Control,簡(jiǎn)稱(chēng)MVCC或MCC),也經(jīng)常稱(chēng)為多版本數據庫。

一致性讀,又稱(chēng)為快照讀。使用的是MVCC機制讀取undo中的已經(jīng)提交的數據。所以它的讀取是非阻塞的。

一致性讀肯定是讀取在某個(gè)時(shí)間點(diǎn)已經(jīng)提交了的數據,有個(gè)特例:本事務(wù)中修改的數據,即使未提交的數據也可以在本事務(wù)的后面部分讀取到。一致性讀是指普通的select語(yǔ)句,不帶 for update, in share mode 等等子句。使用的是undo中的提交的數據,不需要使用鎖(MDL除外)。而當前讀,是指update, delete, select for update, select in share mode等等語(yǔ)句進(jìn)行的讀,它們讀取的是數據庫中的最新的數據,并且會(huì )鎖住讀取的行和gap(RR隔離時(shí))。如果不能獲得鎖,則會(huì )一直等待,直到獲得或者超時(shí)。

數據庫的事務(wù)隔離越嚴格,并發(fā)副作用越小,但付出的代價(jià)也就越大,因為事務(wù)隔離實(shí)質(zhì)上就是使事務(wù)在一定程度上 “串行化”進(jìn)行,這顯然與“并發(fā)”是矛盾的。同時(shí),不同的應用對讀一致性和事務(wù)隔離程度的要求也是不同的,比如許多應用對“不可重復讀”和“幻讀”并不敏感,可能更關(guān)心數據并發(fā)訪(fǎng)問(wèn)的能力。

為了解決“隔離”與“并發(fā)”的矛盾,ISO/ANSI SQL92定義了4個(gè)事務(wù)隔離級別,每個(gè)級別的隔離程度不同,允許出現的副作用也不同,應用可以根據自己的業(yè)務(wù)邏輯要求,通過(guò)選擇不同的隔離級別來(lái)平衡 “隔離”與“并發(fā)”的矛盾。表20-5很好地概括了這4個(gè)隔離級別的特性。

各具體數據庫并不一定完全實(shí)現了上述4個(gè)隔離級別Oracle只提供Read committed和Serializable兩個(gè)標準隔離級別,另外還提供自己定義的Read only隔離級別;SQL Server除支持上述ISO/ANSI SQL92定義的4個(gè)隔離級別外,還支持一個(gè)叫做“快照”的隔離級別,但嚴格來(lái)說(shuō)它是一個(gè)用MVCC實(shí)現的Serializable隔離級別。

MySQL 支持全部4個(gè)隔離級別,但在具體實(shí)現時(shí),有一些特點(diǎn),比如在一些隔離級別下是采用MVCC一致性讀,但某些情況下又不是,這些內容在后面的章節中將會(huì )做進(jìn)一步介紹。

4.獲取InnoDB行鎖爭用情況

可以通過(guò)檢查InnoDB_row_lock狀態(tài)變量來(lái)分析系統上的行鎖的爭奪情況。

mysql> show status like 'innodb_row_lock%';

| Variable_name                 | Value |

| InnoDB_row_lock_current_waits | 0     |

| InnoDB_row_lock_time          | 0     |

| InnoDB_row_lock_time_avg      | 0     |

| InnoDB_row_lock_time_max      | 0     |

| InnoDB_row_lock_waits         | 0     |

5 rows in set (0.01 sec)

如果發(fā)現鎖爭用比較嚴重,如InnoDB_row_lock_waits 和 InnoDB_row_lock_time_avg的值比較高,還可以通過(guò)設置InnoDB Monitors來(lái)進(jìn)一步觀(guān)察發(fā)生鎖沖突的表、數據行等,并分析鎖爭用的原因。

具體方法如下:

mysql> CREATE TABLE innodb_monitor(a INT) ENGINE=INNODB;

Query OK, 0 rows affected (0.14 sec)

然后就可以用下面的語(yǔ)句來(lái)進(jìn)行查看:

mysql> Show innodb status\G;

監視器可以通過(guò)發(fā)出下列語(yǔ)句來(lái)停止查看:

mysql> DROP TABLE innodb_monitor;

Query OK, 0 rows affected (0.05 sec)

設置監視器后,在SHOW INNODB STATUS的顯示內容中,會(huì )有詳細的當前鎖等待的信息,包括表名、鎖類(lèi)型、鎖定記錄的情況等,便于進(jìn)行進(jìn)一步的分析和問(wèn)題的確定。打開(kāi)監視器以后,默認情況下每15秒會(huì )向日志中記錄監控的內容,如果長(cháng)時(shí)間打開(kāi)會(huì )導致.err文件變得非常的巨大,所以用戶(hù)在確認問(wèn)題原因之后,要記得刪除監控表以關(guān)閉監視器,或者通過(guò)使用“--console”選項來(lái)啟動(dòng)以關(guān)閉寫(xiě)日志文件。

5. InnoDB的行鎖模式及加鎖方法

InnoDB實(shí)現了以下兩種類(lèi)型的行鎖。

共享鎖(S):允許一個(gè)事務(wù)去讀一行,阻止其他事務(wù)獲得相同數據集的排他鎖。

排他鎖(X):允許獲得排他鎖的事務(wù)更新數據,阻止其他事務(wù)取得相同數據集的共享讀鎖和排他寫(xiě)鎖。

另外,為了允許行鎖和表鎖共存,實(shí)現多粒度鎖機制,InnoDB還有兩種內部使用的意向鎖(Intention Locks),

這兩種意向鎖都是表鎖。

意向共享鎖(IS):事務(wù)打算給數據行加行共享鎖,事務(wù)在給一個(gè)數據行加共享鎖前必須先取得該表的IS鎖。

意向排他鎖(IX):事務(wù)打算給數據行加行排他鎖,事務(wù)在給一個(gè)數據行加排他鎖前必須先取得該表的IX鎖。

如果一個(gè)事務(wù)請求的鎖模式與當前的鎖兼容,InnoDB就將請求的鎖授予該事務(wù);反之,如果兩者不兼容,該事務(wù)就要等待鎖釋放。

意向鎖是InnoDB自動(dòng)加的,不需用戶(hù)干預。

總結如下:

1.   對于UPDATE、DELETE和INSERT語(yǔ)句,InnoDB會(huì )自動(dòng)給涉及數據集加排他鎖(X);

2.  對于普通SELECT語(yǔ)句,InnoDB不會(huì )加任何鎖;

3.  事務(wù)可以通過(guò)以下語(yǔ)句顯示給記錄集加共享鎖或排他鎖。

共享鎖(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE。

排他鎖(X):SELECT * FROM table_name WHERE ... FOR UPDATE。

用SELECT ... IN SHARE MODE獲得共享鎖,主要用在需要數據依存關(guān)系時(shí)來(lái)確認某行記錄是否存在,并確保沒(méi)有人對這個(gè)記錄進(jìn)行UPDATE或者DELETE操作。

但是如果當前事務(wù)也需要對該記錄進(jìn)行更新操作,則很有可能造成死鎖,對于鎖定行記錄后需要進(jìn)行更新操作的應用,應該使用SELECT... FOR UPDATE方式獲得排他鎖。

6. InnoDB行鎖實(shí)現方式

InnoDB行鎖是通過(guò)給索引上的索引項加鎖來(lái)實(shí)現的,這一點(diǎn)MySQL與Oracle不同,后者是通過(guò)在數據塊中對相應數據行加鎖來(lái)實(shí)現的。

InnoDB這種行鎖實(shí)現特點(diǎn)意味著(zhù):只有通過(guò)索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖!

在實(shí)際應用中,要特別注意InnoDB行鎖的這一特性,不然的話(huà),可能導致大量的鎖沖突,從而影響并發(fā)性能。

(1) 在不通過(guò)索引條件查詢(xún)的時(shí)候,InnoDB確實(shí)使用的是表鎖,而不是行鎖。

(2)由于MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪(fǎng)問(wèn)不同行的記錄,

但是如果是使用相同的索引鍵,是會(huì )出現鎖沖突的。應用設計的時(shí)候要注意這一點(diǎn)。

(3)當表有多個(gè)索引的時(shí)候,不同的事務(wù)可以使用不同的索引鎖定不同的行,

另外,不論是使用主鍵索引、唯一索引或普通索引,InnoDB都會(huì )使用行鎖來(lái)對數據加鎖。

(4)即便在條件中使用了索引字段,但是否使用索引來(lái)檢索數據是由MySQL通過(guò)判斷不同執行計劃的代價(jià)來(lái)決定的,如果MySQL認為全表掃描效率更高,比如對一些很小的表,它就不會(huì )使用索引,這種情況下InnoDB將使用表鎖,而不是行鎖。因此,在分析鎖沖突時(shí),別忘了檢查SQL的執行計劃,以確認是否真正使用了索引。關(guān)于MySQL在什么情況下不使用索引的詳細討論,參見(jiàn)本章“索引問(wèn)題”一節的介紹。

7. 間隙鎖(Next-Key鎖)

當我們用范圍條件而不是相等條件檢索數據,并請求共享或排他鎖時(shí),InnoDB會(huì )給符合條件的已有數據記錄的索引項加鎖;對于鍵值在條件范圍內但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會(huì )對這個(gè)“間隙”加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)。假如emp表中只有101條記錄,其empid的值分別是 1,2,...,100,101 下面的SQL:

Select * from  emp where empid > 100 for update;

是一個(gè)范圍條件的檢索,InnoDB不僅會(huì )對符合條件的empid值為101的記錄加鎖,也會(huì )對empid大于101(這些記錄并不存在)的“間隙”加鎖。InnoDB使用間隙鎖的目的,一方面是為了防止幻讀,以滿(mǎn)足相關(guān)隔離級別的要求,對于上面的例子,要是不使用間隙鎖,如果其他事務(wù)插入了empid大于100的任何記錄,那么本事務(wù)如果再次執行上述語(yǔ)句,就會(huì )發(fā)生幻讀;另外一方面,是為了滿(mǎn)足其恢復和復制的需要。有關(guān)其恢復和復制對鎖機制的影響,以及不同隔離級別下InnoDB使用間隙鎖的情況,在后續的章節中會(huì )做進(jìn)一步介紹。

很顯然,在使用范圍條件檢索并鎖定記錄時(shí),InnoDB這種加鎖機制會(huì )阻塞符合條件范圍內鍵值的并發(fā)插入,這往往會(huì )造成嚴重的鎖等待。因此,在實(shí)際應用開(kāi)發(fā)中,尤其是并發(fā)插入比較多的應用,我們要盡量?jì)?yōu)化業(yè)務(wù)邏輯,盡量使用相等條件來(lái)訪(fǎng)問(wèn)更新數據,避免使用范圍條件。

特別說(shuō)明的是,InnoDB除了通過(guò)范圍條件加鎖時(shí)使用間隙鎖外,如果使用相等條件請求給一個(gè)不存在的記錄加鎖,InnoDB也會(huì )使用間隙鎖!

恢復和復制的需要,對InnoDB鎖機制的影響

MySQL通過(guò)BINLOG記錄執行成功的INSERT、UPDATE、DELETE等更新數據的SQL語(yǔ)句,并由此實(shí)現MySQL數據庫的恢復和主從復制。MySQL的恢復機制(復制其實(shí)就是在Slave Mysql不斷做基于BINLOG的恢復)有以下特點(diǎn)。

一是MySQL的恢復是SQL語(yǔ)句級的,也就是重新執行BINLOG中的SQL語(yǔ)句。這與Oracle數據庫不同,Oracle是基于數據庫文件塊的。

二是MySQL的BINLOG是按照事務(wù)提交的先后順序記錄的,恢復也是按這個(gè)順序進(jìn)行的。這點(diǎn)也與Oralce不同,Oracle是按照系統更新號(System Change Number,SCN)來(lái)恢復數據的,每個(gè)事務(wù)開(kāi)始時(shí),Oracle都會(huì )分配一個(gè)全局唯一的SCN,SCN的順序與事務(wù)開(kāi)始的時(shí)間順序是一致的。

從上面兩點(diǎn)可知,MySQL的恢復機制要求:在一個(gè)事務(wù)未提交前,其他并發(fā)事務(wù)不能插入滿(mǎn)足其鎖定條件的任何記錄,也就是不允許出現幻讀,這已經(jīng)超過(guò)了ISO/ANSI SQL92“可重復讀”隔離級別的要求,實(shí)際上是要求事務(wù)要串行化。

另外,對于“insert  into target_tab select * from source_tab where ...”和“create  table new_tab ...select ... From  source_tab where ...(CTAS)”這種SQL語(yǔ)句,用戶(hù)并沒(méi)有對source_tab做任何更新操作,但MySQL對這種SQL語(yǔ)句做了特別處理。

(這里InnoDB卻給source_tab加了共享鎖,并沒(méi)有使用多版本數據一致性讀技術(shù)?。? 

在上面的例子中,只是簡(jiǎn)單地讀 source_tab表的數據,相當于執行一個(gè)普通的SELECT語(yǔ)句,用一致性讀就可以了。ORACLE正是這么做的,它通過(guò)MVCC技術(shù)實(shí)現的多版本數據來(lái)實(shí)現一致性讀,不需要給source_tab加任何鎖。我們知道InnoDB也實(shí)現了多版本數據,對普通的SELECT一致性讀,也不需要加任何鎖;但這里InnoDB卻給source_tab加了共享鎖,并沒(méi)有使用多版本數據一致性讀技術(shù)!

MySQL為什么要這么做呢?其原因還是為了保證恢復和復制的正確性。因為不加鎖的話(huà),如果在上述語(yǔ)句執行過(guò)程中,其他事務(wù)對source_tab做了更新操作,就可能導致數據恢復的結果錯誤。為了演示這一點(diǎn),我們再重復一下前面的例子,不同的是在session_1執行事務(wù)前,先將系統變量 innodb_locks_unsafe_for_binlog的值設置為“on”(其默認值為off)

從上可見(jiàn),設置系統變量innodb_locks_unsafe_for_binlog的值為“on”后,InnoDB不再對source_tab加鎖,結果也符合應用邏輯,但是如果分析BINLOG的內容:

SET TIMESTAMP=1169175130;

BEGIN;

# at 274

#070119 10:51:57 server id 1  end_log_pos 105   Query   thread_id=1     exec_time=0     error_code=0

SET TIMESTAMP=1169175117;

update source_tab set name = '8' where name = '1';

# at 379

#070119 10:52:10 server id 1  end_log_pos 406   Xid = 5

COMMIT;

# at 406

#070119 10:52:14 server id 1  end_log_pos 474   Query   thread_id=2     exec_time=0     error_code=0

SET TIMESTAMP=1169175134;

BEGIN;

# at 474

#070119 10:51:29 server id 1  end_log_pos 119   Query   thread_id=2     exec_time=0     error_code=0

SET TIMESTAMP=1169175089;

insert into target_tab select d1,name from source_tab where name = '1';

# at 593

#070119 10:52:14 server id 1  end_log_pos 620   Xid = 7

COMMIT;

可以發(fā)現,在BINLOG中,更新操作的位置在INSERT...SELECT之前,如果使用這個(gè)BINLOG進(jìn)行數據庫恢復,恢復的結果與實(shí)際的應用邏輯不符;如果進(jìn)行復制,就會(huì )導致主從數據庫不一致!

因此,INSERT...SELECT...和 CREATE TABLE...SELECT...語(yǔ)句,可能會(huì )阻止對源表的并發(fā)更新,造成對源表鎖的等待。如果查詢(xún)比較復雜的話(huà),會(huì )造成嚴重的性能問(wèn)題,我們在應用中應盡量避免使用。實(shí)際上,MySQL將這種SQL叫作不確定(non-deterministic)的SQL,不推薦使用。

如果應用中一定要用這種SQL來(lái)實(shí)現業(yè)務(wù)邏輯,又不希望對源表的并發(fā)更新產(chǎn)生影響,可以采取以下兩種措施:

一是采取上面示例中的做法,將innodb_locks_unsafe_for_binlog的值設置為“on”,強制MySQL使用多版本數據一致性讀。但付出的代價(jià)是可能無(wú)法用binlog正確地恢復或復制數據,因此,不推薦使用這種方式。

二是通過(guò)使用“select * from source_tab ... Into outfile”和“l(fā)oad data infile ...”語(yǔ)句組合來(lái)間接實(shí)現,采用這種方式MySQL不會(huì )給source_tab加鎖。

8. InnoDB在不同隔離級別下的一致性讀及鎖的差異

前面講過(guò),鎖和多版本數據是InnoDB實(shí)現一致性讀和ISO/ANSI SQL92隔離級別的手段,因此,在不同的隔離級別下,InnoDB處理SQL時(shí)采用的一致性讀策略和需要的鎖是不同的。同時(shí),數據恢復和復制機制的特點(diǎn),也對一些SQL的一致性讀策略和鎖策略有很大影響。將這些特性歸納成如表20-16所示的內容,以便讀者查閱。

1: 在隔離級別是RC情況下,間隙鎖是用不到的,官方文檔說(shuō)明如下:

Each consistent read, even within the same transaction, sets and reads its own fresh snapshot. For information about consistent reads, see Section 14.8.2.3, “Consistent Nonlocking Reads”.

For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE statements, and DELETE statements, InnoDB locks only index records, not the gaps before them, and thus permits the free insertion of new records next to locked records. Gap locking is only used for foreign-key constraint checking and duplicate-key checking.

官方文檔說(shuō)明地址為:https://dev.mysql.com/doc/refman/5.5/en/innodb-transaction-isolation-levels.html

2: 在可重復讀隔離級別下,如果索引是唯一的,且查找也是唯一的,則也不用間隙鎖,否則就用間隙鎖,官方說(shuō)明如下:

REPEATABLE READ

This is the default isolation level for InnoDB. Consistent reads within the same transaction read the snapshot established by the first read. This means that if you issue several plain (nonlocking) SELECT statements within the same transaction, theseSELECT statements are consistent also with respect to each other. See Section 14.8.2.3, “Consistent Nonlocking Reads”.

For locking reads (SELECT with FOR UPDATE or LOCK IN SHARE MODE), UPDATE, and DELETE statements, locking depends on whether the statement uses a unique index with a unique search condition, or a range-type search condition.

For a unique index with a unique search condition, InnoDB locks only the index record found, not the gap before it.

For other search conditions, InnoDB locks the index range scanned, using gap locks or next-key locks to block insertions by other sessions into the gaps covered by the range. For information about gap locks and next-key locks, see Section 14.8.1, “InnoDB Locking”.

官方文檔說(shuō)明地址為:https://dev.mysql.com/doc/refman/5.5/en/innodb-transaction-isolation-levels.html

9.什么時(shí)候使用表鎖?

對于InnoDB表,在絕大部分情況下都應該使用行級鎖,因為事務(wù)和行鎖往往是我們之所以選擇InnoDB表的理由。但在個(gè)別特殊事務(wù)中,也可以考慮使用表級鎖。

第一種情況是:事務(wù)需要更新大部分或全部數據,表又比較大,如果使用默認的行鎖,不僅這個(gè)事務(wù)執行效率低,而且可能造成其他事務(wù)長(cháng)時(shí)間鎖等待和鎖沖突,這種情況下可以考慮使用表鎖來(lái)提高該事務(wù)的執行速度。

第二種情況是:事務(wù)涉及多個(gè)表,比較復雜,很可能引起死鎖,造成大量事務(wù)回滾。這種情況也可以考慮一次性鎖定事務(wù)涉及的表,從而避免死鎖、減少數據庫因事務(wù)回滾帶來(lái)的開(kāi)銷(xiāo)。

當然,應用中這兩種事務(wù)不能太多,否則,就應該考慮使用MyISAM表了。

在InnoDB下,使用表鎖要注意以下兩點(diǎn)。

(1)使用LOCK TABLES雖然可以給InnoDB加表級鎖,但必須說(shuō)明的是,表鎖不是由InnoDB存儲引擎層管理的,而是由其上一層: MySQL Server負責的,僅當autocommit=0、innodb_table_locks=1(默認設置)時(shí),InnoDB層才能知道MySQL加的表鎖,MySQL Server也才能感知InnoDB加的行鎖,這種情況下,InnoDB才能自動(dòng)識別涉及表級鎖的死鎖;否則,InnoDB將無(wú)法自動(dòng)檢測并處理這種死鎖。有關(guān)死鎖,下一小節還會(huì )繼續討論。

(2)在用 LOCK TABLES對InnoDB表加鎖時(shí)要注意,要將AUTOCOMMIT設為0,否則MySQL不會(huì )給表加鎖;事務(wù)結束前,不要用UNLOCK TABLES釋放表鎖,因為UNLOCK TABLES會(huì )隱含地提交事務(wù);COMMIT或ROLLBACK并不能釋放用LOCK TABLES加的表級鎖,必須用UNLOCK TABLES釋放表鎖。正確的方式見(jiàn)如下語(yǔ)句.

例如,如果需要寫(xiě)表t1并從表t讀,可以按如下做:

SET AUTOCOMMIT=0;

LOCK TABLES t1 WRITE, t2 READ, ...;

[do something with tables t1 and t2 here];

COMMIT;

UNLOCK TABLES;

10.關(guān)于死鎖

上文講過(guò),MyISAM表鎖是deadlock free的,這是因為MyISAM總是一次獲得所需的全部鎖,要么全部滿(mǎn)足,要么等待,因此不會(huì )出現死鎖。但在InnoDB中,除單個(gè)SQL組成的事務(wù)外,鎖是逐步獲得的,這就決定了在InnoDB中發(fā)生死鎖是可能的。如表20-17所示的就是一個(gè)發(fā)生死鎖的例子。

在上面的例子中,兩個(gè)事務(wù)都需要獲得對方持有的排他鎖才能繼續完成事務(wù),這種循環(huán)鎖等待就是典型的死鎖。

發(fā)生死鎖后,InnoDB一般都能自動(dòng)檢測到,并使一個(gè)事務(wù)釋放鎖并回退,另一個(gè)事務(wù)獲得鎖,繼續完成事務(wù)。但在涉及外部鎖,或涉及表鎖的情況下,InnoDB并不能完全自動(dòng)檢測到死鎖,這需要通過(guò)設置鎖等待超時(shí)參數innodb_lock_wait_timeout來(lái)解決。需要說(shuō)明的是,這個(gè)參數并不是只用來(lái)解決死鎖問(wèn)題,在并發(fā)訪(fǎng)問(wèn)比較高的情況下,如果大量事務(wù)因無(wú)法立即獲得所需的鎖而掛起,會(huì )占用大量計算機資源,造成嚴重性能問(wèn)題,甚至拖跨數據庫。我們通過(guò)設置合適的鎖等待超時(shí)閾值,可以避免這種情況發(fā)生。

通常來(lái)說(shuō),死鎖都是應用設計的問(wèn)題,通過(guò)調整業(yè)務(wù)流程、數據庫對象設計、事務(wù)大小,以及訪(fǎng)問(wèn)數據庫的SQL語(yǔ)句,絕大部分死鎖都可以避免。

下面就通過(guò)實(shí)例來(lái)介紹幾種避免死鎖的常用方法。

(1)在應用中,如果不同的程序會(huì )并發(fā)存取多個(gè)表,應盡量約定以相同的順序來(lái)訪(fǎng)問(wèn)表,這樣可以大大降低產(chǎn)生死鎖的機會(huì )。在下面的例子中,由于兩個(gè)session訪(fǎng)問(wèn)兩個(gè)表的順序不同,發(fā)生死鎖的機會(huì )就非常高!但如果以相同的順序來(lái)訪(fǎng)問(wèn),死鎖就可以避免。

(2)在程序以批量方式處理數據的時(shí)候,如果事先對數據排序,保證每個(gè)線(xiàn)程按固定的順序來(lái)處理記錄,也可以大大降低出現死鎖的可能。

(3)在事務(wù)中,如果要更新記錄,應該直接申請足夠級別的鎖,即排他鎖,而不應先申請共享鎖,更新時(shí)再申請排他鎖,因為當用戶(hù)申請排他鎖時(shí),其他事務(wù)可能又已經(jīng)獲得了相同記錄的共享鎖,從而造成鎖沖突,甚至死鎖。具體演示可參見(jiàn)20.3.3小節中的例子。

(4)前面講過(guò),在REPEATABLE-READ隔離級別下,如果兩個(gè)線(xiàn)程同時(shí)對相同條件記錄用SELECT...FOR UPDATE加排他鎖,在沒(méi)有符合該條件記錄情況下,兩個(gè)線(xiàn)程都會(huì )加鎖成功。程序發(fā)現記錄尚不存在,就試圖插入一條新記錄,如果兩個(gè)線(xiàn)程都這么做,就會(huì )出現死鎖。這種情況下,將隔離級別改成READ COMMITTED,就可避免問(wèn)題。

(5)當隔離級別為READ COMMITTED時(shí),如果兩個(gè)線(xiàn)程都先執行SELECT...FOR UPDATE,判斷是否存在符合條件的記錄,如果沒(méi)有,就插入記錄。此時(shí),只有一個(gè)線(xiàn)程能插入成功,另一個(gè)線(xiàn)程會(huì )出現鎖等待,當第1個(gè)線(xiàn)程提交后,第2個(gè)線(xiàn)程會(huì )因主鍵重出錯,但雖然這個(gè)線(xiàn)程出錯了,卻會(huì )獲得一個(gè)排他鎖!這時(shí)如果有第3個(gè)線(xiàn)程又來(lái)申請排他鎖,也會(huì )出現死鎖。

對于這種情況,可以直接做插入操作,然后再捕獲主鍵重異常,或者在遇到主鍵重錯誤時(shí),總是執行ROLLBACK釋放獲得的排他鎖。

盡管通過(guò)上面介紹的設計和SQL優(yōu)化等措施,可以大大減少死鎖,但死鎖很難完全避免。因此,在程序設計中總是捕獲并處理死鎖異常是一個(gè)很好的編程習慣。

如果出現死鎖,可以用SHOW INNODB STATUS命令來(lái)確定最后一個(gè)死鎖產(chǎn)生的原因。返回結果中包括死鎖相關(guān)事務(wù)的詳細信息,如引發(fā)死鎖的SQL語(yǔ)句,事務(wù)已經(jīng)獲得的鎖,正在等待什么鎖,以及被回滾的事務(wù)等。據此可以分析死鎖產(chǎn)生的原因和改進(jìn)措施。

下面是一段SHOW INNODB STATUS輸出的樣例:

mysql> show innodb status \G

InnoDB 小結

本章重點(diǎn)介紹了MySQL中MyISAM表級鎖和InnoDB行級鎖的實(shí)現特點(diǎn),并討論了兩種存儲引擎經(jīng)常遇到的鎖問(wèn)題和解決辦法。

對于MyISAM的表鎖,主要討論了以下幾點(diǎn):

(1)共享讀鎖(S)之間是兼容的,但共享讀鎖(S)與排他寫(xiě)鎖(X)之間,以及排他寫(xiě)鎖(X)之間是互斥的,也就是說(shuō)讀和寫(xiě)是串行的。

(2)在一定條件下,MyISAM允許查詢(xún)和插入并發(fā)執行,我們可以利用這一點(diǎn)來(lái)解決應用中對同一表查詢(xún)和插入的鎖爭用問(wèn)題。

(3)MyISAM默認的鎖調度機制是寫(xiě)優(yōu)先,這并不一定適合所有應用,用戶(hù)可以通過(guò)設置LOW_PRIORITY_UPDATES參數,或在INSERT、UPDATE、DELETE語(yǔ)句中指定LOW_PRIORITY選項來(lái)調節讀寫(xiě)鎖的爭用。

(4)由于表鎖的鎖定粒度大,讀寫(xiě)之間又是串行的,因此,如果更新操作較多,MyISAM表可能會(huì )出現嚴重的鎖等待,可以考慮采用InnoDB表來(lái)減少鎖沖突。

對于InnoDB表,本章主要討論了以下幾項內容。

InnoDB的行鎖是基于鎖引實(shí)現的,如果不通過(guò)索引訪(fǎng)問(wèn)數據,InnoDB會(huì )使用表鎖。

介紹了InnoDB間隙鎖(Next-key)機制,以及InnoDB使用間隙鎖的原因。

在不同的隔離級別下,InnoDB的鎖機制和一致性讀策略不同。

MySQL的恢復和復制對InnoDB鎖機制和一致性讀策略也有較大影響。

鎖沖突甚至死鎖很難完全避免。

在了解InnoDB鎖特性后,用戶(hù)可以通過(guò)設計和SQL調整等措施減少鎖沖突和死鎖,包括:

盡量使用較低的隔離級別;

精心設計索引,并盡量使用索引訪(fǎng)問(wèn)數據,使加鎖更精確,從而減少鎖沖突的機會(huì )。

選擇合理的事務(wù)大小,小事務(wù)發(fā)生鎖沖突的幾率也更小。

給記錄集顯示加鎖時(shí),最好一次性請求足夠級別的鎖。比如要修改數據的話(huà),最好直接申請排他鎖,而不是先申請共享鎖,修改時(shí)再請求排他鎖,這樣容易產(chǎn)生死鎖。

不同的程序訪(fǎng)問(wèn)一組表時(shí),應盡量約定以相同的順序訪(fǎng)問(wèn)各表,對一個(gè)表而言,盡可能以固定的順序存取表中的行。這樣可以大大減少死鎖的機會(huì )。

盡量用相等條件訪(fǎng)問(wèn)數據,這樣可以避免間隙鎖對并發(fā)插入的影響。

不要申請超過(guò)實(shí)際需要的鎖級別;除非必須,查詢(xún)時(shí)不要顯示加鎖。

對于一些特定的事務(wù),可以使用表鎖來(lái)提高處理速度或減少死鎖的可能。

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。

国产精品VA在线播放我和闺蜜| 久久久中文久久久无码| 未成满18禁止免费无码网站| 婷婷国产成人精品视频| 内射后入在线观看一区| 中文无码日韩欧AV影视|