<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MySQL的鎖

      1、MySQL的鎖的基本介紹

      鎖是計算機協調多個進程或線程并發訪問某一資源的機制。在數據庫中,除傳統的計算資源(如CPU、RAM、I/O等)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據并發訪問的一致性、有效性是所有數據庫必須解決的一個問題,鎖沖突也是影響數據庫并發訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加復雜。

      相對其他數據庫而言,MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。

      (InnoDB 存儲引擎(MySQL 默認存儲引擎,默認可重復讀隔離級別)中)數據庫事務的鎖是執行某語句時就會加鎖,而且只有當整個事務完成(提交或回滾)后,鎖(排他行鎖、共享行鎖等等)才會被釋放。例如,有一個事務 T1,在其中執行了UPDATE users SET user_email = 'new_email@example.com' WHERE user_id = 1001。當這條UPDATE語句執行后,排他行鎖就會鎖住user_id = 1001對應的行。即使UPDATE語句執行完成,只要事務 T1 還沒有提交或者回滾,這個排他行鎖就會一直存在。

       

      1.1、數據庫鎖的分類

      MySQL 的鎖按照范圍可以分為全局鎖(對整個數據庫實例進行加鎖)、表鎖、行鎖,其中行鎖是由數據庫引擎實現的,并不是所有的引擎都提供行鎖,MyISAM 就不支持行鎖。

      從對數據操作的類型:

      • 共享鎖(讀鎖):針對同一行數據,多個讀操作可以同時進行而不會互相影響,但會阻塞寫操作。
      • 排它鎖(寫鎖):當前寫操作沒有完成前,它會阻斷其他會話的寫和讀。

      共享鎖會阻塞涉及到的數據的寫,但是不會堵塞讀;而排它鎖則會把涉及到的數據的讀和寫都堵塞。也就是共享鎖和排它鎖都會阻塞涉及到的數據的寫操作。

       

      從對數據操作的粒度分:

      • 表級鎖:開銷小,加鎖快;鎖定粒度大,發生鎖沖突的概率最高,并發度最低。
      • 行級鎖:開銷大,加鎖慢;鎖定粒度最小,發生鎖沖突的概率最低,并發度也最高。
      • 頁面鎖:開銷和加鎖時間界于表鎖和行鎖之間;鎖定粒度界于表鎖和行鎖之間,并發度一般

       

      2、表級鎖(共享鎖、排它鎖)

      2.1、表級鎖的分類

      2.1.1、共享表鎖(讀鎖,其他會話對該表無法增刪改)

      假設有會話 A 和 會話 B,會話 A 對 mylock 表加了讀鎖,則:

      • 會話A :可以查該表的數據,但是無法增刪改該表的數據,并且也無法查詢其他表的數據,即使其他表未被鎖定也無法查詢,直到對該鎖表進行釋放鎖。
      • 會話B :可以查詢該鎖表的數據,也可以查詢、增刪改其他表的數據。但是在對已鎖的數據進行增刪改時,會一直阻塞,導致SQL無法執行結束,直到該表鎖被釋放后,SQL會自動執行結束。
        已鎖定表 其他表
      會話A(加鎖的會話) 可查;但無法增刪改 無法增刪改查(會報錯)
      其他會話 可查;但無法增刪改(會一直阻塞) 可增刪改查 

      也就是加共享鎖的會話可以查鎖表數據,但加鎖會話無法增刪改該表,也無法查詢其他表。其他的會話可以查詢任何表的數據,但其他會話對鎖表進行增刪改時也會阻塞,直到鎖表的鎖被釋放。

      總結:共享鎖會阻塞寫,不會阻塞讀。

       

      2.1.2、排它表鎖(寫鎖,其他會話對該表無法增刪改查)

      假設有會話 A 和 會話 B,會話 A 對 mylock 表加了寫鎖,則:

      • 會話A :可以查該表的數據,也可以對該鎖定表進行增刪改,但是無法查詢其他表的數據,即使其他表未被鎖定也無法查詢,直到對已鎖定表進行釋放鎖。
      • 會話B :對已鎖定表進行增刪改查都會一直阻塞,直到該表鎖被釋放??梢詫ζ渌磉M行增刪改查。
        已鎖定表  其他表
       會話A(加鎖的會話)  可增刪改查  無法增刪改查(會報錯)
      其他會話 無法增刪改查(會一直阻塞) 可增刪改查

      也就是加排它鎖的會話可以增刪改查鎖定表的數據,但加鎖會話無法查詢其他表。其他的會話對鎖定表進行增刪改查時會一直阻塞,直到鎖表的鎖被釋放,但可以增刪改查其他表的數據。

      總結:寫鎖會阻塞其他會話的讀和寫。

       

      2.2、表級鎖之MyISAM 引擎表的讀寫操作和鎖

      MyISAM 存儲引擎在執行查詢語句(select)時,會自動給涉及的所有表都加上共享鎖,在執行增刪改操作前,會自動給涉及到的所有表都加上排它鎖。

      所以對 MyISAM 表進行操作,會有以下情況:

      • 對 MyISAM 表進行讀操作時(會自動加共享鎖):不會阻塞其他進程對同一表的讀請求,但會阻塞對同一表的寫請求。只有當讀鎖釋放后,才會執行其它進程的寫操作。
      • 對 MyISAM 表進行寫操作時〈會自動加排它鎖):會阻塞其他進程對同一表的讀和寫操作,只有當寫鎖釋放后,才會執行其它進程對該表的讀寫操作。
      簡而言之,就是讀鎖會阻塞涉及到的表的寫,但是不會堵塞讀;而寫鎖則會把涉及到的表的讀和寫都堵塞。

       

      MyISAM 的讀寫鎖調度是寫優先,這也是 MyISAM 不適合做寫為主的表的引擎的原因。因為寫操作會自動加寫鎖,加鎖后其他線程就沒辦法做任何操作,大量的寫操作會使查詢很難得到鎖,從而造成永遠阻塞。

       

      2.3、表級鎖的相關SQL語句

      2.3.1、查看被鎖定的表

      可以通過以下命令來查看哪些表被鎖定:

      show open tables;

      結果示例如下:

      結果說明如下:

      • Database:含有該表的數據庫
      • Table:表名稱
      • In_use:表當前被查詢使用的次數。如果該數為零,則表是打開的,即當前沒有鎖表。如果該列的值大于 0,則表示表正在被使用,有可能被鎖住。
      • Name_locked:表名稱是否被鎖定。名稱鎖定用于取消表或對表進行重命名等操作

       

      在 MySQL 的 InnoDB 引擎中,information_schema.INNODB_LOCKS表存儲了當前 InnoDB 存儲引擎中存在的鎖信息。可以通過查詢這個表來確定表是否被鎖以及被何種鎖鎖住。

      SELECT * FROM information_schema.INNODB_LOCKS

      通過查詢結果可以看到哪些表被鎖住,并且可以看到鎖的類型(如行鎖、表鎖)、鎖定的事務 ID 等信息。

       

      2.3.2、給表加表級鎖

      可以使用以下命令給表加鎖:

      lock table 表名 read(write), 表名2 read(write), 其他;
      
      -- 示例
      lock table lock_table_test read, lock_table_test2 write;

      示例:

      先創建一個表 mylock:

      create table mylock (
          id int not null primary key auto_increment,
          name varchar(20) default ''
      ) engine myisam;
      
      insert into mylock(name) values('a');
      insert into mylock(name) values('b');
      insert into mylock(name) values('c');
      insert into mylock(name) values('d');
      insert into mylock(name) values('e');

      然后給該表加讀鎖:

      lock table mylock read;

      使用 show open tables; 來查看表鎖情況:

      可以看到,mydbtest.mylock 表已被鎖定。

       

      2.3.3、釋放表鎖

      釋放所有表的鎖:

      unlock tables;

       

      2.3.4、分析表鎖

      我們可以通過以下命令行來分析表鎖的情況:

      show status like 'table_locks%';

      結果示例:

      可以通過檢查 table_locks_waited(主要分析該值) 和 table_locks_immediate 狀態變量來分析系統上的表鎖定,說明如下:

      • table_locks_waited:出現表級鎖定爭用而發生等待的次數(也可以說是不能立即獲取鎖的次數,每觸發一次需等待鎖的SQL時該值就加1),此值高則說明存在著較嚴重的表級鎖爭用情況。
      • table_locks_immediate:產生表級鎖定的次數,表示可以立即獲取鎖的查詢次數,每立即獲取鎖值加1。

       

      3、行級鎖

      MyISAM 引擎支持表級鎖,但不支持行級鎖,InnoDB 引擎支持行級鎖和表級鎖。在默認的可重復讀隔離級別下,InnoDB 會盡量使用行級鎖(而不是表級鎖)和 MVCC(多版本并發控制)機制來保證事務的隔離性。

      在 MySQL 的 InnoDB 存儲引擎中,行級鎖的使用通常與索引密切相關。當通過索引條件來查詢和修改數據時,InnoDB 更傾向于使用行級鎖。這是因為索引能夠幫助數據庫快速定位到要操作的行,從而精確地對這些行加鎖。例如,在一個employees表中有employee_id索引,當執行UPDATE employees SET salary = salary * 1.1 WHERE employee_id = 1001這樣的更新操作時,InnoDB 可以通過employee_id索引快速找到employee_id = 1001對應的行,并對該行加排他行鎖(X 鎖),其他事務對這一行的讀寫操作(不符合 MVCC 機制下的可讀條件)就會被阻塞。

      當查詢或修改數據的條件沒有使用索引時,InnoDB 也有可能會升級為表鎖。這是因為如果沒有索引來定位行,為了保證操作的一致性和正確性,數據庫可能會選擇更粗粒度的鎖,即表鎖。例如,在employees表中,如果執行UPDATE employees SET department = 'New Dept' WHERE age > 30,假設age列沒有索引,InnoDB 可能會對整個employees表加表鎖。這樣做的原因是,在沒有索引的情況下,數據庫難以確定哪些行滿足條件,通過加表鎖可以防止其他事務對表進行不兼容的操作,確保當前事務能夠正確地完成更新操作。不過,這種行為也可能因 MySQL 的版本、配置參數以及具體的操作場景而有所不同。

       

      示例:

      下面建一張表,并且建立索引,因為只有通過索引來檢索數據,InnoDB 才會使用行級表。

      CREATE TABLE test_lock (a INT(11),b VARCHAR(16))ENGINE=INNODB;
      
      INSERT INTO test_lock VALUES(1,'b2');
      INSERT INTO test_lock VALUES(3,'3');
      INSERT INTO test_lock VALUES(4, '4000');
      INSERT INTO test_lock VALUES(5,'5000');
      INSERT INTO test_lock VALUES(6, '6000');
      INSERT INTO test_lock VALUES(7,'7000');
      INSERT INTO test_lock VALUES(8, '8000');
      INSERT INTO test_lock VALUES(9,'9000');
      INSERT INTO test_lock VALUES(1,'b1');
      
      -- 建立索引列
      CREATE INDEX test_lock_a_ind ON test_lock(a);
      CREATE INDEX test_lock_b_ind ON test_lock(b);

      建立兩個會話,并且設置不自動提交事務(這樣才能模擬出在一個事務內的情況,否則事務立馬提交就看不出效果了),先在 A 會話中對某一行數據進行修改但不提交,然后在 B 會話中也對同一行數據進行修改,如下:

          

      此時,會話 B 的修改會一直阻塞,直到 A 提交事務 commit,會話 B 的進程才能執行成功,否則會一直阻塞直到超時報錯,這就是加了行級鎖。

      當然,如果會話 B 修改其他行的數據則是不會受到影響的,因為行級鎖只會鎖定指定行的數據。而且如果只是查詢則沒問題,比如A只是查詢,則不會鎖行,或者A修改B查詢,則B的查詢不會受到影響。

       

      3.1、行級鎖的分類

      • 共享行鎖(Shared Row Lock,S,共享行鎖也稱為 S 鎖)

      定義與原理:共享行鎖用于對一行數據進行讀取操作時的并發控制。當一個事務對某一行數據加上共享行鎖(其實默認情況下普通查詢并不會加鎖)后,允許其他事務也對這一行加共享行鎖來讀取數據。但是,如果其他事務想要對這行數據進行修改,則需要獲取排他行鎖,此時事務會被阻塞,直到所有的共享行鎖都被釋放。這是基于并發讀取數據的需求,多個事務可以同時讀取同一行數據而不會相互干擾,只要它們都只進行讀取操作。

      應用場景和示例:以一個在線圖書閱讀平臺為例,多個用戶可能同時查看某一本書的詳細信息(如書名、作者、簡介等)。假設這些信息存儲在books表中的一行數據中,當用戶 A 的事務對這行數據加共享行鎖進行讀取時,用戶 B 的事務也可以對同一行數據加共享行鎖來讀取相同的信息。這樣可以滿足多個用戶同時獲取圖書信息的需求,并且在沒有寫操作介入時,不會產生沖突。但是,如果有一個事務想要對這行數據進行修改(如更新圖書簡介),則需要獲取排他行鎖,此時該事務會被阻塞,直到所有的共享行鎖都被釋放。

      • 排他行鎖(Exclusive Row Lock,X)

      定義與原理:排他行鎖用于對一行數據進行寫操作(如插入、更新、刪除)時的并發控制。當一個事務對某一行數據加上排他行鎖后,只有該事務能夠對這一行進行讀寫操作,其他事務不能對這一行加共享行鎖進行讀取,也不能加排他行鎖進行寫入,直到持有排他行鎖的事務完成并釋放鎖。這種鎖機制確保了在對數據進行修改時的獨占性,防止其他事務對正在修改的數據進行干擾,從而保證數據的準確性和完整性。

      應用場景和示例:在一個銀行賬戶管理系統中,當一個事務需要更新某個賬戶的余額時,它會對存儲該賬戶余額的行數據加上排他行鎖。例如,事務 A 要從賬戶 1 向賬戶 2 轉賬,事務 A 會對賬戶 1 和賬戶 2 余額所在的行分別加上排他行鎖。在事務 A 完成轉賬操作(包括更新兩個賬戶的余額并提交事務)之前,其他事務(如同時進行的另一個轉賬事務或者查詢賬戶余額的事務)對這兩個賬戶余額行的讀寫操作都會被阻塞。這樣可以確保轉賬操作的原子性,即要么全部完成,要么全部不做,避免數據不一致的情況出現。
       
      • 意向共享行鎖(Intention Shared Row Lock,IS)

      定義與原理:意向共享行鎖是一種表級的鎖意向表示,該鎖是為了提高效率用的。當一個事務對表中的一行或多行加上共享行鎖時,會在表級自動加上意向共享行鎖。它的主要作用是為了提高數據庫在處理更高層次(表級)鎖沖突檢查時的效率。通過在表級設置意向共享行鎖,數據庫在進行表級鎖操作(如另一個事務試圖對整個表加排他表鎖)時,可以快速判斷表內是否有行已經被加上共享行鎖,而不需要逐行檢查。

      應用場景和示例:假設在一個電商系統的庫存管理模塊中,有一個事務需要查詢多個商品的庫存信息行。事務在對這些商品庫存信息行加上共享行鎖的同時,會在inventory表級加上意向共享行鎖。這樣,當其他事務想要對整個inventory表進行排他操作(如更新所有庫存信息)時,數據庫通過檢查表級的意向共享行鎖,就可以快速判斷出表內有行正在被讀取,從而避免了可能的鎖沖突,提高了系統的并發性能和鎖管理效率。

       

      • 意向排他行鎖(Intention Exclusive Row Lock,IX)

      定義與原理:意向排他行鎖同樣是一種表級的鎖意向表示,該鎖是為了提高效率用的。當一個事務對表中的一行或多行加上排他行鎖時,會在表級自動加上意向排他行鎖。它的主要作用是在更高層次上表明表內有行正在進行排他操作,方便數據庫快速進行鎖沖突檢查。當其他事務嘗試對整個表進行不兼容操作(如加共享鎖或排他鎖)時,數據庫可以通過檢查表級的意向排他行鎖及時發現并阻止,從而避免復雜的逐行檢查過程。

      應用場景和示例:在一個訂單處理系統中,當事務 A 對訂單表中的某一訂單行進行更新操作(如修改訂單狀態)時,會對該訂單行加上排他行鎖,并在訂單表級加上意向排他行鎖。此時,如果另一個事務 B 想要對整個訂單表進行讀取操作(加共享鎖)或者進行其他修改操作(加排他鎖),數據庫通過檢查表級的意向排他行鎖,就可以快速知道表內有行正在進行排他操作,從而避免了可能的鎖沖突,確保數據的一致性和操作的正確性。

       

      3.2、索引失效行鎖變表鎖

      InnoDB 行鎖是通過給索引上的索引項加鎖來實現的,只有通過索引條件來查詢修改數據(select xxx where 索引字段),InnoDB才使用行級鎖,否則,InnoDB將使用表鎖!行級鎖都是基于索引的,如果一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖。

      比如,上面的例子當中,如果是修改 a 的值,并且條件不加引號,如條件語句為 where b = 1000,由于 b 是 varchar 類型,而此時不使用引號引起來會導致 mysql 底層自動進行類型轉換,相當于發生了計算,由此索引會失效。當沒有使用到索引時,此時 InnoDB 表不會使用行級鎖,而是使用表鎖。

      如下:

         

      上面 A 會話中由于 SQL 語句中的條件發生了類型轉換,導致索引失效,行鎖變表鎖,所以 B 會話的修改會一直阻塞,直到 A 會話提交事務 B 的修改才能執行結束。

       

      3.3、間隙鎖(Next-Key鎖)

      當我們用范圍條件而不是相等條件來修改數據,InnoDB 會給符合范圍條件的所有數據記錄的索引項加鎖,那些值在條件范圍內但并不存在在表里的數據,叫做“間隙(GAP)”,InnoDB 也會對這些 “間隙” 加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)。可以理解是一個范圍鎖。

      比如,A會話對某個范圍條件的數據進行修改,但 A 還未提交事務,此時 B 會話想新增一條數據,但剛好這條數據符合 A 修改語句的條件范圍,則 B 的新增會一直阻塞,因此此時 InnoDB 對這些范圍數據加了間隙鎖。

      如下:

           

       

      3.4、如何分析行鎖

      可通過以下命令查看數據庫中行鎖的情況:

      show status like 'innodb_row_lock%';

      說明如下:

      • Innodb_row_lock_current_waits:當前正在等待鎖定的數量
      • Innodb_row_lock_time:從系統啟動到現在鎖定總時間長度。
      • Innodb_row_lock_time_avg:每次等待所花平均時長。
      • Innodb_row_lock_time_max:從系統啟動到現在等待最長的一次所花的時間
      • Innodb_row_lock_waits:系統啟動后到現在總共等待的次數

      當等待的次數很高,而且每次等待的時長也不小的時候,我們就需要分析系統中為什么會有如此多的等待,然后根據分析結果著手制定優化計劃。 

       

      4、MySQL 默認事務的鎖

      mysql 默認事務隔離(Repeatable Read)下,增刪改查操作對應的鎖機制:

      1. 查詢(SELECT)操作的鎖機制

        • 普通查詢(非鎖定讀):

          • 在 MySQL 默認的可重復讀隔離級別下,普通查詢并不會加鎖(在大多數正常情況下),InnoDB 存儲引擎通常會基于多版本并發控制(MVCC)機制進行普通查詢。MVCC 允許事務讀取到某個時間點上數據的快照。每個事務在開始時會被分配一個事務 ID,數據庫中的每一行數據都有兩個隱藏列,分別記錄創建版本號(Create Version)和刪除版本號(Delete Version)。當一個事務進行查詢時,它會讀取創建版本號小于等于當前事務 ID,并且刪除版本號大于當前事務 ID 或者為空的數據。例如,在一個簡單的員工信息管理系統中,事務 A 和事務 B 同時查詢員工表employees中的數據。事務 A 開始查詢時,根據 MVCC 機制獲取了當時數據的快照視圖。即使事務 B 在事務 A 查詢期間對員工表中的數據進行了修改并提交,事務 A 仍然可以按照自己開始查詢時的數據快照進行讀取,而不會受到事務 B 修改操作的影響,并且這個過程中不需要對數據行加鎖。
        • 鎖定查詢(鎖定讀):

          • 共享鎖(S 鎖)的使用:如果在查詢語句中使用LOCK IN SHARE MODE子句,事務會對查詢的行加上共享行鎖。這意味著其他事務可以對這些行加共享行鎖進行讀取,但不能加排他行鎖進行寫操作,直到共享行鎖被釋放。例如,SELECT * FROM table_name WHERE condition LOCK IN SHARE MODE會對滿足條件的行加共享行鎖。這種鎖定讀主要用于需要在讀取數據期間防止數據被其他事務修改的場景,比如在統計報表生成過程中,需要確保讀取的數據在統計期間不被修改。
          • 排他鎖(X 鎖)的使用:當使用FOR UPDATE子句進行查詢時,事務會對查詢的行加上排他行鎖。這樣只有當前事務可以對這些行進行讀寫操作,其他事務對這些行的讀寫操作都會被阻塞,直到排他行鎖被釋放。例如,SELECT * FROM table_name WHERE condition FOR UPDATE用于在事務需要對查詢到的數據進行后續更新操作的場景,如在一個訂單處理系統中,先查詢出未處理的訂單,然后對這些訂單進行更新操作,就可以使用FOR UPDATE來確保在更新之前這些訂單不會被其他事務修改。
      2. 插入(INSERT)操作的鎖機制
        • 排他行鎖(X 鎖):
          • 在 InnoDB 中,當插入一條新記錄時,會自動為新插入的行加上排他行鎖。這是為了確保在插入操作期間,其他事務不會同時對同一行進行插入、更新或刪除操作,保證數據的完整性。例如,在一個用戶注冊系統中,當插入新用戶信息時,新用戶記錄所在的行就會被加上排他行鎖。這種鎖在插入操作完成(事務提交或者回滾)后會自動釋放。
      3. 刪除(DELETE)操作的鎖機制
        • 排他行鎖(X 鎖)和間隙鎖(Gap Lock):
          • 首先會對要刪除的行加上排他行鎖。這可以防止其他事務在刪除操作進行期間對同一行進行讀取(違反隔離級別要求的讀?。⒏禄騽h除操作。例如,在一個內容管理系統中,當刪除一篇文章記錄時,對應的文章記錄行就會被加上排他行鎖,其他事務想要讀取這篇文章(如果不符合 MVCC 機制下的可讀條件)或者修改、刪除這篇文章都會被阻塞,直到刪除操作完成并且鎖被釋放。
          • 與插入操作類似,如果刪除操作涉及索引間隙,也會使用間隙鎖。這是為了防止在刪除操作過程中,其他事務在間隙中插入數據,從而導致幻讀問題。例如,在一個按照時間順序存儲記錄的索引中,刪除某個時間區間內的記錄時,InnoDB 會對該時間區間對應的索引間隙加上間隙鎖,確保在刪除操作期間,不會有新的記錄插入到這個區間,保證事務在執行過程中的數據一致性。
      4. 更新(UPDATE)操作的鎖機制

        • 排他行鎖(X 鎖)和 MVCC 機制:

          • 對要更新的行加上排他行鎖。這保證了在更新過程中,只有執行更新操作的事務能夠對該行進行讀寫操作,其他事務對同一行的讀取(不符合 MVCC 機制下的可讀條件)、更新或刪除操作都會被阻塞。例如,在一個電商系統中,當更新商品價格時,對應的商品記錄行就會被加上排他行鎖,防止其他事務同時修改價格或者讀取不符合隔離級別要求的價格數據。

          • 在更新操作時,InnoDB 會利用 MVCC(多版本并發控制)機制。如果事務在更新過程中需要讀取該行數據的舊版本(例如在一個觸發器或者復雜的業務邏輯中),它可以通過 MVCC 機制讀取到該行數據在事務開始時的快照版本。這是因為在可重復讀隔離級別下,事務在整個執行過程中應該看到的數據是一致的,MVCC 機制可以保證這一點,同時減少了對共享鎖的依賴,提高了并發性能。

          • 間隙鎖(Gap Lock):同樣,如果更新操作涉及索引間隙,也會使用間隙鎖來防止幻讀。例如,在一個按照范圍查詢頻繁的表中,更新某個范圍內的記錄時,InnoDB 會對對應的索引間隙加上間隙鎖,確保在更新操作期間,不會有新的記錄插入到這個范圍內,保證事務的隔離性和數據一致性。

       

      4.1、SELECT ... FROM

      1)SELECT ... FROM ...

      • 該語句是一個快照讀,通過讀取數據庫的一個快照,不會加任何鎖,除非將隔離級別設置成了 SERIALIZABLE 。

       

      2)SELECT ... FROM ... LOCK IN SHARE MODE

      • 如果使用到索引并且條件是范圍,則在所有索引掃描范圍的索引記錄上加上共享的間隙鎖(next key鎖)。如果是唯一索引,只需要在相應記錄上加排他行鎖。這些被共享鎖鎖住的行無法進行update/delete。
      • 允許其它事務對這些記錄再加SHARE鎖

       

      3)SELECT ... FROM ... FOR UPDATE

      • 如果使用到索引并且條件是范圍,則在所有索引掃描范圍的索引記錄上加上排他的next key鎖。如果是唯一索引,只需要在相應記錄上加排他行鎖

       

      4.2、UPDATE ... WHERE ...

      • 對要更新的行加上排他行鎖。
      • 如果涉及范圍更新,則會對索引間隙加上間隙鎖。

       

      4.3、DELETE FROM ... WHERE ...

      • 語句在所有索引掃描范圍的索引記錄上加上排他的next key鎖。如果是唯一索引,只需要在相應記錄上加排他行鎖

       

      4.4、INSERT

      • 在插入的記錄上加一把排他行鎖。

       

      總結:

      隔離級別越高,越能保證數據的完整性和一致性,但是對并發性能的影響也越大,魚和熊掌不可兼得啊。對于多數應用程序,可以優先考慮把數據庫系統的隔離級別設為Read Committed,它能夠避免臟讀取,而且具有較好的并發性能。盡管它會導致不可重復讀、幻讀這些并發問題,在可能出現這類問題的個別場合,可以由應用程序采用悲觀鎖或樂觀鎖來控制。

      可參考:http://www.rzrgm.cn/frankyou/p/9603784.html

       

      5、數據庫的事務隔離和鎖的關系

      事務隔離級別是為了解決多并發時查到的數據不一致的問題,而鎖是為了阻塞其他事務對同一數據進行修改。一個是為查,一個是為改。

       

      6、多并發事務產生死鎖

      6.1、分析和示例

      1. 死鎖產生的原因
        • 資源競爭:在多并發事務中多條更新語句并發執行時,死鎖主要是由于多個事務對資源(數據庫中的行或表)的相互競爭和等待引起的。每個事務都持有一些資源的鎖,同時又在等待其他事務釋放它們所需的資源鎖。例如,事務 A 獲取了資源 X 的排他行鎖,正在等待資源 Y 的排他行鎖;而事務 B 獲取了資源 Y 的排他行鎖,正在等待資源 X 的排他行鎖,這樣就形成了死鎖。
        • 更新順序不一致:如果多個事務對相同的資源進行更新,且更新的順序不一致,很容易導致死鎖。假設在一個銀行轉賬系統中,事務 A 先更新賬戶 1 的余額,再更新賬戶 2 的余額;而事務 B 先更新賬戶 2 的余額,再更新賬戶 1 的余額。當兩個事務并發執行時,就可能出現死鎖情況。
      2. 示例場景
        • 假設有一個包含accounts表的數據庫,表中有account_id(主鍵)、balance兩個列。有兩個事務T1和 T2 同時進行轉賬操作。
        • 事務 T1 的 SQL 語句如下:
          • START TRANSACTION;
          • UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
          • UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
          • COMMIT;
        • 事務 T2 的 SQL 語句如下:
          • START TRANSACTION;
          • UPDATE accounts SET balance = balance - 100 WHERE account_id = 2;
          • UPDATE accounts SET balance = balance + 100 WHERE account_id = 1;
          • COMMIT;
        • 在這個場景中,當 T1 執行第一條更新語句鎖住account_id = 1對應的行后,T2 執行第一條更新語句鎖住account_id = 2對應的行。然后 T1 等待account_id = 2的行鎖釋放來執行第二條更新語句,T2 等待account_id = 1的行鎖釋放來執行第二條更新語句,這樣就產生了死鎖。

      在 MySQL 默認的隔離級別(Repeatable Read)中,事務在更新多行數據時(比如上述依次更新account_id = 1和account_id = 2 兩行數據)會依次對它們加上排他行鎖,并且這些鎖會在事務結束時統一釋放。即在可重復讀隔離級別下,多行數據的排他行鎖會在事務提交(COMMIT)或者回滾(ROLLBACK)時才會統一釋放,以確保事務的一致性和可重復讀特性。

       

      據 “鎖的重入性”(同一事務對已持有的鎖可重復獲取),所以在同一個事務中,先后兩次更新同一行數據并不會產生死鎖,死鎖的核心是 “兩個或多個事務相互等待對方釋放鎖”。

       

      6.2、如何預防死鎖

      1. 固定更新順序
        • 原理:確保所有事務按照相同的順序訪問和更新資源。這樣可以避免循環等待的情況,因為每個事務都在等待另一個事務持有的鎖,而這個等待關系是由于訪問順序不一致導致的。
        • 例如,銀行轉賬中,可以規定所有轉賬事務都按照賬戶 ID 從小到大的順序來更新賬戶余額,這樣可以避免因更新順序不一致而導致的死鎖。
      2. 減少事務持有鎖的時間
        • 原理:縮短事務的執行時間可以降低在同一時間內多個事務競爭資源的可能性。通過優化查詢語句、減少復雜的業務邏輯在事務中的占比等方式,可以使事務更快地完成,從而減少死鎖的發生。
        • 示例和方法:
          • 優化查詢性能:在事務中的更新語句里,確保所涉及的查詢能夠高效執行。例如,為更新操作涉及的列添加合適的索引,這樣可以加快數據的定位和更新速度。如果更新customers表中根據customer_id查找的客戶信息,為customer_id列添加索引可以加快UPDATE語句的執行。
          • 合理拆分事務:如果一個事務包含了多個可以獨立執行的更新操作,并且這些操作對數據一致性的要求允許它們分開執行,那么可以將事務拆分成多個較小的事務。例如,一個訂單處理事務包含更新訂單狀態、更新庫存和更新客戶積分三個操作。如果業務允許,可將其拆分為三個獨立的事務,分別處理訂單狀態更新、庫存更新和客戶積分更新,這樣每個事務持有鎖的時間就會縮短。
      3. 使用合適的鎖粒度和鎖類型
        • 原理:選擇合適的鎖粒度(行鎖、表鎖等)和鎖類型(共享鎖、排他鎖等)可以平衡并發性能和數據一致性。細粒度的行鎖通??梢蕴岣卟l度,但可能會增加鎖管理的復雜性;粗粒度的表鎖可以簡化鎖管理,但會降低并發性能。根據業務需求合理選擇可以減少死鎖。
        • 示例:在一個以讀取為主的報表系統中,大部分操作是查詢數據,偶爾會有少量的更新操作用于數據修正。對于這種情況,在更新操作時可以使用排他行鎖,這樣在更新數據行時不會影響其他事務對其他行的讀取操作,同時也能減少因為對整個表加鎖而導致的死鎖風險。如果不分情況地對整個表加排他表鎖,在高并發讀取場景下很容易導致死鎖。

       

      posted @ 2022-02-28 23:48  wenxuehai  閱讀(673)  評論(0)    收藏  舉報
      //右下角添加目錄
      主站蜘蛛池模板: 亚洲国产精品日韩AV专区| 一个色综合亚洲热色综合| 久热这里只精品视频99| 久久久久久伊人高潮影院| 日韩欧美亚洲综合久久| 人人爽人人爽人人片a免费| 久久香蕉欧美精品| 国产一区二区三区日韩精品| 国产乱xxxxx97国语对白| 国产精品人伦一区二区三| 一区二区三区四区黄色网| 国产精品一区二区久久岳| 四虎国产精品永久入口| 国产精品久久久久aaaa| 免费无码一区无码东京热| 色午夜一av男人的天堂| 精品一卡2卡三卡4卡乱码精品视频| 亚洲一区二区三区自拍麻豆| 国产V日韩V亚洲欧美久久| 99久久无码私人网站| 国产成人av免费观看| 国产精品 欧美激情 在线播放| 古丈县| 色综合五月伊人六月丁香| 亚洲a∨国产av综合av| 最新的国产成人精品2020| 少妇宾馆粉嫩10p| 久久久一本精品99久久精品88 | 国偷自产一区二区免费视频| 久久国产成人午夜av影院| 亚洲情色av一区二区| 国产区二区三区在线观看| 国产精品日韩中文字幕| 成人福利国产午夜AV免费不卡在线 | 日韩不卡一区二区在线观看| 精品无码久久久久久尤物 | 日本一区二区三区专线| 久久久亚洲欧洲日产国码αv| 国产一区日韩二区三区| 国产成人无码精品久久久露脸| 国产精品日韩av在线播放|