timestamp應用(解決並發問題)——樂觀鎖和悲觀鎖

來源:互聯網
上載者:User

       這種資料類型表現自動產生的位元,確保這些數在資料庫中是唯一的。timestamp 一般用作給表行加版本戳的機制。儲存大小為 8 位元組。

      一個表只能有一個 timestamp 列。每次插入或更新包含 timestamp 列的行時,timestamp 列中的值均會更新。這一屬性使 timestamp 列不適合作為鍵使用,尤其是不能作為主鍵使用。對行的任何更新都會更改 timestamp 值,從而更改索引值。如果該列屬於主鍵,那麼舊的索引值將無效,進而引用該舊值的外鍵也將不再有效。如果該表在動態資料指標中引用,則所有更新均會更改遊標中行的位置。如果該列屬於索引鍵,則對資料行的所有更新還將導致索引更新。

     不可為空白的 timestamp 列在語義上等價於 binary(8) 列。可為空白的 timestamp 列在語義上等價於 varbinary(8) 列。

     在實際的多使用者並發訪問的生產環境裡邊,我們經常要儘可能的保持資料的一致性。而其中最典型的例子就是我們從表裡邊讀取資料,檢查驗證後對資料進行修改,然後寫回到資料庫中。在讀取和寫入的過程中,如果在多使用者並發的環境裡邊,其他使用者已經把你要修改的資料

進行了修改是非常有可能發生的情況,這樣就造成了資料的不一致性。解決這樣的辦法,SQL SERVER提出了樂觀鎖定和悲觀鎖定的概念,下邊我以一個執行個體來說明如何使用樂觀鎖定和悲觀鎖定來解決這樣的問題。

/* 建立測試表:Train_ticket,代表一個真實的火車票庫,供使用者註冊.使用者要從裡邊購買一個未使用的火車票,也就是S_Flag=0的票,給使用者註冊:更新T_Name,T_Time,S_Flag欄位. 如果出現兩個使用者同時更新一張票的情況,是不能容忍的,也就是我們所說的資料不一致行。*/

create table Train_ticket(T_NO varchar(20),T_Name varchar(20),S_Flag bit,T_Time datetime)

悲觀鎖定解決方案

Begin Tran

select top 1 @TrainNo=T_NO

         from Train_ticket   with (UPDLOCK)   where S_Flag=0


      update Train_ticket

         set T_Name=user,

             T_Time=getdate(),

             S_Flag=1

         where T_NO=@TrainNo

commit

注意其中的區別了嗎?with(updlock),是的,我們在查詢的時候使用了with (UPDLOCK)選項,在查詢記錄的時候我們就對記錄加上了更新鎖定,表示我們即將對次記錄進行更新.注意更新鎖定和共用鎖定是不衝突的,也就是其他使用者還可以查詢此表的內容,但是和更新鎖定和排它鎖是衝突的.所以其他的更新使用者就會阻塞.如果我們在另外一個視窗執行此代碼,同樣不加waifor delay子句.兩邊執行完畢後,我們發現成功的註冊了兩張火車票.可能我們已經發現了悲觀鎖定的缺點:當一個使用者進行更新的事務的時候,其他更新使用者必須排隊等待,即使那個使用者更新的不是同一條記錄.

樂觀鎖定解決方案

--   首先我們在Train_ticket表裡邊加上一列T_TimeStamp 列,該列是varbinary(8)類型.但是在更新的時候這個值會自動成長.

alter table Train_ticket add   T_TimeStamp timestamp not null

--   取得號和原始的時間戳記值

         select top 1 @TrainNo=T_No,

                     @timestamp=T_TimeStamp

        from Train_ticket

         where S_Flag=0

        

         --   延遲50秒,類比並發訪問.

         waitfor delay '000:00:50'

         --   購買票,但是要比較時間戳記是否發生了變化.如果沒有發生變化.更新成功.如果發生變化,更新失敗.

         update Train_ticket

         set T_Name=user,

             T_Time=getdate(),

             S_Flag=1

         where T_No = @TrainNo and F_TimeStamp = @timestamp


        set @rowcount=@@rowcount

         if @rowcount=1

         begin

                 print 'Successful!'

                 commit

         end

         else if @rowcount=0

         begin

                 if exists(select 1 from Train_ticket where T_No = @TrainNo)

                begin

                         print 'The ticket was already buyed.'

                         rollback tran

                 end

                 else

                 begin

                         print 'This ticket doesn't exist!'

                         rollback tran

                 end

         end

      上邊我詳細介紹了樂觀鎖定和悲觀鎖定的使用方法,在實際生產環境裡邊,如果並發量不大,我們完全可以使用悲觀鎖定的方法,因為這種方法使用起來非常方便和簡單.但是如果系統的並發非常大的話,悲觀鎖定會帶來非常大的效能問題,所以我們就要選擇樂觀鎖定的方法.

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.