Mysql 从具有并发连接的表中获取

Mysql 从具有并发连接的表中获取,mysql,node.js,stored-procedures,Mysql,Node.js,Stored Procedures,我们有一个游戏,用户可以登录并玩游戏,该游戏只针对6名用户,当6名用户加入一个组时,游戏开始 我们在mysql中有一个名为“temp_group”的表,其中包含用户id和一个随机数字 现在,我们要实现的是,当用户进入游戏时,我们需要插入他的用户id,并检查组中有多少用户具有相同的随机编号,场景如下: 如果组中没有用户(第一个进入游戏的用户),我们将生成一个随机_数,并针对新用户插入它 一个组中有用户(第2到第6个用户加入游戏)-获取该组的随机_编号,并针对该用户进行更新 如果第7个用户加入游戏-

我们有一个游戏,用户可以登录并玩游戏,该游戏只针对6名用户,当6名用户加入一个组时,游戏开始

我们在mysql中有一个名为“temp_group”的表,其中包含用户id和一个随机数字 现在,我们要实现的是,当用户进入游戏时,我们需要插入他的用户id,并检查组中有多少用户具有相同的随机编号,场景如下:

  • 如果组中没有用户(第一个进入游戏的用户),我们将生成一个随机_数,并针对新用户插入它
  • 一个组中有用户(第2到第6个用户加入游戏)-获取该组的随机_编号,并针对该用户进行更新
  • 如果第7个用户加入游戏-将其视为一个组的新用户,并按照第1点中的操作
  • 我们已经创建了一个存储过程,首先在其中检查

    选择计数(随机数),从临时组组中按随机数选择计数(随机数)<6顺序按id ASC限制1

    如果我们得到该行,我们将获取随机_编号,并为新用户(第2–第6个用户)更新该编号

    如果我们没有得到该行,我们将生成随机_数并针对新用户进行更新

    我们的存储过程:

    BEGIN
    DECLARE ch_done INT DEFAULT 0;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET ch_done = 1;
    
                START TRANSACTION;
    
                SELECT count(random_number), random_number  from `temp_group` where group by random_number HAVING COUNT(random_number) < players order by temp_id ASC limit 1 into cnt, randomnumber;
    
                IF(ch_done = 1) THEN 
                    IF(randomnumber IS NULL) OR (cnt = 0) THEN    
                        SET randomnumber = MD5(NOW());
                        SET cnt = 0;
                    END IF;
                END IF;
    
                INSERT INTO temp_group (`user_id`,`random_number`,`no_of_players`) VALUES(userid,,randomnumber,6) ON DUPLICATE KEY UPDATE `random_number` = randomnumber, `no_of_players` = 6;
                COMMIT;
    END
    
    开始
    声明Chu done INT默认值为0;
    为未找到集Chu done=1声明继续处理程序;
    启动交易;
    选择count(random_number),random_number从'temp_group'中选择,其中group by random_number具有count(random_number)<玩家按temp_id ASC limit 1排序进入cnt,random number;
    如果(Chu done=1),则
    如果(随机数为空)或(cnt=0),则
    设置randomnumber=MD5(现在为());
    设置cnt=0;
    如果结束;
    如果结束;
    在重复键更新时,将值(userid,random number,6)插入临时组(`user\u id`,`random\u number`,`no\u of \u players`=6);
    犯罪
    结束
    
    问题:

    当我们测试单个用户一次加入游戏时,它工作正常。 但是当我们用并发连接测试它时,相同的随机数被分配给6个以上的用户

    问题是,当并发连接调用存储过程时,所有存储过程都会获取select查询并获取random_编号,因此它只会为所有用户更新相同的random_编号。
    是否有人可以帮助我停止存储过程读取数据,直到上一个存储过程更新表并提交

    您的过程中存在一些问题:

    首先,也可能是您的主要问题,您的
    select
    是非锁定的,例如,如果两个并发会话同时读取表,它们可以得到相同的结果,并根据相同的当前状态做出决策。例如,他们可能会将自己的球员加入同一个团队,因为他们都假设目前只有5名未分配的球员,从而形成一个7人的团队。修复将是锁定读取,您可以通过添加以下内容获得:

    然后,第二个查询将不得不等待,直到您提交第一个会话(空表除外,这可能是一个问题,也可能不是问题),因此,正如您所希望的,它“停止存储过程读取数据,直到前一个存储过程更新表并提交”

    第二个问题是
    MD5(NOW())
    不是唯一的。如果您有两个并发会话,这意味着它们同时运行-因此
    MD5(NOW())
    将返回相同的值,即使您的过程实际上打算创建一个新组。如果在同一秒钟内有6名以上的玩家加入,这可能会成为一个问题,但即使是罕见的问题也是问题

    虽然您可能会找到更好的随机化器,但我强烈建议您添加一个新表,其中包含有关组的信息,其形式最简单,例如just
    team(id int primary key auto_increment)
    。您当前的表
    temp\u group
    可能会变成类似于
    team\u user(team\u id,user\u id)

    您可以通过向团队表中添加一行来创建一个新团队,而不是生成一个随机数来创建一个新团队(同时为其分配一名球员),然后通过将球员插入
    team\u user
    表来将其分配给该团队。通过这种方式,您可以将两个逻辑步骤(创建新团队、向团队添加用户)正确地划分为两个实际步骤

    一个合适的数据模型可以简化许多数据库任务,例如,teamid的唯一性基本上是在不做任何工作的情况下自然出现的(即使每个团队需要一个唯一的md5值,也可以通过向团队表添加一个唯一的键来实现)。另外,假设您想要添加关于团队的任何附加信息(例如,团队名称、游戏模式、创建私人/密码保护大厅的选项,或者,正如您目前似乎正在存储的,最多6名玩家)-您必须将其存储在
    临时组
    表中数次,这始终是一个坏主意

    最后一期:

    SELECT ... group by random_number ... order by temp_id
    

    一般来说,这是因为
    temp\u id
    没有确定的值(例如
    temp\u id
    每个
    随机数最多6个值中的哪一个?MySQL仅在禁用(不应该禁用)的情况下才允许这样做。例如,修复可以是使用
    按分钟排序(临时id)
    (取决于您想要实现的目标)。另一方面,如果添加
    team
    -表,则可以(正确地)使用
    group by team\u id have。。。。按团队id排序

    此存储过程的参数是什么?
    分隔符$$CREATE sp_GetRandom(在lid INT中,在players INT中,OUT randomnumber VARCHAR(40),OUT cnt INT)无SQL BEGING声明CHU done INT默认值0;为非FO声明继续处理程序
    
    SELECT ... group by random_number ... order by temp_id