使用单个客户端和单个会话模拟 SQL Server 上的死锁

Posted

技术标签:

【中文标题】使用单个客户端和单个会话模拟 SQL Server 上的死锁【英文标题】:Simulate a dead lock on SQL server using single client and single session 【发布时间】:2021-12-29 07:55:31 【问题描述】:

我正在尝试在 sql server 上模拟故意的死锁,我可以在其中测试一段可以重试的代码。需要一个我可以执行的查询/SP/Func,稍后此查询会因 1205/死锁而失败并触发我的重试逻辑。

约束: -在单个客户端 n 单个会话中。 (可能是在单个会话中读取元数据并锁定自身)

尝试成功: -模拟自定义 SQL 异常 n 成功恢复。 - 多线程方法。

现在,需要一个在单个会话中执行此操作的 SQL 组件。

编辑:重新构建问题以获得更好的建议。

【问题讨论】:

当会话试图让另一个会话锁定对象时,数据库中会发生死锁。因此,session1 锁定 table1 并等待 session2 解锁 table1。同时,session2 正在等待 session1 解锁 table1。这是发生死锁的时候。如果不建立至少 2 个会话,您将无法模拟它 不找这个,因为它不能在我的套装中自动测试。 为什么不呢?线程和任务已经存在一段时间了。 重新思考一下...如果您需要两个客户端/连接来测试这个,听起来您依赖于具体的类,例如SqlConnectionSqlCommand 等。如果您正在使用IDbConnectionIDbCommand 正确地你应该能够从模拟中抛出 SqlException.Number = 1205 @AlwaysLearning 试过了!给出各种错误:MARS,当我让其他线程休眠时不允许并行连接/传输等。所以“我的”测试套件,假设我正在维护它,只能提供这么多的灵活性。即将抛出新的自定义 Sql 异常,编号为 1205:我需要与 DB 的实际集成。我的 reties 的模拟和单元测试已经弄清楚了。感谢您的准确,感谢! 如果您要测试的只是命令失败时的弹性,您可以通过THROW/RAISERROR 模拟服务器端故障。为此复制死锁是毫无意义的(无论是一个会话还是多个会话),因为如果您可以在实际设置中完全做到这一点,那么您通常想要做的是修复死锁(所以这是一个回归测试,而不是集成测试),而如果您使用纯理论设置来使其可复制,那么仅测试始终产生的错误并不比这更好。 【参考方案1】:

这是目前可能的。

以下代码会自行死锁

BEGIN TRAN
CREATE TYPE dbo.OptionIDs AS TABLE( OptionID INT PRIMARY KEY )
EXEC ('DECLARE @OptionIDs dbo.OptionIDs;')
ROLLBACK 

这是一个长期存在的问题,因为在创建 TVP 实例时使用了内部系统事务,无法访问用户事务获取的锁。

在某些时候它可能会被修复

【讨论】:

我在 bw 中用 Go 尝试过同样的方法,但失败了(因为 Go 是非 T-SQL,是 SSMS 原生的)后来也尝试不使用它,但没有运气。 EXEC ('DECLARE OptionIDs dbo.OptionIDs;') 这行成功了!谢谢@Martin 在此处使用此脚本进行测试:***.com/questions/70062183/… 谢谢!

以上是关于使用单个客户端和单个会话模拟 SQL Server 上的死锁的主要内容,如果未能解决你的问题,请参考以下文章

允许每个用户的单个会话 IdentityServer4

使用 SQL Server 模拟从 Web API 方法返回 IQueryable

使用 Chilkat 和 SQL Server 将单个电子邮件附件保存到 BLOB

使用 Spring Boot 在单个浏览器会话中使用多个 OAuth2 客户端

Linux X11 单个会话中的多个客户端

SQL Server 转换 xml 并解析单个值,但不使用内置函数