目前公司的項目中碰到一個情況:需要向一個數據表table1中插入記錄,該表的結構類似於下面的定義:
列名 | 類型 | 是否允許為空 |
Id | int | no |
Area | string | no |
AreaIndex | int | no |
Name | string | no |
其中Name的值由Area和AreaIndex拼接而成,形式類似於“Area+AreaIndex”。對於相同的Area,AreaIndex從1開始計數,所以對於Area分別為“AA”,“BB”,“CC”的情況,Name的值類似下面這樣:
AA001 AA002 BB001 AA003 BB002 CC001這種形式。
當插入新值的時候,需要判斷數據表中該Area的最大AreaIndex,在此基礎上加1做為新行的AreaIndex,同時拼接Name到數據庫中。在數據庫並發的情況下,會出現大量相同記錄的情況。
目前想到的一個比較好的解決方法就是:
1,創建一個新表Table2來存儲Area的最大AreaIndex,當插入新記錄時,從新表中獲取最大AreaIndex,加一作為新記錄的AreaIndex,同時更新新表的最大AreaIndex。
2,創建一個新的存儲過程來添加記錄到表中。在該存儲過程中,先查詢Table2並鎖定該表。獲取插入記錄對應Area的最大AreaIndex並更新Table2中的記錄后,插入記錄到Table1中。存儲過程的代碼類似下面這樣:
BEGIN
BEGIN TRAN
DECLARE @MaxAreaIndex int
--查詢並鎖定Table2
SELECT @MaxAreaIndex = AreaIndex
FROM Table2 WITH (TABLOCKX)
WHERE Area= @Area
--獲取到最大的AreaIndex后,更新Table2
IF @MaxAreaIndex IS NULL
BEGIN
--如果Table2中沒有記錄,則新增一條記錄
SET @MaxAreaIndex = 1
INSERT INTO [Table2]
([MaxAreaIndex] ,[Area])
VALUES
(@MaxAreaIndex, @Area)
END
ELSE
BEGIN
SET @MaxAreaIndex = @MaxAreaIndex + 1
UPDATE Table2
SET MaxAreaIndex = @MaxAreaIndex
WHERE Area = @Area
END
INSERT INTO Table1
([Name] ,[Area] ,[AreaIndex])
VALUES
(@Area+ RTRIM(LTRIM(STR(@MaxAreaIndex))) ,@Area ,@MaxAreaIndex)
COMMIT TRAN
關鍵的代碼在:
SELECT @MaxAreaIndex = AreaIndex
FROM Table2 WITH (TABLOCKX)
WHERE Area= @Area
當在存儲過程中對表Table2進行加鎖后,其他對該存儲過程的調用就必須等待前一次執行完成並釋放對表的鎖定后才能繼續執行。
在Area不是很多的情況下,效率沒有大的影響。