c# - 执行非查询时出现SqlException 'timeout expired',但插入了数据

标签 c# .net sql-server ado.net sql-server-2012

我在负载测试场景下遇到了奇怪的行为:后端(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/

相关文章:

c# - 我如何声明派生的 "shell"类,它们除了重命名外什么都不做?

c# - .Net 项目构建问题

php - 为什么 CodeIgniter 会耗尽允许的内存大小?

C# boolean 需要转换为 SQL Server 的位,所以它需要是 1 而不是 True

c# - 网格松动 "Stretch"-Property

c# - 抓取 Gridview 文本框输入值 Jquery

c# - 业务层/代码隐藏性能问题

c# - 在组合框中选择最后添加的列表项

c# - 依赖注入(inject)和缓存类最佳实践

sql-server - 这种连接是否过于复杂?