天天看點

sql給資料庫加鎖問題

加鎖是在操作資料時進行了,不能事後加鎖。

例: 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  

  --在第二個連接配接中執行以下語句  

        select   *   from   #tb  

        where   B='b2'        

  --若同時執行上述兩個語句,則select查詢必須等待update執行完畢才能執行即要等待30秒  

  --2)共享鎖  

        select   *   from   #tb   holdlock   --holdlock人為加鎖  

        where   B='b2'    

        select   A,C   from   #tb  

  --若同時執行上述兩個語句,則第二個連接配接中的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'  

        waitfor     delay   '00:00:5'  

        update   #tb2  

        set   D='d5'  

        where   E='e1'    

        waitfor     delay   '00:00:3'  

        where   B='b2'      

  --删除臨時表  

  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  

  select   *   from   tablename   with   (rowlock)   where   id=3  

  waitfor   delay   '00:00:05'  

  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   (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    

  exec('kill   '+rtrim(@spid))    

  end    

  close   getspid    

  deallocate   getspid    

  --用法    

  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)  

  --因為函數中不可以用getdate,是以用個視圖,得到目前時間  

  create   view   v_getdate   as   select   dt=getdate()  

  --建立自定義函數,判斷記錄是否鎖定  

  create   function   f_chk(@departmentid   int)  

  returns   bit  

  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)  

  --資料處理測試  

  if   dbo.f_chk(3)=1  

  print   '記錄被鎖定'  

  insert   into   lock   values(3,getdate())  

  update   部門   set   name='A'   where   departmentid=3  

  delete   from   lock   where   departmentid=3  

  --删除測試環境  

  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  

  if   exists(select   1   from   鎖表   where   datediff(ss,dt,getdate())<20)   --判斷時間是防止死鎖,即B表被鎖定的最長時間為20秒,超過此時間表示B表被死鎖  

  rollback   tran  

  ..同步處理  

  6.死鎖可以查一下:  

  1:sp_who   或   sp_who2  

  2:   Select   *   from   sysprocesses   where   blocked   <>   0  

  3:   企業管理器->伺服器->管理工具->活動->目前活動   然後把他kill掉。。。  

  4:SQL事件探查器,監控一下,看主要是那些處理引起的死鎖.然後做相應的處理.