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