創新互聯建站專業為企業提供尚志網站建設、尚志做網站、尚志網站設計、尚志網站制作等企業網站建設、網頁設計與制作、尚志企業網站模板建站服務,十多年尚志做網站經驗,不只是建網站,更提供有價值的思路和整體網絡服務。
鎖是計算機協調多個進程或純線程并發訪問某一資源的機制。
在數據庫中,除傳統的計算資源(CPU、RAM、I/O)的爭用以外,數據也是一種供許多用戶共享的資源。
如何保證數據并發訪問的一致性、有效性是所在有數據庫必須解決的一個問題,鎖沖突也是影響數據庫并發訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加復雜。
使用數據庫,避免不了并發問題,當并發事務同時訪問一個資源時,有可能導致數據不一致,因此需要一種機制來將數據訪問順序化,以保證數據庫數據的一致性。
鎖就是其中的一種機制。
我們可以用公廁做個比喻。
公廁是可供多個消費者使用的,因此可能出現多個人同時需要使用廁所的情況。
但是,廁所只有一個,總不能大家一起吧?
為了避免沖突,于是廁所里裝了鎖,某一個人在上測試時,可以在里面用鎖鎖住,其他人就不能再從外面打開了,只能等待。
等里面的人出來了,從里面把鎖打開,外面的人才能進去。
下面,帶你一起梳理下 MySQL 的鎖管理機制和鎖的執行流程,先有一個大致的脈絡。
1、全局讀鎖 — FLUSH TABLES WITH READ LOCK(SQL層)
2、表級 table-level 數據鎖(SQL層)
3、Meta-data 元數據鎖:在 table cache 緩存里實現的,為 DDL(Data Definition Language)提供隔離操作。
4、存儲引擎特有機制 — row locks行鎖,page locks頁鎖,table locks表級,版本控制(在引擎中實現)
相對其他數據庫而言,MySQL 的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。
1、計算語句使用到的所有表;
2、在每個表:打開表,從 table cache 緩存里得到 TABLE 對象,并在此表加上 meta-data 元數據鎖;
3、等待全局讀鎖后改變數據;
4、在每個表:鎖表,在表加上 table-level 數據鎖;
5、執行語句:調用:handler::write_row()/read_rnd()/read_index() 等;隱式地調用引擎級 engine-level 鎖機制;
6、在每個表:釋放表的數據鎖;
7、在每個表:釋放表的 DDL 鎖并把表放回 table cache 緩存里;
下面,我們開始簡單針對每一種鎖,看下都有什么特點。
加了全局鎖后,整個庫變為只讀狀態,所有的寫操作都會被阻塞,包括:
數據的增刪改
表結構的創建、修改
更新事務
加全局鎖的命令:Flush tables with read lock
,即 FTWRL。
全局鎖的主要使用場景是全庫的邏輯備份,加了全局鎖進行備份時有一定的使用風險:
1、若在主庫備份,備份期間只讀,會影響業務;
2、若在從庫備份,從庫只讀,無法及時同步主可以的更新,造成主從不一致;
也許你還記得,我們在之前講事務的時候,有一個隔離級別叫做可重復讀,也就是設置了隔離級別進入事務后,別的事務更改數據不會影響當前的讀取。
使用 mysqldump 命令,結合 --single-transaction
參數,可以將隔離級別設置為:REPEATABLE READ。
并且隨后再執行一條 START TRANSACTION 語句,讓整個數據在 dump 過程中保證數據的一致性,這個選項對 InnoDB 的數據表很有用,且不會鎖表。
為了確保使用 --single-transaction 命令時,最終 dump 文件的有效性。需沒有下列語句 ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE,因為一致性讀不能隔離上述語句。所以如果在 dump 過程中,使用上述語句,可能會導致 dump 出來的文件數據不一致或者不可用。
為啥不直接使用 mysqldump --single-transaction 來備份?
因為,有些引擎不支持事務啊,比如 MyISAM 引擎,所以,現在大家都在力推用 InnoDB 替代 MyISAM。
set global readonly=true
也可以將全局表設為只讀狀態,有啥區別呢?
首先,修改 global 變量的方式影響面更大,不建議使用。
另外,異常處理機制上和 FTWRL 有差異:
FTWRL 命令:客戶端異常斷開,MySQL 會自動釋放全局鎖,整個庫回到正常更新的狀態
readonly 狀態下,客戶端發生異常,數據庫會一直保持 readonly 狀態,導致整個庫長時間處于不可寫狀態
FTWRL 前有讀寫的話 ,FTWRL 都會等待讀寫執行完畢后才執行
FTWRL 執行的時候要刷臟頁的數據到磁盤,要保持數據的一致性
執行 FTWRL 時候會等待所有事務都提交完畢
語法
LOCK TABLES tbl_name ; # 不影響其他表的寫操作
解鎖也是:
UNLOCK TABLES;
注意點:
這兩個語句在執行的時候都需要注意個特點,就是隱式提交的語句,在退出 mysql 終端的時候都會隱式的自動執行 unlock tables,也就是如果要讓表鎖定生效就必須一直保持對話。
lock tables 除了會限制別的線程的讀寫外,也會限制本線程接下來的操作對象
鎖住整個表的影響面較大
P.S. MYSQL 的 read lock 和 wirte lock
read-lock:允許其他并發的讀請求,但阻塞寫請求,即可以同時讀,但不允許任何寫,也叫共享鎖
write-lock:不允許其他并發的讀和寫請求,是排他的(exclusive),也叫獨占鎖
元數據鎖不需要顯式使用,在訪問一個表的時候會自動加上。
它的作用主要是保證讀寫的正確性。
表的增刪改查操作,需要先加 MDL 讀鎖;
表結構變更操作,需要先加 MDL 寫鎖
MDL 讀鎖之間不互斥,多個線程可以同時對一張表增刪改查。
MDL 讀寫鎖之間、寫鎖之間是互斥的,用來保證變更表結構操作的安全性。
如果有兩個線程要同時給一個表加字段,其中一個要等另一個執行完才能開始執行。
事務中的 MDL 鎖,在語句執行開始時申請,但是語句結束后并不會馬上釋放,而會等到整個事務提交后再釋放。
因此,需要避免長事務,因為長事務會造成鎖一直不能釋放,后續的操作會堆積,這個庫的線程很快就會爆滿。
行鎖是引擎層實現的,像 MyISAM 引擎就直接不支持行鎖,這些引擎在并發控制只能用表鎖!
兩階段協議:
需要的時候加上
事務結束時釋放
當需要鎖多個行時,盡量把影響并發的鎖往后放,這樣可以最大程度的減少事務之間的鎖等待,提升并發度。
另外,InnoDB 的 行鎖建立在索引的基礎上,鎖的是索引。因此,如果更新的列沒建索引會鎖住整個表。
不同線程出現循環資源依賴,涉及的線程都在等待別的線程釋放資源。
死鎖對策
1、主動等待超時,由參數 innodb_lock_wait_timeout
設置,但是業務無法等待;
2、主動死鎖檢測(innodb_deadlock_detect=on
)
發生死鎖后,InnoDB 一般都可以檢測到,并使一個事務釋放鎖回退,另一個則可以獲取鎖完成事務。
另外,我們可以采取以下方式避免死鎖:
通過表級鎖來減少死鎖產生的概率;
多個程序盡量約定以相同的順序訪問表(這也是解決并發理論中哲學家就餐問題的一種思路);
同一個事務盡可能做到一次鎖定所需要的所有資源。
另外,死鎖檢測也非常耗費資源,判斷會不會由于自己的加入導致了死鎖,這是一個時間復雜度是 O(n) 的操作。
比如有 1000 個并發線程要同時更新同一行,那么死鎖檢測操作就是 100 萬這個量級的,這將消耗大量的 CPU 資源。
如何解決死鎖檢測耗費資源的情況?
1、關掉死鎖檢測,需要保證不會發生死鎖;
2、控制并發,對應相同行的更新,在進入引擎之前排隊;
數據庫服務端實現,中間件實現
不要在客戶端實現,因為客戶端的數量未知
改 MySQL 源碼
將熱更新的行數據拆分成邏輯上的多行來減少鎖沖突,但是業務復雜度可能會大大提高
引擎支持行鎖就行鎖,比如 innodb;
引擎不支持行鎖就表鎖,比如 myisam;
在 MySQL5.6 中,開始支持更多的 alter table 類型操作來避免 copy data,同時支持了在線上 DDL 的過程中不阻塞 DML 操作,真正意義上的實現了 Online DDL。
1、拿 MDL 寫鎖
2、降級成 MDL 讀鎖
3、真正做 DDL
4、升級成 MDL 寫鎖
5、釋放 MDL 鎖
1、2、4、5 如果沒有鎖沖突,執行時間非常短。
第 3 步占用了 DDL 絕大部分時間,這期間這個表可以正常讀寫數據,是因此稱為「online」
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的概率最高,并發度最低。
這些存儲引擎通過總是一次性同時獲取所有需要的鎖以及總是按相同的順序獲取表鎖來避免死鎖。
表級鎖更適合于以查詢為主,并發用戶少,只有少量按索引條件更新數據的應用,如 Web 應用
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的概率最低,并發度也最高。
最大程度的支持并發,同時也帶來了最大的鎖開銷。
在 InnoDB 中,除單個 SQL 組成的事務外,鎖是逐步獲得的,這就決定了在 InnoDB 中發生死鎖是可能的。
行級鎖只在存儲引擎層實現,而 Mysql 服務器層沒有實現。
行級鎖更適合于有大量按索引條件并發更新少量不同數據,同時又有并發查詢的應用,如一些在線事務處理(OLTP)系統
上述特點來看,很難說哪種鎖更好,只能相對于所處的業務場景來選擇更加適合的鎖機制。
如果僅從鎖的角度來看,表級鎖更適合以查詢為主的應用場景,而行級鎖則更適合于大量按索引條件并發更新少量數據的應用場景。
對于平時常用的存儲引擎,MyISAM 采用的是表級鎖,InnoDB 采用的是行級鎖加表級鎖。
參考:
https://dwz.cn/oudQ7cM9
分享題目:MySQL實戰|06/07簡單說說MySQL中的鎖
標題URL:http://www.2m8n56k.cn/article22/pdiecc.html
成都網站建設公司_創新互聯,為您提供App設計、外貿建站、外貿網站建設、手機網站建設、關鍵詞優化、域名注冊
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:[email protected]。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯