我有一个 SQL Server 数据库,其中有一个带有触发器的表,该触发器在插入后执行。如果我直接一个接一个地插入两个条目,那么只有在触发器执行完成后才插入第二个条目,这一点很重要。我可以依靠这个吗?或者我可能会在某个时候遇到有问题的竞争条件?
触发器的代码如下所示:
ALTER TRIGGER [dbo].[TR_MachineState_Desable_OldData_ON_Insert]
ON [dbo].[machine_state]
AFTER INSERT
AS
BEGIN
DECLARE @RowID INT;
DECLARE @Name NVARCHAR(30);
DECLARE @MachineState NVARCHAR(30);
DECLARE @Devicescount INT;
DECLARE @StartedOn DATETIME;
DECLARE @CreateOn DATETIME;
DECLARE @ToolName NVarchar(30);
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
SELECT
@RowID=[RowId]
,@Name= [Name]
,@MachineState=[MachineState]
,@Devicescount=[Devicescount]
,@StartedOn= [StartedOn]
,@CreateOn =[ActionDate]
,@ToolName=[ToolName]
from inserted ;
update [machine_state]
set [IsActive]=0
where [Name] =@Name and ToolName = @ToolName and RowId <> @RowID
update machine_state
set IsActive =1
where RowId=@RowID
END
正如您所看到的,触发器确保只有具有相同工具名称和相同名称的最后一个条目才为IsActive
true。
哦亲爱的
如果有人向该表中插入了不止一行,那么您将遇到一个更大的问题。你的触发器将有一个相当不确定的时间。
但是不,不能保证当另一行到达时您的触发器已经完成执行。
您可能想使用SQL Query Stress等工具在更高的并发性下尝试插入。
虽然不能保证不同语句的触发器的执行,但正确的锁定应该可以防止出现任何问题。
正如其他人提到的,您需要修复无法正确处理多行(或零行!)的巨大错误。
您需要一个索引
machine_state (Name, ToolName) INCLUDE (RowId, IsActive)
才能使锁定正常工作。您还需要我添加的额外检查,以确保有人不会尝试Name, ToolName
立即添加重复的行,否则结果将是不确定的。抛开所有这些不谈,我强烈建议您考虑使用Temporal Tables,而不是尝试自己制作不太好的版本。Temporal Tables 会自动处理已存档的非活动行,然后您可以在上使用普通主键
Name, ToolName
。