我有一个从业务代码调用的存储过程。此代码使用并行性,因此根据某些条件,此SP的多个实例可以同时运行。
此SP中有一些逻辑我只想执行一次。我有一个表(我们称之为HISTORY),它包含运行的UID和执行此部分代码时的DATETIME。这是我的流程:
SP BEGIN
-- some logic
IF certain conditions are met, check if HISTORY does not have an entry for the UID
1. Add an entry in HISTORY for the current UID
2. Run the once only code
SP END
问题在于,如果不同的实例同时到达该部分,有时上述逻辑仍会被执行多次。我该怎么做才能确保它只运行一次?
谢谢!
答案 0 :(得分:1)
BEGIN TRANSACTION;
INSERT [HISTORY](UID, ...)
SELECT @UID, ...
WHERE NOT EXISTS (
SELECT * FROM [HISTORY] WITH (HOLDLOCK) WHERE UID = @UID
);
IF @@ROWCOUNT = 1 BEGIN;
-- we inserted, do logic that should run only once
END;
COMMIT;
HOLDLOCK
(相当于在SERIALIZABLE
下运行事务,但更精细)确保并行运行的其他事务不能在HISTORY
中为该UID插入条目;尝试这样的任何事务都将阻塞,直到第一个INSERT
完成然后返回(因为一行已经存在)。确保UID
上的索引存在,否则会锁定比性能健康更多的索引。
正确获取这样的代码总是很棘手,因此请务必在实践中对同一(和不同)UID的并发插入进行压力测试。