所以我有这个存储过程将消息插入我的数据库。我希望阻止用户在短时间内发布重复邮件,无论是出于意外还是故意(延迟连接或垃圾邮件发送者)。
这就是insert语句的样子:
IF NOT EXISTS (SELECT * FROM tblMessages WHERE message = @message and ip = @ip and datediff(minute,timestamp, getdate()) < 10)
BEGIN
INSERT INTO tblMessages (ip, message, votes, latitude, longitude, location, timestamp, flags, deleted, username, parentId)
VALUES (@ip, @message, 0, @latitude, @longitude, @location, GETDATE(), 0, 0, @username, @parentId)
END
你可以看到我检查同一个用户是否在10分钟内发布了相同的消息,如果没有,我发布它。我昨天仍然看到一个骗局。当我检查数据库中两个消息的时间戳时,它们完全相同,一直到第二个,所以我猜这个'存在'检查在每个插入时运行,两个都回空,所以它们都插入正常(在基本相同的时间)。
我可以通过什么方式防止这种情况正确发生?
答案 0 :(得分:1)
实际上Derek Kromm并不遥远;基本上你确实需要一个唯一约束,你只需要其中一列的范围。
您可以将其表达为filtered index,它会强制您想要的列的唯一性,但使用过滤器来匹配10分钟范围内的时间戳。
CREATE NONCLUSTERED INDEX IX_UNC_tblMessages
ON tblMessages (message, ip, timestamp)
WHERE datediff(minute, timestamp, getdate()) < 10)
关于唯一约束和保持唯一性(MSDN)的过滤索引之间的差异:
创建UNIQUE之间没有显着差异 约束并创建独立于约束的唯一索引。 数据验证以相同的方式进行,查询优化器也是如此 不区分由约束创建的唯一索引或 手动创建。但是,您应该创建一个UNIQUE或PRIMARY KEY 当数据完整性是目标时,对列的约束。通过 这样做,指数的目标将是明确的。
我不确定的唯一方面是使用getdate()。我不确定这会对索引和性能产生什么影响 - 你需要自己测试一下。
答案 1 :(得分:1)
我认为你需要一个触发器
唯一约束/索引不足以处理给定消息和ip的帖子之间的10分钟差距。
CREATE TRIGGER TRG_tblMessages_I FRO INSERT
AS
SET NOCOUNT ON;
IF EXISTS (SELECT *
FROM tblMessages M
JOIN INSERTED I ON M.message = I.message and M.ip = I.ip
WHERE
datediff(minute, M.timestamp, I.timestamp) < 10)
BEGIN
RAISERRROR ('blah', 16, 1)
ROLLBACK TRAN
END
编辑:你需要一个额外的条件来忽略你刚刚插入的同一行(例如使用代理键)
答案 2 :(得分:0)
向表中添加唯一约束以绝对防止它发生
ALTER TABLE tblMessages ADD CONSTRAINT uq_tblMessages UNIQUE (message,ip,timestamp)
答案 3 :(得分:0)
我认为,最简单的方法是使用触发器检查表中现有记录中的发件人和邮件正文。
或者,正如Derek所说,你可以使用约束,但还有另一个条件:
ALTER TABLE tblMessages ADD CONSTRAINT uq_tblMessages UNIQUE (message,ip,username, parentId)
但约束会产生异常(你需要处理它)。