我在负载测试场景下遇到了奇怪的行为:后端(sql server 2012)过载并且一些命令超时(这仍然是预期的,因为后端服务器有一半是故意慢的硬件);但我们的平台会定期(随着延迟增加)重试超时操作 - 在几次重试后,它突然开始收到“无法插入重复键”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 Server 分布式事务——例如:
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 在他的回答中指出的那样
最佳答案
这是预期的行为。当客户端和服务器之间的通信中断时,客户端不知道操作的结果。可能从来没有发送过,或者发送了但没有收到,或者收到了但失败了,或者收到了但没有成功响应。
这是 Two Generals Problem .它是无解的(当严格定义它时)。
你必须解决它。要么在插入之前检查是否存在,要么处理重复键异常。
或者,简单地增加超时。中止本来可以成功的其他工作命令对您没有任何好处。中止并重新启动它不会使其运行得更快(巧合除外)。超时主要用于网络错误或失控查询(错误)。
关于c# - 执行非查询时出现SqlException 'timeout expired',但插入了数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27002635/