代码之家  ›  专栏  ›  技术社区  ›  JustAMartin

阻止web应用程序中的同时事务

  •  4
  • JustAMartin  · 技术社区  · 14 年前

    我们有一个web应用程序(它是一个游戏),有许多不同的形式和元素,它们充当按钮并触发服务器上的一些操作。问题是,用户有时会混淆我们的应用程序,如果他点击按钮太快,或打开两个标签,然后同时发出一些行动的网站。我们有一些基本的保护——MySQL事务,一些防止双击的Javascripts,但是不管怎么说,有时候有些东西会被跳过。当然,最好的方法是重新设计所有SQL事务和支持函数,以避免混淆系统。这种混乱的一个例子是同时发出两个更新—一个web请求更改了数据库中的某些内容,但第二个请求仍然使用旧数据运行,因此SQL update返回“受影响的行数为零”,因为第一个事务已经更改了数据库中的数据。 显而易见的解决方案是在更新之前再次读取数据,看看它是否仍然需要更新,但这意味着在任何地方都放置更多的双选查询,这不是一个好的解决方案-为什么要从db读取相同的数据两次? 此外,我们还考虑使用一些隐藏的令牌在服务器上对每个更新请求进行比较,并拒绝具有相同令牌id的操作,但这也意味着涉及到代码的许多地方,并可能在系统中引入新的bug,除了这一个问题外,这些bug运行正常。

    操作流的逻辑如下:如果用户同时发出两个请求,则第二个请求应该等到第一个请求完成。但是我们还必须考虑到我们的应用程序中有很多重定向(例如在POSTs之后,以避免用户刷新页面时重复发布),因此解决方案不应该为用户创建死锁。

    所以问题是: 哪种最简单的全局修复方法可以让所有的用户操作有序进行?有什么好的通用解决方案吗?

    3 回复  |  直到 14 年前
        1
  •  2
  •   The Surrican    14 年前

    我很高兴你意识到这只是一个不好的临时解决方案,你应该优化你的代码。 忘了你的代币什么的。

    <?php
        $fp = fopen("/tmp/only-one-bed-available.txt", "w+");
    
        if (flock($fp, LOCK_EX)) { // do an exclusive lock
    
             // do some very important critical stuff here which must not be interrupted:
             // sleeping.
             sleep(60);
             echo "I now slept 60 seconds";
            flock($fp, LOCK_UN); // release the lock
        } else {
            echo "Couldn't get the lock!";
        }
    
        fclose($fp);
    ?>
    

    这将全局序列化此代码的所有执行。

    <?php $fp = fopen("/tmp/lock-".$_SERVER["REMOTE_ADDR"].".txt", "w+"); ?>

    还可以为一组操作定义锁文件名。也许用户可以并行地做一些事情,但只有这个操作会产生问题?给它一个标签,并将其包含在锁文件名中!

    有了上面发布的解决方案,您可以在应用程序中实现这一点,这可能是很好的。 您也可以在Mysql中使用相同的方案: http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock

    但是PHP实现对于您的用例来说可能更简单、更好。

    如果你真的想找一个更优雅的解决方案, http://www.php.net/manual/en/function.sem-get.php

        2
  •  1
  •   Loïc Février    14 年前

    两个标签和同时行动?你的用户有多快?

    只需一个选项卡,就可以在javascript中堆叠操作,并在获得上一次调用的返回值后提交一个新的操作。

        3
  •  1
  •   Alfred    14 年前

    使用mysql的 get_lock 功能? transactions .

    推荐文章