MSSQL同時操作數據加鎖問題


加鎖是在操作數據時進行了,不能事后加鎖。

例: begin   tran  
        insert   表   with(TABLOCKX)     --加鎖  
        (字段列表)   values(值列表)  
        commit   tran

其他鎖的示例  
   
  --設tb(A,B,C)  
  create   table   #tb(A   varchar(2),B   varchar(2),C   varchar(2))  
  insert   into   #tb  
  select   'a1','b1','c1'  
  union   all   select   'a2','b2','c2'  
  union   all   select   'a3','b3','c3'  
   
  --1)排它鎖  
  --在第一個連接中執行以下語句  
  begin   tran  
        update   #tb  
        set   A='aa'  
        where   B='b2'  
        waitfor   delay   '00:00:3'     --等待3秒  
  commit   tran  
   
  --在第二個連接中執行以下語句  
  begin   tran  
        select   *   from   #tb  
        where   B='b2'        
  commit   tran  
  --若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒  
   
  --2)共享鎖  
  --在第一個連接中執行以下語句  
  begin   tran  
        select   *   from   #tb   holdlock   --holdlock人為加鎖  
        where   B='b2'    
        waitfor   delay   '00:00:3'     --等待3秒  
  commit   tran  
   
  --在第二個連接中執行以下語句  
  begin   tran  
        select   A,C   from   #tb  
        where   B='b2'    
        update   #tb  
        set   A='aa'  
        where   B='b2'        
  commit   tran  
  --若同時執行上述兩個語句,則第二個連接中的select查詢可以執行  
  --而update必須等待第一個連接中的共享鎖結束后才能執行   即要等待30秒  
   
  --3)死鎖  
  --增設tb2(D,E)  
  create   table   #tb2(D   varchar(2),E   varchar(2))  
  insert   into   #tb2  
  select   'd1','e1'  
  union   all   select   'd2','e2'  
   
  --在第一個連接中執行以下語句  
  begin   tran  
        update   #tb  
        set   A='aa'  
        where   B='b2'    
        waitfor     delay   '00:00:5'  
        update   #tb2  
        set   D='d5'  
        where   E='e1'    
  commit   tran  
         
  --在第二個連接中執行以下語句  
  begin   tran  
        update   #tb2  
        set   D='d5'  
        where   E='e1'    
        waitfor     delay   '00:00:3'  
        update   #tb  
        set   A='aa'  
        where   B='b2'      
  commit   tran  
   
  --刪除臨時表  
  drop   table   #tb,#tb2  
   
  --同時執行,系統會檢測出死鎖,並中止進程  
  /*-------------------------------------------------------------  
  SET   IMPLICIT_TRANSACTIONS     ON   --用戶每次必須顯式提交或回滾。否則當用戶斷開連接時,  
                                                              --事務及其所包含的所有數據更改將回滾  
   
  SET   IMPLICIT_TRANSACTIONS     OFF   --自動提交模式。在自動提交模式下,如果各個語句成功  
                                                                --完成則提交。  
-----------------------------------------------------------------------------------------------------------------------參考:  
   
  1.問:有什么樣的辦法   讓幾個程序   同時調用   同一個或者不同存貯過程   同時更新數據表的   同一行的不同字段時   互不干擾   各完成各的操作?  
  A:mssqlserver2000默認的lock   的粒度是行級,所以如果一個線程在update一條記錄時,就在該行加了排他鎖,所以其它的線程是無法讀取該記錄(除非可以臟讀),這是因為在mssqlserver中是不可以同時給一條記錄加不同的鎖。另外mssqlserver沒有鎖某一列的鎖!  
   
  所以讓幾個程序   同時調用   同一個或者不同存貯過程   同時更新數據表的   同一行的不同字段時如果一個在更新,其他的就只能WAIT....  
   
   
     
   
  2.   如何鎖一個表的某一行  
   
   
  A   連接中執行  
   
  SET   TRANSACTION   ISOLATION   LEVEL   REPEATABLE   READ  
   
  begin   tran  
   
  select   *   from   tablename   with   (rowlock)   where   id=3  
   
  waitfor   delay   '00:00:05'  
   
  commit   tran  
   
  B連接中如果執行  
   
  update   tablename   set   colname='10'   where   id=3   --則要等待5秒  
   
  update   tablename   set   colname='10'   where   id<>3   --可立即執行  
   
   
   
  3.   鎖定數據庫的一個表  
   
  SELECT   *   FROM   table   WITH   (HOLDLOCK)    
   
   
  注意:   鎖定數據庫的一個表的區別  
   
  SELECT   *   FROM   table   WITH   (HOLDLOCK)    
  其他事務可以讀取表,但不能更新刪除  
   
  SELECT   *   FROM   table   WITH   (TABLOCKX)    
  其他事務不能讀取表,更新和刪除  
   
  SELECT   語句中“加鎖選項”的功能說明  
  SQL   Server提供了強大而完備的鎖機制來幫助實現數據庫系統的並發性和高性能。用戶既能使用SQL   Server的缺省設置也可以在select   語句中使用“加鎖選項”來實現預期的效果。   本文介紹了SELECT語句中的各項“加鎖選項”以及相應的功能說明。  
  功能說明:     
  NOLOCK(不加鎖)    
  此選項被選中時,SQL   Server   在讀取或修改數據時不加任何鎖。   在這種情況下,用戶有可能讀取到未完成事務(Uncommited   Transaction)或回滾(Roll   Back)中的數據,   即所謂的“臟數據”。    
   
  HOLDLOCK(保持鎖)    
  此選項被選中時,SQL   Server   會將此共享鎖保持至整個事務結束,而不會在途中釋放。    
   
  UPDLOCK(修改鎖)    
  此選項被選中時,SQL   Server   在讀取數據時使用修改鎖來代替共享鎖,並將此鎖保持至整個事務或命令結束。使用此選項能夠保證多個進程能同時讀取數據但只有該進程能修改數據。    
   
  TABLOCK(表鎖)    
  此選項被選中時,SQL   Server   將在整個表上置共享鎖直至該命令結束。   這個選項保證其他進程只能讀取而不能修改數據。    
   
  PAGLOCK(頁鎖)    
  此選項為默認選項,   當被選中時,SQL   Server   使用共享頁鎖。    
   
  TABLOCKX(排它表鎖)    
  此選項被選中時,SQL   Server   將在整個表上置排它鎖直至該命令或事務結束。這將防止其他進程讀取或修改表中的數據。  
   
   
     
   
  4.我的程序沒有碩操作的﹐但是今天發現某行無法select,別的行都可以。  
  在管理--》目前活動--》鎖定/處理序識別碼﹐看見有被封鎖和封鎖。  
  不知道怎么開鎖。  
   
  use   master  
  go  
  create   proc   killspid   (@dbname   varchar(20))    
  as    
  begin    
  declare   @sql   nvarchar(500)    
  declare   @spid   int    
  set   @sql='declare   getspid   cursor   for    
  select   spid   from   sysprocesses   where   dbid=db_id('''+@dbname+''')'    
  exec   (@sql)    
  open   getspid    
  fetch   next   from   getspid   into   @spid    
  while   @@fetch_status   <   >-1    
  begin    
  exec('kill   '+rtrim(@spid))    
  fetch   next   from   getspid   into   @spid    
  end    
  close   getspid    
  deallocate   getspid    
  end    
   
  --用法    
  use   master    
  exec   killspid   '數據庫名'  
   
   
  5.--查看鎖信息  
  select   進程id=req_spid  
  ,數據庫=db_name(rsc_dbid)  
  ,類型=case   rsc_type   when   1   then   'NULL   資源(未使用)'  
  when   2   then   '數據庫'  
  when   3   then   '文件'  
  when   4   then   '索引'  
  when   5   then   '表'  
  when   6   then   '頁'  
  when   7   then   '鍵'  
  when   8   then   '擴展盤區'  
  when   9   then   'RID(行   ID)'  
  when   10   then   '應用程序'  
  end  
  ,rsc_objid,rsc_indid  
  from   master..syslockinfo  
   
   
  6.今想實現一個特定的操作,大概想法是這樣的:  
  在SQL   SERVER里實現對某個特定的表進行操作鎖定,應用程序要對這個表的數據進行刪除操作,必須經過審核(注:只想在SQL   SERVER里控制,不想用應用程序實現)。  
   
  用觸發器  
  create   trigger   ...  
  for   delete  
  as  
  if   exists(select   1   from   deleted   where   未審核)  
  rollback  
   
   
  5.我在SQL   SERVER里二張一樣的表,做了個TRIGGERE,可以將同樣的數據復制的那一表,在此將源表叫做A,被TRIGGER的表叫做B,A被一套程序使用,B被另一個程序使用,當B被程序訪問時(讀取),A表正好有問題要INSERT或UPDATE,此時TRIGGER起作用但寫不進B表,造成訪問A表的程序不正常,請問有什么方法可以解決嗎!?  
   
   
  用手工鎖定就行了.類似下面的例子:  
   
  --鎖定記錄,只允許單用戶修改的例子:  
   
  --創建測試環境  
  --創建測試表--部門表  
  create   table   部門(departmentid   int,name   varchar(10))  
   
  --記錄鎖定表  
  create   table   lock(departmentid   int,dt   datetime)  
   
  go  
  --因為函數中不可以用getdate,所以用個視圖,得到當前時間  
  create   view   v_getdate   as   select   dt=getdate()  
  go  
  --創建自定義函數,判斷記錄是否鎖定  
  create   function   f_chk(@departmentid   int)  
  returns   bit  
  as  
  begin  
  declare   @re   bit,@dt   datetime  
  select   @dt=dt   from   v_getdate  
  if   exists(select   1   from   lock   where   departmentid=@departmentid  
  and   datediff(ss,dt,@dt)<5)  
  set   @re=1  
  else  
  set   @re=0  
  return(@re)  
  end  
  go  
   
  --數據處理測試  
  if   dbo.f_chk(3)=1  
  print   '記錄被鎖定'  
  else  
  begin  
  begin   tran  
  insert   into   lock   values(3,getdate())  
  update   部門   set   name='A'   where   departmentid=3  
  delete   from   lock   where   departmentid=3  
  commit   tran  
  end  
   
  --刪除測試環境  
  drop   table   部門  
  drop   view   v_getdate  
  drop   function   f_chk  
   
   
   
  即創建一個鎖表,在B表被訪問時,添加一個記錄到鎖表中,如果A表發生更新,首先判斷鎖表的內容,如果被鎖定,則觸發器失敗.  
   
  a.創建鎖表  
  create   table   鎖表(lock   bit,dt   datetime)  
   
  b.B表被訪問時:  
  insert   into   鎖表   values(1,getdate())  
  訪問B表...  
  訪問B表結束  
  truncate   talbe   鎖表  
   
  c.A表的觸發器  
  create   trigger   t_process   on   A表  
  for   insert,delete,update  
  as  
  if   exists(select   1   from   鎖表   where   datediff(ss,dt,getdate())<20)   --判斷時間是防止死鎖,即B表被鎖定的最長時間為20秒,超過此時間表示B表被死鎖  
  rollback   tran  
  else  
  begin  
  ..同步處理  
  end  
  go  
   
   
  6.死鎖可以查一下:  
  1:sp_who   或   sp_who2  
  2:   Select   *   from   sysprocesses   where   blocked   <>   0  
  3:   企業管理器->服務器->管理工具->活動->當前活動   然后把他kill掉。。。  
  4:SQL事件探查器,監控一下,看主要是那些處理引起的死鎖.然后做相應的處理.   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM