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

歡迎訪問 生活随笔!

生活随笔

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

数据库

并发编程(四):也谈谈数据库的锁机制

發布時間:2025/3/21 数据库 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并发编程(四):也谈谈数据库的锁机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先聲明,本次文章基本上都是從其他人的文章中或者論壇的回復中整理而來。我把我認為的關鍵點提取出來供自己學習。所有的引用都附在文后,在這里也就不一一表謝了。

第二個聲明,我對于Internel DB并沒有研究過,所使用的也是簡單的寫寫SQL,截止到現在最多的一個經驗也就是SQL的性能調優,具體點就是通過Postgresql的執行計劃,來調整優化SQL語句完成在特定場景下的數據庫調優。對于鎖,由于數據庫支持的鎖機制已經能夠滿足平時的開發需要。因為所從事的行業并不是互聯網,沒有實時性高并發的應用場景,因此也沒有速到過數據庫的復雜問題;對于線上應用的死鎖問題,那更是沒有研究過了。本文算是自己學習數據庫鎖機制的一個讀書筆記。再次感謝各位同仁的分享。

??? 鎖機制為什么是數據庫非常重要的內容,那么看一下數據庫并發的問題你就知道為什么了:

1. 數據庫并發的問題

數據庫帶來的并發問題包括:???

?  1. 丟失更新。

?  2. 未確認的相關性(臟讀)。

?  3. 不一致的分析(非重復讀)。

??????? 4. 幻像讀。

詳細描述如下:

1.1.丟失更新

當兩個或多個事務選擇同一行,然后基于最初選定的值更新該行時,會發生丟失更新問題。每個事務都不知道其它事務的存在。最后的更新將重寫由其它事務所做的更新,這將導致數據丟失。   

e.g.事務A和事務B同時修改某行的值,

  • 事務A將數值改為1并提交
  • 事務B將數值改為2并提交。
  • 這時數據的值為2,事務A所做的更新將會丟失。?

    看下面一段sql:

    [sql]?view plaincopy
  • select?old_attributes??from?table?where?primary_key?=???---step1??
  • attributes?=?merge(old_attributes,new_attributes)???????----step2??
  • update?table?set?attributes_column?=?attributes?where?primary_key?=?????----step3???

  • 但是這樣的話,存在一個丟失更新的問題,兩個線程ThreadA 和 ThreadB 同時運行到了step1得到相同的old_attributes,

    然后同時做step2,最后ThreadA先做step3,而ThreadB后做step3,這樣ThreadB就把ThreadA的屬性更新給丟失了!

    如何解決呢?基本兩種思路,一種是悲觀鎖,另外一種是樂觀鎖; 簡單的說就是一種假定這樣的問題是高概率的,最好一開始就鎖住,免得更新老是失敗;另外一種假定這樣的問題是小概率的,最后一步做更新的時候再鎖住,免得鎖住時間太長影響其他人做有關操作。

    1.1.1 悲觀鎖

      a)傳統的悲觀鎖法(不推薦):

      以上面的例子來說明,在彈出修改工資的頁面初始化時(這種情況下一般會去從數據庫查詢出來),在這個初始化查詢中使用select ……for update nowait, 通過添加for update nowait語句,將這條記錄鎖住,避免其他用戶更新,從而保證后續的更新是在正確的狀態下更新的。然后在保持這個鏈接的狀態下,在做更新提交。當然這個有個前提就是要保持鏈接,就是要對鏈接要占用較長時間,這個在現在web系統高并發高頻率下顯然是不現實的。

      b)現在的悲觀鎖法(推薦優先使用):

      在修改工資這個頁面做提交時先查詢下,當然這個查詢必須也要加鎖(select ……for update nowait),有人會說,在這里做個查詢確認記錄是否有改變不就行了嗎,是的,是要做個確認,只是你不加for update就不能保證你在查詢到更新提交這段時間里這條記錄沒有被其他會話更新過,所以這種方式也需要在查詢時鎖定記錄,保證在這條記錄沒有變化的基礎上再做更新,若有變化則提示告知用戶。

    1.1.2. 樂觀鎖

      a)舊值條件(前鏡像)法:

      就是在sql更新時使用舊的狀態值做條件,SQL大致如下 Update table set col1 = newcol1value, col2 = newcol2value…。 where col1 = oldcol1value and col2 = oldcol2value…。,在上面的例子中我們就可以把當前工資作為條件進行更新,如果這條記錄已經被其他會話更新過,則本次更新了0行,這里我們應用系統一般會做個提示告知用戶重新查詢更新。這個取哪些舊值作為條件更新視具體系統實際情況而定。(這種方式有可能發生阻塞,如果應用其他地方使用悲觀鎖法長時間鎖定了這條記錄,則本次會話就需要等待,所以使用這種方式時最好統一使用樂觀鎖法。)

      b)使用版本列法(推薦優先使用):

      其實這種方式是一個特殊化的前鏡像法,就是不需要使用多個舊值做條件,只需要在表上加一個版本列,這一列可以是NUMBER或 DATE/TIMESTAMP列,加這列的作用就是用來記錄這條數據的版本(在表設計時一般我們都會給每個表增加一些NUMBER型和DATE型的冗余字段,以便擴展使用,這些冗余字段完全可以作為版本列用),在應用程序中我們每次操作對版本列做維護即可。在更新時我們把上次版本作為條件進行更新。在對一行進行更新的時候 限制條件=主鍵+版本號,同時對記錄的版本號進行更新。?

      偽代碼如下:?

    [sql]?view plaincopy
  • start?transaction;??
  • select?attributes,?old_version?from?table?where?primary_key?=????
  • attribute?Merge?operations??
  • update?table?set?version?=?old_verison?+?1?,?attributes_column?=?attributes_value?where?primary_key?=???and?version?=?old_version??
  • commit;???
  • 事務提交以后,看最后一步更新操作的記錄更新數是否為1,如果不是,則在業務上提示重試。(表明此時更新操作的并發度較高。)

    在用戶并發數比較少且沖突比較嚴重的應用系統中選擇悲觀鎖b方法,其他情況首先樂觀鎖版本列法。

    SQL Server中指定鎖:

    [sql]?view plaincopy
  • SELECT?*?FROM?table?WITH?(HOLDLOCK)?----其他事務可以讀取表,但不能更新刪除??
  • SELECT?*?FROM?table?WITH?(TABLOCKX)?-----其他事務不能讀取表,更新和刪除??
  • 不同的數據庫鎖的類型有差別,具體需要查詢各自的api doc。

    1.2.未確認的相關性(臟讀 DirtyRead)

      當一個事務讀取另一個事務尚未提交的修改時,產生臟讀。e.g.

    ????? ? 1.Mary的原工資為1000, 財務人員將Mary的工資改為了8000(但未提交事務) ?????? ?2.Mary讀取自己的工資 ,發現自己的工資變為了8000,歡天喜地!

    ???? 3.而財務發現操作有誤,回滾了事務,Mary的工資又變為了1000

    ????? 像這樣,Mary記取的工資數8000是一個臟數據。?

    ?解決辦法:如果在第一個事務提交前,任何其他事務不可讀取其修改過的值,則可以避免該問題。

    1.3.不一致的分析(不可重復讀 non-repeatable read)

     同一查詢在同一事務中多次進行,由于其他提交事務所做的修改或刪除,每次返回不同的結果集,此時發生非重復讀。e.g.

  • 在事務1中,Mary 讀取了自己的工資為1000,操作并沒有完成
  • 在事務2中,這時財務人員修改了Mary的工資為2000,并提交了事務.
  • 在事務1中,Mary 再次讀取自己的工資時,工資變為了2000
  • 解決辦法:如果只有在修改事務完全提交之后才可以讀取數據,則可以避免該問題。

    ?1.4.幻像讀?phantom read    

    ? 同一查詢在同一事務中多次進行,由于其他提交事務所做的插入操作,每次返回不同的結果集,此時發生幻像讀。當對某行執行插入或刪除操作,而該行屬于某個事務正在讀取的行的范圍時,會發生幻像讀問題。事務第一次讀的行范圍顯示出其中一行已不復存在于第二次讀或后續讀中,因為該行已被其它事務刪除。同樣,由于其它事務的插入操作,事務的第二次或后續讀顯示有一行已不存在于原始讀中。

    ?  e.g.目前工資為1000的員工有10人。

  • 事務1,讀取所有工資為1000的員工。
  • 這時事務2向employee表插入了一條員工記錄,工資也為1000。
  • 事務1再次讀取所有工資為1000的員工 共讀取到了11條記錄。?
  • 解決辦法:如果在操作事務完成數據處理之前,任何其他事務都不可以添加新數據,則可避免該問題

    討論加鎖機制,還不要了解一下數據庫的隔離機制。

    2. 數據庫隔離機制

    ???? 談到數據庫隔離機制,就不得不先說事務transaction。數據庫事務有嚴格的定義,它必須同時滿足4個特性:原子性(Atomic)、一致性(Consistency)、隔離性(Isolation)和持久性(Durabiliy),簡稱為ACID。

    原子性:保證事務中的所有操作全部執行或全部不執行。例如執行轉賬事務,要么轉賬成功,要么失敗。成功,則金額從轉出帳戶轉入到目的帳戶,并且兩個帳戶金額將發生相應的變化;失敗,則兩個賬戶的金額都不變。不會出現轉出帳戶扣了錢,而目的帳戶沒有收到錢的情況。
    一致性:保證數據庫始終保持數據的一致性——事務操作之前是一致的,事務操作之后也是一致的,不管事務成功與否。如上面的例子,轉賬之前和之后數據庫都保持數據上的一致性。
    隔 離性:多個事務并發執行的話,結果應該與多個事務串行執行效果是一樣的。在并發數據操作時,不同的事務擁有各自的數據空間,其操作不會對對方產生干擾。隔離允許事務行為獨立或隔離于其他并發運行的事務。通過控制隔離,每個事務在其行動時間里都像是修改數據庫的惟一事務。一個事務與其他事務隔離的程度稱為隔離級別。數據庫規定了多種事務隔離級別,不同隔離級別對應不同的干擾程度,隔離級別越高,數據一致性就越好,但并發性越弱。
    持久性:持久性表示事物操作完成之后,對數據庫的影響是持久的,即使數據庫因故障而受到破壞,數據庫也應該能夠恢復。通常的實現方式是采用日志。

    ?ANSI/ISO SQL92標準定義了一些數據庫操作的隔離級別。每種隔離級別指定當前事務執行時所不允許的交互作用類型,即事務間是否相互隔離,或它們是否可以讀取或更新被另一事務所使用的信息。較高隔離級別包括由較低級別所施加的限制。

    定義的4種隔離級別:

    • Read Uncommited

      可以讀取未提交記錄。此隔離級別,不會使用,忽略。

    • Read Committed (RC)

      快照讀忽略,本文不考慮。

      針對當前讀,RC隔離級別保證對讀取到的記錄加鎖 (記錄鎖),存在幻讀現象。

    • Repeatable Read (RR)

      快照讀忽略,本文不考慮。

      針對當前讀,RR隔離級別保證對讀取到的記錄加鎖 (記錄鎖),同時保證對讀取的范圍加鎖,新的滿足查詢條件的記錄不能夠插入 (間隙鎖)

    • Serializable

      從MVCC并發控制退化為基于鎖的并發控制。不區別快照讀與當前讀,所有的讀操作均為當前讀,讀加讀鎖 (S鎖),寫加寫鎖 (X鎖)。

      Serializable隔離級別下,讀寫沖突,因此并發度急劇下降,因此不建議使用。

    不同的隔離等級對應的將會導致的數據庫并發的問題總結如下:

    隔離等級
    臟讀
    不可重復讀
    幻讀
    讀未提交RU
    Yes
    Yes
    Yes
    讀已提交RC
    No
    Yes
    Yes
    可重復讀RR
    No
    No
    Yes
    串行化
    No
    No
    No
    因此,對于不同的隔離等級,需要在事務中主動加鎖,以避免這些并發的問題。

    3. 數據庫的鎖機制

    ???? 各種大型數據庫所采用的鎖的基本理論是一致的,但在具體實現上各有差別。

    ???? SQL?Server更強調由系統來管理鎖。在用戶有SQL請求時,系統分析請求,自動在滿足鎖定條件和系統性能之間為數據庫加上適當的鎖,同時系統在運行期間常常自動進行優化處理,實行動態加鎖。

    ??? SQLite采用粗放型的鎖。當一個連接要寫數據庫,所有其它的連接被鎖住,直到寫連接結束了它的事務。SQLite有一個加鎖表,來幫助不同的寫數據庫都能夠在最后一刻再加鎖,以保證最大的并發性。

    ?????MySQL數據庫由于其自身架構的特點,存在多種數據存儲引擎,每種存儲引擎所針對的應用場景特點都不太一樣,為了滿足各自特定應用場景的需求,每種存儲引擎的鎖定機制都是為各自所面對的特定場景而優化設計,所以各存儲引擎的鎖定機制也有較大區別。
    總的來說,MySQL各存儲引擎使用了三種類型(級別)的鎖定機制:行級鎖定,頁級鎖定和表級鎖定。

    ???? 對于一般的用戶而言,通過系統的自動鎖定管理機制基本可以滿足使用要求。 但是涉及到寫操作,還是一定要理解隔離機制和并發可能帶來的問題,在事務中或者SQL中加入鎖機制。對于數據庫的死鎖,一般數據庫系統都會有一套機制去解鎖,一般不會造成數據庫的癱瘓,但解鎖的過程會造成數據庫性能的急速下降,反映到程序上就會造成程序的反應性能的下降,并且會造成程序有的操作失敗。????

    ???? 在實際開發中,要充分考慮所有可能的并發可能,既不能加作用的鎖,又要保證數據處理的正確性。因此,深刻理解鎖有非常重要的現實意義。

    3.1 快照讀VS當前讀

    ?????? 多版本的并發控制協議——MVCC (Multi-Version Concurrency Control) 最大的好處,相信也是耳熟能詳:讀不加鎖,讀寫不沖突。在讀多寫少的OLTP應用中,讀寫不沖突是非常重要的,極大的增加了系統的并發性能,這也是為什么現階段幾乎所有的RDBMS都支持了MVCC。

    ?????? 與MVCC相對的,是基于鎖的并發控制,Lock-Based Concurrency Control。

    ?????? 在MVCC并發控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。當前讀,讀取的是記錄的最新版本,并且,當前讀返回的記錄,都會加上鎖,保證其他事務不會再并發修改這條記錄。?

    ???? 在一個支持MVCC并發控制的系統中,哪些讀操作是快照讀?哪些操作又是當前讀呢?以MySQL InnoDB為例:

    • 快照讀:簡單的select操作,屬于快照讀,不加鎖。(當然,也有例外,下面會分析)
      • select * from table where ?;
    • 當前讀:特殊的讀操作,插入/更新/刪除操作,屬于當前讀,需要加鎖。
      • select * from table where ? lock in share mode;
      • select * from table where ? for update;
      • insert into table values (…);
      • update table set ? where ?;
      • delete from table where ?;

      ? 所有以上的語句,都屬于當前讀,讀取記錄的最新版本。并且,讀取之后,還需要保證其他并發事務不能修改當前記錄,對讀取? 記錄加鎖。其中,除了第一條語句,對讀取記錄加S鎖 (共享鎖)外,其他的操作,都加的是X鎖 (排它鎖)。注:這個語句的加鎖是數據庫完成的。

    3.2 當前讀的加鎖

    ?????? 為什么將 插入/更新/刪除 操作,都歸為當前讀?可以看看下面這個 更新 操作,在數據庫中的執行流程:

    ???????????????????

    ??????? 從圖中,可以看到,一個Update操作的具體流程。當Update SQL被發給MySQL后,MySQL Server會根據where條件,讀取第一條滿足條件的記錄,然后InnoDB引擎會將第一條記錄返回,并加鎖 (current read)。待MySQL Server收到這條加鎖的記錄之后,會再發起一個Update請求,更新這條記錄。一條記錄操作完成,再讀取下一條記錄,直至沒有滿足條件的記錄為止。因此,Update操作內部,就包含了一個當前讀。同理,Delete操作也一樣。Insert操作會稍微有些不同,簡單來說,就是Insert操作可能會觸發Unique Key的沖突檢查,也會進行一個當前讀。

    根據上圖的交互,針對一條當前讀的SQL語句,InnoDB與MySQL Server的交互,是一條一條進行的,因此,加鎖也是一條一條進行的。先對一條滿足條件的記錄加鎖,返回給MySQL Server,做一些DML操作;然后在讀取下一條加鎖,直至讀取完畢。

    ?????? 傳統RDBMS加鎖的一個原則,就是2PL (二階段鎖): Two-Phase Locking 。相對而言,2PL比較容易理解,說的是鎖操作分為兩個階段:加鎖階段與解鎖階段,并且保證加鎖階段與解鎖階段不相交。下面,仍舊以MySQL為例,來簡單看看2PL在MySQL中的實現。

    ?

    從上圖可以看出,2PL就是將加鎖/解鎖分為兩個完全不相交的階段。加鎖階段:只加鎖,不放鎖。解鎖階段:只放鎖,不加鎖。

    ??? 如果想要學習更多的數據庫內部加鎖機制,那么請移步何登成大牛的博客:http://hedengcheng.com/?p=771

    ?

    參考資料:

    1. http://blog.csdn.NET/mshust2006/article/details/1333361

    2. http://www.poluoluo.com/jzxy/201011/98761.html

    3. http://bbs.csdn.Net/topics/60365964

    4. http://blog.csdn.net/d8111/article/details/2595635

    5. http://www.cnblogs.com/dongqingswt/archive/2013/03/28/2987367.html

    6. http://database.ctocio.com.cn/426/12256926.shtml、

    7. http://blog.sina.com.cn/s/blog_5b16e2790100dc75.html

    8. http://blog.sina.com.cn/s/blog_616b428f010163bo.html

    9. http://hedengcheng.com/?p=771#_Toc374698319


    from:?http://blog.csdn.net/anzhsoft/article/details/19132909

    總結

    以上是生活随笔為你收集整理的并发编程(四):也谈谈数据库的锁机制的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    主站蜘蛛池模板: 99在线视频免费观看 | 亚洲精品三级 | 在线国产一区二区 | 女同性做受全过程动图 | 丰满双乳秘书被老板狂揉捏 | 第一毛片 | 日韩在线一区二区三区 | 国产女主播一区二区 | 亚洲做受高潮无遮挡 | 天天摸天天操天天爽 | 波多野结衣 在线 | 日本久久免费 | av网站免费播放 | 中文字幕免费在线 | 巨乳在线播放 | 全部免费毛片 | 午夜在线视频播放 | 男生c女生 | 香蕉久久精品 | 亚洲成人av影片 | 老色鬼在线| 中国 免费 av | 性欧美成人播放77777 | 日韩一区二区三区在线观看视频 | 国产视频污在线观看 | 久久精品国产亚洲AV黑人 | 青青草这里只有精品 | 制服丝袜快播 | 黄页视频在线免费观看 | 久久综合久色欧美综合狠狠 | 亚洲高清在线视频 | 天天做天天躁天天躁 | 色网址在线| 亚洲精品在线观看免费 | 伦理久久| 亚洲欧美综合精品久久成人 | 人人看超碰 | 久久性色av | 亚洲一区二区三区视频 | 亚洲中文无码久久 | 久久久中文 | 极品女神无套呻吟啪啪 | 免费看黄色一级视频 | 日本国产精品视频 | 国产美女激情 | 中出av在线 | 久久国产精品久久国产精品 | 成人精品免费视频 | 丝袜制服一区 | 91蝌蚪91九色白浆 | 亚洲丁香婷婷 | 在线免费你懂的 | 天天看视频 | 欧美极品jizzhd欧美 | 综合视频在线 | 精品久久久一区二区 | 野战少妇38p | 天天天天射 | 国产精品啊啊啊 | 久久国内免费视频 | 欧美日韩一区二区在线观看视频 | 美女靠逼app | 国产精品1区 | 深夜视频在线看 | 午夜剧场在线 | 国产91在线观看丝袜 | 不卡中文字幕在线观看 | 亚洲精品女| 青娱乐在线视频免费观看 | 亚洲国产日韩精品 | 国产又粗又大又硬 | 波多野结衣一区二区三区中文字幕 | av免费看网址 | 在线www | 91美女在线观看 | 欧美黄色小说视频 | 96免费视频 | 一品毛片 | 久久久久亚洲av无码a片 | 午夜免费成人 | 国产一区二区三区四区视频 | 天天撸在线视频 | 成人在线一区二区三区 | 黑料视频在线观看 | 欧美字幕 | 日本一本在线 | 国产美女无遮挡永久免费 | 三级五月天 | 国产成人亚洲精品无码h在线 | 日韩综合网 | 国产日本视频 | 一区二区成人在线 | 高h喷汁呻吟3p | 超碰在线91 | 国产乱色精品成人免费视频 | 永久免费精品影视网站 | 殴美一级黄色片 | 你懂的亚洲 | 成年人黄色网址 |