sql server死锁有insert,select,delete

时间:2015-08-17 18:14:28

标签: c# sql-server transactions

申请详情

C#web api(隐式并发)

dapper for sql execution

要求

将四个用户添加到"休息室"这意味着游戏已准备好开始。第四个添加的用户负责启动游戏。一旦游戏开始,用户必须从"休息室"中删除。

UserInLounge(LoungeId,UserId) 请注意,还有一个休息室,

代码

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"

1 个答案:

答案 0 :(得分:0)

我从这里得到了解决方案 - 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();