我在负载测试场景下遇到了奇怪的行为:后端(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在他的回答中指出
这是预期的行为.当客户端和服务器之间的通信中断时,客户端不知道操作的结果.它可能永远不会被发送,或者它已被发送但未被接收,或者它已收到但失败了,或者它已收到但是成功响应没有通过.
这是两个将军的问题.它是无法解决的(严格定义时).
你必须解决它.在插入之前检查是否存在或处理重复键异常.
或者,只需增加超时.对于最终成功的其他工作命令,中止它对你没有任何好处.中止并重新启动它并不会使它变得更快(除非巧合).超时主要用于网络错误或失控查询(错误).