我在负载测试场景下遇到了奇怪的行为:后端(sql server 2012)正在超载并且一些命令超时(这仍然是预期的,因为后端服务器是半故意慢的HW);但我们的平台经常(延迟时间越来越长)重试超时操作 - 经过几次重试后突然开始接收'无法插入重复的密钥' SQLEXCEPTION。
我确认只能生成一个具有特定唯一键的行并尝试插入(第一次插入并且所有可能的重试始终在同一个线程上进行)。
我还修改了SP,以便它使用显式事务:
BEGIN TRY
BEGIN TRANSACTION;
-- Insert into table A
-- Insert into table B
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW
END CATCH
然而问题仍然存在。
有什么想法可以解决这个问题吗?
如何找出超时的来源(后端与客户端)?
有没有办法确保操作成功完成或失败(基本上是事务 - 但可能来自客户端代码)?
EDIT01: 我认为解决这个问题的一种方法是利用ado.net集成SQL服务器分布式事务 - 例如:
using (TransactionScope scope = new TransactionScope())
{
//Perform the sql commands
//if above statements throws (e.g. due to timeout) - than the transaction is not commited and it will be rolled back
scope.Complete()
}
但是:我同意它只会增加复杂性并且仍然可能仍然反对同一个问题(usr概述的两个将军问题)。 因此,最好的方法是编写客户端和服务器端的代码可以依靠这样的选项 - 再次由usr在他的回答中指出
答案 0 :(得分:7)
这是预期的行为。当客户端和服务器之间的通信中断时,客户端不知道操作的结果。它可能永远不会被发送,或者它已被发送但未被接收,或者已收到但未通过,或者已收到但成功响应未通过。
这是Two Generals Problem。它是无法解决的(严格定义时)。
你必须解决它。在插入之前检查是否存在或处理重复的键异常。
或者,只是增加超时。对于最终成功的其他工作命令,中止它对你没有任何好处。中止并重新启动它并不会使它变得更快(除非巧合)。超时主要用于网络错误或失控查询(错误)。
答案 1 :(得分:-1)
根据文档SqlException Class。
SQL Server返回警告或抛出时引发的异常 错误。这个类不能被继承。
我的经验是,如果你有一个SQL异常,那么它来自SQL。
超时是SQL设置。您可以将其设置为SSMS。
好的我现在相信+1来自客户端 SqlCommand.CommandTimeout
获取或设置终止执行a的尝试之前的等待时间 命令并生成错误。
这不是我希望它实现的方式。 你可能会有一个疯狂的查询并失去连接,SQL会继续运行。