加鎖是在操作數據時進行了,不能事后加鎖。
例: 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事件探查器,監控一下,看主要是那些處理引起的死鎖.然后做相應的處理.