場景:多個客戶端並發,同時調用同一個存儲過程,如何處理,使之查詢數據不會出現重復?
解決方法:
在查詢的表上使用排它鎖
存儲過程示例:
CREATE PROCEDURE id_test @deal_no varchar(10) output, @getno_date varchar(50) output AS declare @id int declare @curr_id int --開始事務 BEGIN TRANSACTION select @curr_id = isnull(curr_id,0) + 1 from tb_sm_id with (TABLOCKX) --查詢時加排他鎖 --延遲100毫秒再更新 WAITFOR DELAY '00:00:00.100' update tb_sm_id set curr_id = @curr_id set @deal_no = 'A' + right('000000' + cast(@curr_id as varchar(10)),5) select @id = isnull(max(id),0) + 1 from tb_sm_data with (TabLOCKx)--查詢時加排他鎖 insert into tb_sm_data(id,deal_no) values(@id,@deal_no) declare @update_date datetime declare @ms int --查詢datetime select @update_date = update_date from tb_sm_data where id = @id select @ms = datepart(ms,@update_date) --轉換成帶毫秒的字符串日期 set @getno_date = convert(varchar(20),@update_date,120) + '.' + right('000' +cast(@ms as varchar(3)),3) --提交事務 COMMIT TRANSACTION
兩個表:
CREATE TABLE [dbo].[tb_sm_id] ( [curr_id] [int] NULL ) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tb_sm_data] ( [id] [int] NULL , [deal_no] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL , [update_date] [datetime] NOT NULL ) ON [PRIMARY] GO
附錄
鎖定提示
可以使用 SELECT、INSERT、UPDATE 和 DELETE 語句指定表級鎖定提示的范圍,以引導 Microsoft® SQL Server™ 2000 使用所需的鎖類型。當需要對對象所獲得鎖類型進行更精細控制時,可以使用表級鎖定提示。這些鎖定提示取代了會話的當前事務隔離級別。
說明 SQL Server 查詢優化器自動作出正確的決定。建議僅在必要時才使用表級鎖定提示更改默認的鎖定行為。禁止鎖定級別反過來會影響並發。
鎖定提示 | 描述 |
---|---|
HOLDLOCK | 將共享鎖保留到事務完成,而不是在相應的表、行或數據頁不再需要時就立即釋放鎖。HOLDLOCK 等同於 SERIALIZABLE。 |
NOLOCK | 不要發出共享鎖,並且不要提供排它鎖。當此選項生效時,可能會讀取未提交的事務或一組在讀取中間回滾的頁面。有可能發生臟讀。僅應用於 SELECT 語句。 |
PAGLOCK | 在通常使用單個表鎖的地方采用頁鎖。 |
READCOMMITTED | 用與運行在提交讀隔離級別的事務相同的鎖語義執行掃描。默認情況下,SQL Server 2000 在此隔離級別上操作。 |
READPAST | 跳過鎖定行。此選項導致事務跳過由其它事務鎖定的行(這些行平常會顯示在結果集內),而不是阻塞該事務,使其等待其它事務釋放在這些行上的鎖。READPAST 鎖提示僅適用於運行在提交讀隔離級別的事務,並且只在行級鎖之后讀取。僅適用於 SELECT 語句。 |
READUNCOMMITTED | 等同於 NOLOCK。 |
REPEATABLEREAD | 用與運行在可重復讀隔離級別的事務相同的鎖語義執行掃描。 |
ROWLOCK | 使用行級鎖,而不使用粒度更粗的頁級鎖和表級鎖。 |
SERIALIZABLE | 用與運行在可串行讀隔離級別的事務相同的鎖語義執行掃描。等同於 HOLDLOCK。 |
TABLOCK | 使用表鎖代替粒度更細的行級鎖或頁級鎖。在語句結束前,SQL Server 一直持有該鎖。但是,如果同時指定 HOLDLOCK,那么在事務結束之前,鎖將被一直持有。 |
TABLOCKX | 使用表的排它鎖。該鎖可以防止其它事務讀取或更新表,並在語句或事務結束前一直持有。 |
UPDLOCK | 讀取表時使用更新鎖,而不使用共享鎖,並將鎖一直保留到語句或事務的結束。UPDLOCK 的優點是允許您讀取數據(不阻塞其它事務)並在以后更新數據,同時確保自從上次讀取數據后數據沒有被更改。 |
XLOCK | 使用排它鎖並一直保持到由語句處理的所有數據上的事務結束時。可以使用 PAGLOCK 或 TABLOCK 指定該鎖,這種情況下排它鎖適用於適當級別的粒度。 |
例如,如果將事務隔離級別設置為 SERIALIZABLE,並且在 SELECT 語句中使用表級鎖定提示 NOLOCK,則鍵范圍鎖通常用於維護不采用可串行事務。
USE pubs
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
GO
BEGIN TRANSACTION
SELECT au_lname FROM authors WITH (NOLOCK)
GO
生成的鎖是:
EXEC sp_lock
GO