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事件探查器,監控一下,看主要是那些處理引起的死鎖.然后做相應的處理.???
轉載于:https://www.cnblogs.com/cxd4321/archive/2012/06/10/2544417.html
總結
以上是生活随笔為你收集整理的MSSQL同时操作数据加锁问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 生成和验证注册码的基本思路
- 下一篇: Expect 在网络管理中发挥着重要作用