2

考虑到一个论坛表和许多用户同时向其中插入消息,这个事务有多安全?

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION

 DECLARE @LastMessageId SMALLINT
 SELECT @LastMessageId = MAX(MessageId)
 FROM Discussions
 WHERE ForumId = @ForumId AND DiscussionId = @DiscussionId

 INSERT INTO Discussions
 (ForumId, DiscussionId, MessageId, ParentId, MessageSubject, MessageBody)
 VALUES
 (@ForumId, @DiscussionId, @LastMessageId + 1, @ParentId, @MessageSubject, @MessageBody)

IF @@ERROR = 0
BEGIN
 COMMIT TRANSACTION
 RETURN 0
END

ROLLBACK TRANSACTION
RETURN 1

在这里,我阅读了最后一个 MessageId 并增加了它。我不能使用标识字段,因为它需要为插入组中的每条消息增加(不是每条消息都插入表中。)

4

1 回答 1

2

您的事务确实应该是相当安全的 - 查看SERIALIZABLE 事务级别的 MSDN 文档

可序列化

指定以下内容:

  • 语句不能读取已被其他事务修改但尚未提交的数据。

  • 在当前事务完成之前,任何其他事务都不能修改当前事务已读取的数据。

  • 在当前事务完成之前,其他事务不能插入键值落在当前事务中的任何语句读取的键范围内的新行。

范围锁被放置在与事务中执行的每个语句的搜索条件相匹配的键值范围内。这会阻止其他事务更新或插入符合当前事务执行的任何语句的任何行。这意味着如果事务中的任何语句第二次执行,它们将读取相同的行集。范围锁一直保持到事务完成。这是隔离级别中最具限制性的,因为它锁定整个范围的键并保持锁定直到事务完成。由于并发性较低,因此仅在必要时使用此选项。此选项与在事务中的所有 SELECT 语句中的所有表上设置 HOLDLOCK 具有相同的效果。

这种事务隔离级别的主要问题是它在服务器上的负载非常重,并且会序列化(顾名思义)任何访问,因此您的服务器性能和可伸缩性将受到影响,例如,对于非常多的用户,您将等待事务完成的用户可能会出现很多超时。

因此,使用更轻量级的全局消息 idINT IDENTITY方法肯定会好得多!

于 2010-12-04T09:46:14.987 回答