我遇到從我的SQL語句中遇到死鎖,如果它存在,我想選擇它,否則插入並選擇它。我使用雙重檢查鎖定來防止鎖定開銷,建議here。在SQL中使用雙重檢查鎖定的死鎖
很明顯,我這樣做是爲了支持併發插入,而且我正在運行多個線程。我的SQL技巧非常低,所以我可能錯過了關於鎖定的基本知識?這裏是我的方法:
CREATE PROCEDURE InsertAndOrSelectZipCity
@PostalDistrict nvarchar(25),
@CityName nvarchar(34),
@MunicipalityId smallint,
@ZipCode smallint
AS
DECLARE @id AS INT
SELECT @id = ZipCityId FROM ZipCity (NOLOCK) WHERE [email protected] AND [email protected]
IF @id IS NULL
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT @id = ZipCityId FROM ZipCity WHERE [email protected] AND [email protected]
IF @id IS NULL
BEGIN
INSERT INTO ZipCity (PostalDistrict, CityName, MunicipalityId, ZipCode) VALUES (@PostalDistrict, @CityName, @MunicipalityId, @ZipCode)
SELECT @id = SCOPE_IDENTITY()
END
COMMIT TRANSACTION
END
SELECT @id
UPDATE
這是通過使用在TRANSATION內SELECT語句中的適當的鎖(XLOCK,ROWLOCK,HOLDLOCK)固定。
以下是使用MERGE語句來代替,沒有事務需要編寫的程序:
DECLARE @id as INT
MERGE INTO ZipCity WITH (TABLOCK) AS Target
USING (SELECT @PostalDistrict, @CityName, @MunicipalityId, @ZipCode) AS Source (PostalDistrict, CityName, MunicipalityId, ZipCode)
ON Target.MunicipalityId = Source.MunicipalityId AND Target.ZipCode = Source.ZipCode
WHEN MATCHED THEN
UPDATE SET @id = Target.ZipCityId
WHEN NOT MATCHED THEN
INSERT (PostalDistrict, CityName, MunicipalityId, ZipCode) VALUES (@PostalDistrict, @CityName, @MunicipalityId, @ZipCode)
OUTPUT INSERTED.ZipCityId;
這樣做 - 謝謝!對於MERGE建議,如果我的數據是靜態的,那麼不得不使用UPDATE語句的開銷嗎?例如。每個ZipCity行總是相同的。 – Jeppebm
MERGE可以包含任何您想要的子句的組合。你可以只有一個不匹配然後插入,沒有別的。合併是所有其他DML語句的超集。 – usr
輝煌。使用MERGE後,我會不得不選擇(NOLOCK)後ZipCityID,以實現相同的輸出和功能? – Jeppebm