【发布时间】:2021-08-20 06:50:15
【问题描述】:
我有多个服务器运行同一个应用程序(分布式容器)。该应用程序修改了一个 SQL Server 表,所以它的作用是检查一个表的标志(例如status = open),阻止其中一些(有一个 top(10) 用于性能问题)并处理那些打开的行。完成后,它会相应地设置标志(高度简化)
我现在遇到的问题是,一些服务器随机崩溃
事务在锁定资源上与另一个进程发生死锁,并已被选为死锁牺牲品
我认为这是 SQL Server 错误。所以我的问题: 开始时
using (var connection = new SqlConnection(connectionString))
和小巧玲珑,就像
connection.Query("my Query");
在使用结束之前,是否所有查询都像在一个 SQL 事务中一样处理?这里BeginTransaction 解决了问题还是将所有内容都视为嵌套事务?
真的很难测试,我的猜测是,这个问题每执行 10 次左右就会出现一次。整个过程需要处理对另一台服务器的 HTTP 请求,这些请求可能持续时间更长或更短,因此整个过程可能需要数百毫秒或几秒钟(我对此没有影响)。
更新
所以应用程序(无助于显示真实代码)会执行类似的操作
connection.Query(query1);
doOtherStuff
connection.Query(query2);
doOtherStuff
connection.Query(query3);
doOtherStuff
其他东西是异步的(有时),但是,每个查询都可以独立执行,不需要处于关闭的事务中。
【问题讨论】:
-
不幸的是,死锁并不是那么简单......您需要捕获并检查死锁图以查看其发生的位置和原因。长话短说,您永远无法完全防止死锁,因此您应该在发生死锁时进行某种形式的重试(并尽量避免死锁)。
-
正如我所说,唯一 了解发生了什么的方法是查看死锁图...省去你自己的猜测 :)
-
@rst 所有操作都使用锁,只要连接打开,或者如果使用事务,只要事务处于活动状态。这与 SqlConnection 或 Dapper 无关,这就是数据库的工作方式。这就是为什么您需要尽快使用紧密连接的原因。 Dapper 或 SqlCommand 实际上都没有启动事务。 Dapper 不会关闭已经打开的连接。如果您的代码保持连接打开的时间过长,则会导致阻塞或死锁
-
检查Using tables as Queues,尤其是
Implementing a queue backed by a table is notoriously difficult, error prone and susceptible to deadlocks.这句话我了解到,最简单的解决方案是那篇文章中显示的破坏性阅读。DELETE .. OUTPUT将返回已删除的数据,本质上充当真实队列中的Dequeue -
@rst 你还没有验证这是你想要的,或者你对“队列”使用了什么 SQL 技术。我从过去的痛苦经历中“猜测”。
标签: sql-server .net-core dapper sqlconnection