首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在线时间系统中的死锁

在线时间系统中的死锁
EN

Stack Overflow用户
提问于 2014-07-26 04:34:46
回答 2查看 94关注 0票数 0

我正在为一个在线游戏开发一个在线小时系统。问题是,有时SQL会引发死锁错误:

40001 Transaction (Process ID 411) was deadlocked on lock | communication buffer resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

该游戏有5个房间,每个房间是一个应用程序与自己的SQL连接。播放机不能在多个房间登录。每个应用程序每10分钟在在线播放器上循环一次,将命令发送到SQL过程以更新其联机分钟.

EXEC StoredProcedure 'PlayerName', 7

遵循存储过程代码:

代码语言:javascript
复制
USE [DataBase]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[StoredProcedure]
    @PlayerName varchar(10),
    @Minutes int
AS

BEGIN
    DECLARE @PlayerLogin varchar(10),
        @OnlineMinutes int

    SELECT @PlayerLogin = PlayerLogin FROM [dbo].[PlayerTable] WHERE PlayerName = @PlayerName

    UPDATE [dbo].[PlayerTable] SET OnlineMinutes = OnlineMinutes + @Minutes WHERE PlayerName = @PlayerName
    UPDATE [dbo].[AccountTable] SET OnlineMinutes = OnlineMinutes + @Minutes WHERE PlayerLogin = @PlayerLogin

    SELECT @OnlineMinutes = OnlineMinutes FROM [dbo].[AccountTable] WHERE PlayerLogin = @PlayerLogin

    IF ( @OnlineMinutes >= 60 )
    BEGIN
        UPDATE [dbo].[AccountTable] SET OnlineHours = OnlineHours + ( @OnlineMinutes / 60 ), OnlineMinutes = ( @OnlineMinutes % 60 ) WHERE PlayerLogin = @PlayerLogin
    END
END

将在线分钟存储在两个表中的原因是,PlayerTable用于对页面进行排名,而在AccountTable中,它用作玩家在在线游戏商店中花费的虚拟现金。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-07-26 05:17:14

我建议作以下修改。

1)在调用应用程序中,跟踪@PLayerName并将其传递给这个过程。然后使用它查找@PlayerLogin。您还应该跟踪调用方中的@PlayerName,并将两个变量传递给这个过程,避免在proc中查找@PlayerLogin

2)替换

代码语言:javascript
复制
SELECT @OnlineMinutes = OnlineMinutes FROM [dbo].[AccountTable] WHERE PlayerLogin = @PlayerLogin

IF ( @OnlineMinutes >= 60 )
BEGIN
    UPDATE [dbo].[AccountTable] SET OnlineHours = OnlineHours + ( @OnlineMinutes / 60 ),   
        OnlineMinutes = ( @OnlineMinutes % 60 ) WHERE PlayerLogin = @PlayerLogin
END

使用

代码语言:javascript
复制
UPDATE [dbo].[AccountTable] SET 
    OnlineHours = OnlineHours + ( @OnlineMinutes / 60 ) 
 , OnlineMinutes = ( @OnlineMinutes % 60 )
WHERE PlayerLogin = @PlayerLogin AND OnlineMinutes >= 60

通过这些更改,您可以消除这两个表上的SELECT然后更新模式。这对于避免死锁是件好事。

最后,您应该遵循重新运行事务的建议。将所有三个update语句放入一个封装在事务中的循环中,在错误上,回滚并让它再次尝试事务,当然,在成功的情况下,只需提交并退出循环。您仍然需要进行前两个更改,因为避免死锁比死锁后重新尝试要好得多。

您需要在重试次数上设置一个相当小的上限(我建议不要超过5次)。

票数 0
EN

Stack Overflow用户

发布于 2014-07-26 04:37:30

我建议使用WITH(ROWLOCK)选项:

代码语言:javascript
复制
UPDATE [dbo].[PlayerTable] WITH (ROWLOCK)
SET OnlineMinutes = OnlineMinutes + @Minutes 
WHERE PlayerName = @PlayerName
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24967556

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档