Mysql 从具有并发连接的表中获取
我们有一个游戏,用户可以登录并玩游戏,该游戏只针对6名用户,当6名用户加入一个组时,游戏开始 我们在mysql中有一个名为“temp_group”的表,其中包含用户id和一个随机数字 现在,我们要实现的是,当用户进入游戏时,我们需要插入他的用户id,并检查组中有多少用户具有相同的随机编号,场景如下:Mysql 从具有并发连接的表中获取,mysql,node.js,stored-procedures,Mysql,Node.js,Stored Procedures,我们有一个游戏,用户可以登录并玩游戏,该游戏只针对6名用户,当6名用户加入一个组时,游戏开始 我们在mysql中有一个名为“temp_group”的表,其中包含用户id和一个随机数字 现在,我们要实现的是,当用户进入游戏时,我们需要插入他的用户id,并检查组中有多少用户具有相同的随机编号,场景如下: 如果组中没有用户(第一个进入游戏的用户),我们将生成一个随机_数,并针对新用户插入它 一个组中有用户(第2到第6个用户加入游戏)-获取该组的随机_编号,并针对该用户进行更新 如果第7个用户加入游戏-
选择计数(随机数),从临时组组中按随机数选择计数(随机数)<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名以上的玩家加入,这可能会成为一个问题,但即使是罕见的问题也是问题
虽然您可能会找到更好的随机化器,但我强烈建议您添加一个新表,其中包含有关组的信息,其形式最简单,例如justteam(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