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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库支持锁的种类

發布時間:2024/4/11 数据库 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库支持锁的种类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

數據庫支持鎖的種類

文章目錄

  • 數據庫支持鎖的種類
    • 一、引入
    • 二、鎖的分類
      • 1.按照鎖粒度進行劃分
      • 2.從數據庫管理的角度對鎖進行劃分
      • 3.從程序員的角度對進行劃分
    • 三、案例

一、引入

  • 數據庫上加鎖是為了保證數據的一致性。
  • 編程語言中也有鎖的概念。其實,只要有并發的地方,就有鎖的用武之地。
  • 數據庫的鎖五花八門,都是怎樣分類的呢?

二、鎖的分類

1.按照鎖粒度進行劃分

  • 從鎖定對象的粒度大小來對鎖進行劃分,分別為行鎖、頁鎖和表鎖。
  • 行鎖就是按照行的粒度對數據進行鎖定。鎖定力度小,發生鎖沖突概率低,可以實現的并發度高,但是對于鎖的開銷大,加鎖會比較慢,容易出現死鎖情況。
  • 頁鎖就是在頁的粒度上進行鎖定,鎖定的數據資源比行鎖要多,因為一個頁中可以有多個行記錄。當使用頁鎖的時候,會出現數據浪費的現象,但這樣的浪費最多就是一個頁上的數據行。頁鎖的開銷介于表鎖和行鎖之間,會出現死鎖。鎖定粒度介于表鎖和行鎖之間,并發度一般。
  • 表鎖就是對數據表進行鎖定,鎖定粒度很大,同時發生鎖沖突的概率也會較高,數據訪問的并發度低。不過好處在于對鎖的使用開銷小,加鎖會很快。
  • 行鎖、頁鎖和表鎖是相對常見的三種鎖,除此以外還可以在區和數據庫的粒度上鎖定數據,對應區鎖和數據庫鎖。
  • 不同的數據庫和存儲引擎支持的鎖粒度不同,InnoDB 和 Oracle 支持行鎖和表鎖。而 MyISAM 只支持表鎖,MySQL 中的 BDB 存儲引擎支持頁鎖和表鎖。SQL Server 可以同時支持行鎖、頁鎖和表鎖。

2.從數據庫管理的角度對鎖進行劃分

  • 共享鎖、排它鎖和意向鎖
  • 共享鎖也叫讀鎖或 S 鎖,共享鎖鎖定的資源可以被其他用戶讀取,但不能修改。在進行SELECT的時候,可將對象進行共享鎖鎖定,當數據讀取完畢之后,就會釋放共享鎖,這樣就可以保證數據在讀取時不被修改。
  • 排它鎖也叫獨占鎖、寫鎖或 X 鎖。排它鎖鎖定的數據只允許進行鎖定操作的事務使用,其他事務無法對已鎖定的數據進行查詢或修改。

在對數據進行更新的時候,也就是INSERT、DELETE或者UPDATE的時候,數據庫也會自動使用排它鎖,防止其他事務對該數據行進行操作。

  • 當要獲取某個數據表的排它鎖的時候,需要先看下這張數據表有沒有上了排它鎖。如果這個數據表中的某個數據行被上了行鎖,就無法獲取排它鎖。這時需要對數據表中的行逐一排查,檢查是否有行鎖,如果沒有,才可以獲取這張數據表的排它鎖。
  • 這個過程未免太麻煩,所以就有了意向鎖。
  • 意向鎖(Intent Lock),簡單來說就是給更大一級別的空間示意里面是否已經上過鎖。
  • 如果給某一行數據加上了排它鎖,數據庫會自動給更大一級的空間,比如數據頁或數據表加上意向鎖,告訴其他人這個數據頁或數據表已經有人上過排它鎖了,這樣當其他人想要獲取數據表排它鎖的時候,只需要了解是否有人已經獲取了這個數據表的意向排他鎖即可。
  • 如果事務想要獲得數據表中某些記錄的共享鎖,就需要在數據表上添加意向共享鎖。同理,事務想要獲得數據表中某些記錄的排他鎖,就需要在數據表上添加意向排他鎖。這時,意向鎖會告訴其他事務已經有人鎖定了表中的某些記錄,不能對整個表進行全表掃描。

為什么共享鎖會發生死鎖的情況?

在客戶端 1 獲取某數據行共享鎖的同時,另一個客戶端 2也獲取了該數據行的共享鎖,這時任何一個客戶端都沒法對這個數據進行更新,因為共享鎖會阻止其他事務對數據的更新,當某個客戶端想要對鎖定的數據進行更新的時候,就出現了死鎖的情況。

當死鎖發生的時候,就需要一個事務進行回滾,另一個事務獲取鎖完成事務,然后將鎖釋放掉,這很像交通堵塞時候的解決方案。

3.從程序員的角度對進行劃分

樂觀鎖和悲觀鎖詳解

  • 如果從程序員的視角來看鎖的話,可以將鎖分成樂觀鎖和悲觀鎖,從名字中也可以看出這兩種鎖是兩種看待數據并發的思維方式。
  • 樂觀鎖(Optimistic Locking)認為對同一數據的并發操作不會總發生,屬于小概率事件,不用每次都對數據上鎖,也就是不采用數據庫自身的鎖機制,而是通過程序來實現。在程序上,我們可以采用版本號機制或者時間戳機制實現。

1.樂觀鎖的版本號機制

在表中設計一個版本字段 version,第一次讀的時候,同時會獲取 version
字段的取值。然后對數據進行更新或刪除操作時,會執行UPDATE ... SET version=version+1 WHERE version=version。此時如果已經有事務對這條數據進行了更改,修改就不會成功。

2.樂觀鎖的時間戳機制

時間戳和版本號機制一樣,也是在更新提交的時候,將當前數據的時間戳和更新之前取得的時間戳進行比較,如果兩者一致則更新成功,否則就是版本沖突。

樂觀鎖就是程序員自己控制數據并發操作的權限,基本是通過給數據行增加一個戳(版本號或者時間戳),從而證明當前拿到的數據是否最新。

  • 悲觀鎖(Pessimistic Locking)也是指一種鎖的思想,對數據被其他事務的修改持保守態度,會通過數據庫自身的鎖機制(表鎖,行鎖,讀鎖,寫鎖等)來實現,從而保證數據操作的排它性。
  • 從這兩種鎖的設計思想中,可以看出樂觀鎖和悲觀鎖的適用場景:
  • 樂觀鎖適合讀操作多的場景,相對來說寫的操作比較少。它的優點在于程序實現,不存在死鎖問題,不過適用場景也會相對樂觀,因為它阻止不了除了程序以外的數據庫操作。
  • 悲觀鎖適合寫操作多的場景,因為寫的操作具有排它性。采用悲觀鎖的方式,可以在數據庫層面阻止其他事務對該數據的操作權限,防止讀 - 寫和寫 - 寫的沖突。
  • 如何避免死鎖?
  • 1.如果事務涉及多個表,操作比較復雜,那么可以盡量一次鎖定所有的資源,而不是逐步來獲取,這樣可以減少死鎖發生的概率;
  • 2.如果事務需要更新數據表中的大部分數據,數據表又比較大,這時可以采用鎖升級的方式,比如將行級鎖升級為表級鎖,從而減少死鎖產生的概率;
  • 3.不同事務并發讀寫多張數據表,可以約定訪問表的順序,采用相同的順序降低死鎖發生的概率。

三、案例

規定這里用T1代表一個數據庫執行請求,T2代表另一個請求,也可以理解為T1為一個線程,T2 為另一個線程,T3,T4以此類推

  • 共享鎖
  • 例1:
T1: select * from table (請想象它需要執行1個小時之久,后面的sql語句請都這么想象) T2: update table set column1='hello'過程:T1運行 (加共享鎖)T2運行 If T1 還沒執行完T2等...... else鎖被釋放T2執行 endifT2之所以要等,是因為T2在執行update前,試圖對table表加一個排他鎖, 而數據庫規定同一資源上不能同時共存共享鎖和排他鎖。所以T2必須等T1 執行完,釋放了共享鎖,才能加上排他鎖,然后才能開始執行update語句。
  • 例2
T1: select * from table T2: select * from table這里T2不用等待T1執行完,而是可以馬上執行。分析: T1運行,則table被加鎖,比如叫lockA T2運行,再對table加一個共享鎖,比如叫lockB。兩個鎖是可以同時存在于同一資源上的(比如同一個表上)。這被稱為共 享鎖與共享鎖兼容。這意味著共享鎖不阻止其它session同時讀資源,但阻 止其它session update
  • 例3:
T1: select * from table T2: select * from table T3: update table set column1='hello'這次,T2不用等T1運行完就能運行,T3卻要等T1和T2都運行完才能運行。 因為T3必須等T1和T2的共享鎖全部釋放才能進行加排他鎖然后執行update 操作。
  • 例4:(死鎖的發生)
T1: begin transelect * from table (holdlock) (holdlock意思是加共享鎖,直到事物結束才釋放)update table set column1='hello'T2: begin transelect * from table(holdlock)update table set column1='world'假設T1和T2同時達到select,T1對table加共享鎖,T2也對加共享鎖,當 T1的select執行完,準備執行update時,根據鎖機制,T1的共享鎖需要升 級到排他鎖才能執行接下來的update.在升級排他鎖前,必須等table上的 其它共享鎖釋放,但因為holdlock這樣的共享鎖只有等事務結束后才釋放, 所以因為T2的共享鎖不釋放而導致T1等(等T2釋放共享鎖,自己好升級成排 他鎖),同理,也因為T1的共享鎖不釋放而導致T2等。死鎖產生了。
  • 例5:
T1: begin tranupdate table set column1='hello' where id=10T2: begin tranupdate table set column1='world' where id=20這種語句雖然最為常見,很多人覺得它有機會產生死鎖,但實際上要看情 況,如果id是主鍵上面有索引,那么T1會一下子找到該條記錄(id=10的記 錄),然后對該條記錄加排他鎖,T2,同樣,一下子通過索引定位到記錄, 然后對id=20的記錄加排他鎖,這樣T1和T2各更新各的,互不影響。T2也不 需要等。但如果id是普通的一列,沒有索引。那么當T1對id=10這一行加排他鎖后, T2為了找到id=20,需要對全表掃描,那么就會預先對表加上共享鎖或更新 鎖或排他鎖(依賴于數據庫執行策略和方式,比如第一次執行和第二次執行 數據庫執行策略就會不同)。但因為T1已經為一條記錄加了排他鎖,導致 T2的全表掃描進行不下去,就導致T2等待。死鎖怎么解決呢?一種辦法是,如下:
  • 例6:
T1: begin transelect * from table(xlock) (xlock意思是直接對表加排他鎖)update table set column1='hello'T2: begin transelect * from table(xlock)update table set column1='world'這樣,當T1的select 執行時,直接對表加上了排他鎖,T2在執行select時,就需要等T1事物完全執行完才能執行。排除了死鎖發生。 但當第三個user過來想執行一個查詢語句時,也因為排他鎖的存在而不得不等待,第四個、第五個user也會因此而等待。在大并發 情況下,讓大家等待顯得性能就太友好了,所以,這里引入了更新鎖。
  • 更新鎖(Update lock)

為解決死鎖,引入更新鎖。

  • 例7:
T1: begin transelect * from table(updlock) (加更新鎖)update table set column1='hello'T2: begin transelect * from table(updlock)update table set column1='world'更新鎖的意思是:“我現在只想讀,你們別人也可以讀,但我將來可能會做更新操作, 我已經獲取了從共享鎖(用來讀)到排他鎖(用來更新)的資格”。一個事物只能有 一個更新鎖獲此資格。T1執行select,加更新鎖。 T2運行,準備加更新鎖,但發現已經有一個更新鎖在那兒了,只好等。當后來有user3、user4...需要查詢table表中的數據時,并不會因為T1的 select在執行就被阻塞,照樣能查詢,相比起例6,這提高了效率。
  • 例8:
T1: select * from table(updlock)(加更新鎖)T2: select * from table(updlock)(等待,直到T1釋放更新鎖,因為同一時間不能在同一資源上有兩個更新鎖)T3: select * from table (加共享鎖,但不用等updlock釋放,就可以讀)這個例子是說明:共享鎖和更新鎖可以同時在同一個資源上。這被稱為共享鎖和更新鎖是兼容的。
  • 例9:
T1: beginselect * from table(updlock) (加更新鎖)update table set column1='hello' (重點:這里T1做update時,不需要等T2釋放什么,而是直接把更新鎖升級為排他鎖,然后執行update)T2: beginselect * from table (T1加的更新鎖不影響T2讀取)update table set column1='world' (T2的update需要等T1的update做完才能執行)我們以這個例子來加深更新鎖的理解,第一種情況:T1先達,T2緊接到達;在這種情況中,T1先對表加更新鎖,T2對表加共享鎖, 假設T2的select先執行完,準備執行update,發現已有更新鎖存在,T2等。T1執行 這時才執行完select,準備執行update,更新鎖升級為排他鎖,然后執行update,執行完成,事務結束,釋放鎖,T2才輪到執行update。第二種情況:T2先達,T1緊接達;在這種情況,T2先對表加共享鎖,T1達后,T1 對表加更新鎖,假設T2 select先結束,準備update,發現已有更新鎖,則等待, 后面步驟就跟第一種情況一樣了。這個例子是說明:排他鎖與更新鎖是不兼容的,它們不能同時加在同一子資源上。
  • 排他鎖(獨占鎖,Exclusive Locks)

這個簡單,即其它事務既不能讀,又不能改排他鎖鎖定的資源。

  • 例10
T1: update table set column1='hello' where id<1000 T2: update table set column1='world' where id>1000假設T1先達,T2隨后至,這個過程中T1會對id<1000的記錄施加排他鎖. 但不會阻塞T2的update。
  • 例11 (假設id都是自增長且連續的)
T1: update table set column1='hello' where id<1000 T2: update table set column1='world' where id>900如同例10,T1先達,T2立刻也到,T1加的排他鎖會阻塞T2的update.
  • 意向鎖(Intent Locks)

意向鎖就是說在屋(比如代表一個表)門口設置一個標識,說明屋子里有人(比如代表某些記錄)被鎖住了。另一個人想知道屋子里是否有人被鎖,不用進屋子里一個一個的去查,直接看門口標識就行了。

當一個表中的某一行被加上排他鎖后,該表就不能再被加表鎖。數據庫程序如何知道該表不能被加表鎖?一種方式是逐條的判斷該表的每一條記錄是否已經有排他鎖,另一種方式是直接在表這一層級檢查表本身是否有意向鎖,不需要逐條判斷。顯然后者效率高。

  • 例12:
T1: begin transelect * from table (xlock) where id=10 --意思是對id=10這一行強加排他鎖T2: begin transelect * from table (tablock) --意思是要加表級鎖假設T1先執行,T2后執行,T2執行時,欲加表鎖,為判斷是否可以加表鎖,數據庫 系統要逐條判斷table表每行記錄是否已有排他鎖,如果發現其中一行已經有排他鎖 了,就不允許再加表鎖了。只是這樣逐條判斷效率太低了。實際上,數據庫系統不是這樣工作的。當T1的select執行時,系統對表table的 id=10的這一行加了排他鎖,還同時悄悄的對整個表加了意向排他鎖(IX), 當T2執行表鎖時,只需要看到這個表已經有意向排他鎖存在,就直接等待,而不 需要逐條檢查資源了。
  • 例13:
T1: begin tranupdate table set column1='hello' where id=1T2: begin tranupdate table set column1='world' where id=1這個例子和上面的例子實際效果相同,T1執行,系統對table同時對行家排他鎖、 對頁加意向排他鎖、對表加意向排他鎖。
  • 計劃鎖(Schema Locks)
  • 例14:
alter table .... (加schema locks,稱之為Schema modification (Sch-M) locksDDL語句都會加Sch-M鎖 該鎖不允許任何其它session連接該表。連都連不了這個表了,當然更不用說想對 該表執行什么sql語句了。
  • 例15:
用jdbc向數據庫發送了一條新的sql語句,數據庫要先對之進行編譯, 在編譯期間,也會加鎖,稱之為:Schema stability (Sch-S) locksselect * from tableA編譯這條語句過程中,其它session可以對表tableA做任何操作 (update,delete,加排他鎖等等),但不能做DDL(比如alter table)操作。

總結

以上是生活随笔為你收集整理的数据库支持锁的种类的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。