插入行并避免竞争条件(PHP/MySQL)

jus*_*vin 3 mysql

我正在开发一个多人游戏,它有一个大厅式的区域,玩家可以选择"扇区"进入.大厅网关由PHP提供支持,而实际的游戏玩法由一个或多个Java服务器处理.数据存储区是MySQL.

快乐的道路:玩家选择一个扇区并告诉大厅他想要进入.大厅检查这是否合适,包括检查扇区中是否有太多玩家(将该扇区的扇区分配中的条目数与扇区的max_players值进行比较).播放器被添加到sector_assignments表中,将其与扇区配对.玩家客户端收到一个密钥,让他连接到相应的游戏服务器.

竞争条件:如果两个玩家在接近同一时间请求访问同一个扇区,我可以设想一个情况,它们都被添加,因为当他们的支票开始并且超过最大玩家时有一个空闲空间.

sector_assignments上的最佳解决方案LOCK TABLE?还有其他选择吗?

ewe*_*nli 6

通常,这种并发问题的解决方案涉及事务和乐观锁定:当您更新计数器时,添加一个where子句来检查旧值并计算更新的行数.

v = select value from counter where id=x.
update counter set value = v+1 where value = v and id=x
Run Code Online (Sandbox Code Playgroud)

如果计数器在此期间更新,则更新不会更改任何行 - 因此您知道必须回滚并再次尝试事务.

一个问题是它可能导致高争用,只有少数事务成功并且很多失败.

然后,最好坚持悲观锁定,首先锁定行,然后更新它.但只有一个基准测试会告诉你.

编辑

如果使用没有乐观锁定的事务,则可能发生以下情况.

Max authorized = 50. Current value = 49.

T1: start tx, read value --> 49
T2: start tx, read value --> 49
T1: update value --> 50, acquire a row lock
T1: commits --> release the lock
T2: update value --> 50, acquire a row lock
T2: commits --> release the lock
Run Code Online (Sandbox Code Playgroud)

两个事务都成功,值为50,但存在不一致.