c# - 插入,选择,删除的SQL Server死锁

标签 c# sql-server transactions

申请详情

C# web api(隐式并发)

用于执行 sql 的 dapper

要求

当四个用户被添加到“休息室”时,这意味着游戏已准备好开始。第四个添加的用户负责启动游戏。游戏开始后,必须将用户从“休息室”中移除。

表格

UserInLounge (LoungeId, UserId) 注意,比lounge还多一个,

代码

var tran = connection.BeginTransaction();
connection.Execute("insert into UserInLounge(LoungeId, UserId, TimeEntered) values (@loungeId, @userId, @timeEntered)", new { loungeId, userId = user.Id, timeEntered = DateTime.UtcNow }, tran);
var userIds = connection.Query<string>("select UserId from UserInLounge where LoungeId = @loungeId", new { loungeId }, tran).ToList();
if (userIds.Count == 4)
{
    connection.Execute("delete from UserInLounge where LoungeId = @loungeId and UserId IN @userIds", new { loungeId, userIds }, tran);
}
tran.Commit();

问题

多用户运行(我用4个测试)会造成事务死锁。我使用一个事务,因为我需要在插入后准确知道现在是否有四个人,如果是,则将他们删除。

第二次尝试

var tran = connection.BeginTransaction();
var userIds = connection.Query<string>("select UserId from UserInLounge where LoungeId = @loungeId", new { loungeId }, tran).ToList();
if (userIds.Count == 3)
{
    connection.Execute("delete from UserInLounge where LoungeId = @loungeId and UserId IN @userIds", new { loungeId, userIds }, tran);
    tran.Commit();
}
else
{
    connection.Execute("insert into UserInLounge(LoungeId, UserId, TimeEntered) values (@loungeId, @userId, @timeEntered)", new { loungeId, userId = user.Id, timeEntered = DateTime.UtcNow }, tran);
tran.Commit();
 Log.InfoFormat("{0} added to Lounge: {1}; Now {2} users", user.UserName, ret.Name, userIds.Count);

}

第二次尝试时,if 语句永远不会为真。这是日志输出-

|INFO |FiveHundred.Web.Stores.DapperLoungeStore - user3@fivehundred.com added to Lounge: Main; Now 0 users
|INFO |FiveHundred.Web.Stores.DapperLoungeStore - user2@fivehundred.com added to Lounge: Main; Now 0 users
|INFO |FiveHundred.Web.Stores.DapperLoungeStore - user1@fivehundred.com added to Lounge: Main; Now 0 users
|INFO |FiveHundred.Web.Stores.DapperLoungeStore - user4@fivehundred.com added to Lounge: Main; Now 0 users

如果我按照建议添加 HOLDLOCK,我会遇到死锁

"select UserId from UserInLounge with (holdlock) where LoungeId = @loungeId"

最佳答案

我从这里得到了解决方案 - http://michaeljswart.com/2011/09/mythbusting-concurrent-updateinsert-solutions/

与上面基本相同,但加上 -

var tran = connection.BeginTransaction(IsolationLevel.Serializable);
var userIds = connection.Query<string>("select UserId from UserInLounge with (updlock) where LoungeId = @loungeId", new { loungeId }, tran).ToList();

关于c# - 插入,选择,删除的SQL Server死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32057031/

相关文章:

c# - MVVM wpf在 View 模型之间传递参数

c# - 组合两个类的成员选择器表达式

c# - 我如何确认 NHibernate 确实使用了使用 SQL Profiler 的事务?

mysql - 使用可重复读取隔离时 SELECT .. FOR UPDATE 有什么用?

ios - 处理 Realm 事务

c# - Azure 认知服务无法在生产模式下工作

c# - LINQ over XAML 提供程序

sql - 是否可以在变量中设置选择语句的一部分

sql-server - 使用node js将多列和行插入SQL Server

sql-server - 如何指定在连接字符串中使用 SQL Server LocalDb 2014 而不是 SQL Server LocalDb 2016?