<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                在[數據庫(五),事務](http://www.cnblogs.com/dy2903/p/8438209.html)里面我們講了事務ACID屬性,事務最重要的能在異常情況的修復以及并發連接的處理上。 異常情況的修復主要通過**日志**來完成,那么并發連接的處理主要通過**鎖**。本章主要整理的是**鎖**的相關知識。 # 為什么需要鎖? 現在Bob的賬戶里面有1000塊錢,此時程序突然同時來了兩個要求,一個要把Bob的錢轉給Smith 20塊,一個要把Bob的錢轉Joe 30塊。這兩個要求一查Bob的賬戶,都發現現在Bob有1000塊,所以要求A算出現在Bob應該有980塊,要求B算出來Bob應有970。要求A的數據被要求B的數據覆蓋了。 這樣就出問題了,明明應該扣50塊錢,現在卻只是扣了30塊。 **鎖**就是用來解決這樣的并發訪問的問題。當每次訪問Bob賬戶之前,都加一個鎖,禁止別人再次訪問,只有**等待持有鎖的人來釋放** ![image.png](http://upload-images.jianshu.io/upload_images/1323506-dadfa6419f8635b7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # 悲觀鎖和樂觀鎖 ## 悲觀鎖 如果事務A把Bob賬戶鎖住了,事務B自然不能操作Bob賬戶,也就是說其他線程只能在外面等待。 這種加鎖的方式就是**悲觀鎖**。它每次取讀寫數據時總認為數據會被別人修改,所以將數據加鎖,置于鎖定狀態,不讓別人訪問。 缺點是如果持有鎖的時間太長,其他用戶需要等待很長的時間。 悲觀鎖主要適用于**并發爭搶**比較嚴重的場景。 ## 樂觀鎖 悲觀鎖的問題顯而易見,如果將數據加鎖了以后,其他的線程是無法訪問的,只能等待。如果持有鎖的時間太長,需要等待大量的時間。 所以我們引入了**樂觀鎖**,所謂樂觀鎖是認為一般情況下不會有太多的人修改余額,所有沒有加鎖,只有在最后更新的時候才去看是否有沖突。 那**具體怎么做呢?** 可以在日志中加上一個version(版本)字段, - 每次**讀**的時候,不僅需要讀出余額,還需要讀出版本號。 - 等修改了余額以后,往回寫之前需要檢查一下版本號,看看與讀的時候版本號是否一樣。 - 如果不一樣,說明數據已經被改變了,所以需要放棄寫操作,重新讀取余額和版本號 - 如果一樣,則將新余額寫回去,把版本號加1 。 比如 事務1把Bob的余額減去30,此時它讀到了(Bob余額=1000,版本=1) 事務2也需要將Bob的余額減去50,他也讀到了(Bob余額=1000,版本=1) 然后事務1率先完成計算,把新的余額值970寫回了,版本 加 1 ,變成了版本2。 事務2寫回去的時候,發現最新的版本號變為2,表示之前讀的數據已經改變,所以需要**重新讀一遍** 這就是樂觀鎖,這種方式**適合于沖突不多的場景**,如果沖突很多,數據爭用激烈,會導致不斷的嘗試,反而降低了性能。 ![image.png](http://upload-images.jianshu.io/upload_images/1323506-0ee87c4c302e4d9f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) # 死鎖 ## 死鎖產生的條件 如果出現如下這種情況 - 有兩個**線程**同時參與 - 這兩個線程在**不同方向**給同一個資源加鎖 - 爭搶相同的**資源** 那么很可能出現死鎖 比如事務1是Bob給Smith轉賬,事務2是Smith給Bob轉賬。 當這兩個事務單元同時發生的時候,就有問題呢。 事務單元1會先鎖定Bob,然后鎖定Smith,而事務單元2會先鎖定Smith,然后鎖定Bob 事務1會等待事務2把Bob給釋放了,而事務2在等待事務1把Smith釋放了。 ![image.png](http://upload-images.jianshu.io/upload_images/1323506-ce9291d2b340f666.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ## 如何解決 那么如何解決死鎖呢?最好的方法是盡可能不出現死鎖,當然很難。或者說如果鎖定時間超時了,則強行釋放,不過這種方法效率比較低,因為如果有用戶的事務本來時間就很長,則每個死鎖的檢測時間將會很長。 所以最優的方案在于**預測死鎖,**可以把**事務單元等待的鎖記錄下來** 比如下圖中,事務單元1持有"Lock Bob"的鎖,現在又在申請一把"Lock Smith"的鎖,在申請之前,可以查看同樣申請了"Lock Smith"的有哪些事務單元。明顯事務單元2也申請過這把鎖。好了,下一步是看事務單元2在申請什么鎖呢,發現它居然在申請"Lock Bob"這把鎖,而這把鎖目前由事務單元1持有。所以現在已經發現有死鎖的可能了,也就是發生了**碰撞**。所以可以提前補救。 ![image.png](http://upload-images.jianshu.io/upload_images/1323506-75256e3d01332df6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ## U鎖 下面來討論一種死鎖的情況。如下圖 ![image.png](http://upload-images.jianshu.io/upload_images/1323506-6b72969e647dc84a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 事務1 Trx1 > 開始事務1 讀A(讀鎖) A - 100(讀鎖需要升級為寫鎖) 提交事務1 事務2 Trx2 > 開始事務2 讀A(讀鎖) A - 100(讀鎖需要升級為寫鎖) 提交事務2(解鎖) 事務1和事務2的讀鎖是可以并行的,所以讀鎖可以同時進入臨界區,但是寫鎖不能,會被擋在外面。此時事務2又發起了寫鎖。那么尷尬的局面就產生了。 事務1的寫鎖需要等事務2的讀鎖釋放資源。 事務2的寫鎖需要等待事務1的讀鎖釋放資源。 所以形成了死鎖。其實這種死鎖的形成條件非常的簡單,**只需要針對同一個數據進行讀寫**。比如說`update set A=A-1 where id = 100`如果運行多次,就會出現死鎖 解決的辦法是引入**U鎖**,可以將讀鎖直接升級為寫鎖。 對于事務1,讀以后馬上就是寫,所以直接就使用寫鎖,而不是讀鎖呢。 ![image.png](http://upload-images.jianshu.io/upload_images/1323506-f1aefbc2a654deca.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 同理事務2也是如此。 ![image.png](http://upload-images.jianshu.io/upload_images/1323506-87ad69908d3a26d9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ![image.png](http://upload-images.jianshu.io/upload_images/1323506-944ae00be056cc65.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看