【问题标题】:SQL Server Insert query for a forum论坛的 SQL Server 插入查询
【发布时间】:2010-12-04 08:04:04
【问题描述】:

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

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 并将其递增。我不能使用标识字段,因为它需要为插入组中的每条消息增加(不是每条消息都插入表中。)

【问题讨论】:

  • 为什么每次讨论都需要重启MessageId?只需使用全局 MessageId 而不是复合键即可。这将为您节省很多麻烦并简化操作,例如将消息从一个讨论转移到另一个讨论。
  • 是的。你是对的。一个作为 Identity 的全局 MessageId 更容易解决这个问题。我不记得我为什么要这样设计!还是谢谢。

标签: sql sql-server concurrency transaction-isolation


【解决方案1】:

您的交易确实应该非常安全 - 查看MSDN docs on the SERIALIZABLE transaction level

可序列化

指定以下内容:

  • 语句无法读取已修改的数据但尚未 由其他事务提交。

  • 没有其他事务可以修改已被 当前交易直到当前 交易完成。

  • 其他事务无法插入具有以下键值的新行 将落在读取的键范围内 通过当前的任何陈述 交易至当前 交易完成。

范围锁被放置在匹配的键值范围内 每个语句的搜索条件 在事务中执行。这块 其他交易更新或 插入任何符合条件的行 对于由执行的任何语句 当前交易。这表示 如果 a 中的任何语句 交易被执行第二次 时间,他们会读到同一套 行。范围锁一直保持到 交易完成。这是 最严格的隔离 水平,因为它锁定了整个范围 钥匙和持有锁,直到 交易完成。因为 并发较低,使用此选项 仅在必要时。这个选项有 与设置 HOLDLOCK 相同的效果 所有 SELECT 语句中的所有表 一笔交易。

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

因此,使用更轻量级的全局消息 ID 方法作为INT IDENTITY 肯定要好得多!

【讨论】:

  • 如前所述,复合键在维护期间会引入更大的问题。我改变了桌子设计,老实说,我不知道我为什么首先这样做!也许我昨​​晚太累了 :-) 感谢您提供详细的描述、信息和提示。我很感激。
  • 我不能投票。我没有声望。对不起。再次感谢。
  • @Hamed:不客气。你可以稍后投票,只要你有 15 个或更多的代表点 - 不应该花很长时间 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
  • 1970-01-01
  • 2010-10-11
  • 1970-01-01
  • 2011-01-20
  • 2013-10-17
相关资源
最近更新 更多