草庐IT

php - 如何处理对 mySQL 数据库中一条记录的大量同时更新请求并确定谁先到达

coder 2023-10-25 原文

我使用 php 和 mySQL 设计了一个显示图书出租的网站。当有人点击这本书时,会显示一个带有倒计时计时器的信息页面,用户有 10 秒的时间来决定是否要借这本书。如果时间到了,用户需要返回并再次点击该书以显示“借阅页面”。当用户单击该书时,PHP 实际上首先检查该书当前是否正在被其他人“查看”。如果没有人在看它,PHP 显示“借阅页面”并且用户获得 10 秒的书籍独占权。在这 10 秒内,其他用户将无法打开页面或查看“借用按钮”。一切都已启动并运行,只是我不知道如何正确执行,所以只有一个用户可以首先获得 10 秒的独占权。我的逻辑是这样的:

MySQL 表:

图书(图书 ID、书名、当前用户、过期时间)

一个。当用户点击书籍时:PHP Check if expire_time <>

如果为真(之前的查看时间已过期),则将 current_user 字段设置为请求者的用户 ID,并将过期时间设置为现在 + 10 秒:

UPDATE Book SET current_user='$userID', expire_time=ADDTIME(NOW(), '00:00:10')

如果为 false(仍在查看时间内),则进一步检查 current_user 字段是否等于请求者的用户 ID。

如果为真,则显示“借用页面”。

如果为 false,则显示错误消息“其他人正在查看这本书。请在 10 秒后回来”

我测试过使用 2 台电脑同时点击这本书。大多数时候,只有一台计算机可以访问该页面并获得 10 秒的独占权。不过有一次,两台电脑同时成功打开了“借书”页面。这绝对不是我想要的。想象一下,如果有 100 个 Web 请求要求打开同一本书,其中一半通过了,而只有 1 本书可供出租。

借书之物仅供引用。我想知道的是,当有大量查询同时到达mysql服务器时,如何获取或选择第一个并搁置其余的?

最佳答案

我会将锁封装到一个类中,然后你可以这样做:

$book = new Book($book_id);
$success = $book->getLock($user_id);
if (!$success)
  echo 'Lock failed';
else
  echo 'You got 10 seconds to buy, sucka!';


    class book {
        private $id = false;
        private $initialized = false; 
        public function __construct($id = false) {
            if (!is_numeric($id) || $id === false)
                return false;
                    $this->id = $id;
            $this->initialized = true;
            return;
        }
        public function getLock($userID = false) {
            if ($this->initialized !== true)
                return false;

            if (!is_numeric($userID) || $userID === false)
                return false;

           // check for a current lock
           $sql = 'SELECT current_user, expire_time FROM Book WHERE id = '.$this->id;

           // do whatever you do, get back the row
           $avail = do_query($sql);

          // the book is already locked
          if ($avail['current_user'] > 0 && strtotime($avail['expire_time']) > time())
        return false;

            // assert the lock
            $sql = 'UPDATE Book SET current_user='.$userID.', expire_time=ADDTIME(NOW(), "00:00:10") WHERE id = '.$this->id;

            // use whatever method you use for db access
            do_query($sql);

            // verify the lock
            $sql = 'SELECT current_user FROM Book WHERE id = '.$this->id;

            // do whatever you do for db access, get the id field
            $result = do_query($sql);

            // if these match, lock was a success
            if ($result == $userID)
                return true;

            return false;
        }
        public function releaseLock($userID=false) {
            if ($this->initialized !== true)
                return false;

            if (!is_numeric($userID) || $userID === false)
                return false;

            // verify the lock is in the specified user's id
            $sql = 'SELECT current_user FROM Book WHERE id = '.$this->id;

            // do whatever you do for db access, get the id field
            $result = do_query($sql);

            // if these match, lock is actively assigned to this user
            if ($result == $userID)
                return false;

            // release it
            $sql = 'UPDATE Book SET current_user=NULL, expire_time=NULL WHERE id = '.$this->id;
            do_query($sql);
            return true;
        }

    }

关于php - 如何处理对 mySQL 数据库中一条记录的大量同时更新请求并确定谁先到达,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6862358/

有关php - 如何处理对 mySQL 数据库中一条记录的大量同时更新请求并确定谁先到达的更多相关文章

  1. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  2. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  3. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

  4. ruby-on-rails - 如何处理 Grape 中特定操作的过滤器之前? - 2

    我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?

  5. Ruby - 如何处理子类意外覆盖父类(super class)私有(private)字段的问题? - 2

    假设您编写了一个类Sup,我决定将其扩展为SubSup。我不仅需要了解你发布的接口(interface),还需要了解你的私有(private)字段。见证这次失败:classSupdefinitialize@privateField="fromsup"enddefgetXreturn@privateFieldendendclassSub问题是,解决这个问题的正确方法是什么?看起来子类应该能够使用它想要的任何字段而不会弄乱父类(superclass)。编辑:equivalentexampleinJava返回"fromSup",这也是它应该产生的答案。 最佳答案

  6. ruby - Rails -- :id attribute? 所需的数据库索引 - 2

    因此,当我遵循MichaelHartl的RubyonRails教程时,我注意到在用户表中,我们为:email属性添加了一个唯一索引,以提高find的效率方法,因此它不会逐行搜索。到目前为止,我们一直在根据情况使用find_by_email和find_by_id进行搜索。然而,我们从未为:id属性设置索引。:id是否自动索引,因为它在默认情况下是唯一的并且本质上是顺序的?或者情况并非如此,我应该为:id搜索添加索引吗? 最佳答案 大多数数据库(包括sqlite,这是RoR中的默认数据库)会自动索引主键,对于RailsMigration

  7. ruby-on-rails - 如何让 datamapper 与 postgresql 数据库一起工作? - 2

    我已经找到了几个使用datamapper的示例,并且能够让它们正常工作。不过,所有这些示例都是针对sqlite数据库的。我正在尝试将数据映射器与postgresql一起使用。我将datamapper中的调用从sqlite3更改为postgres,并且我已经安装了dm-postgres-adapter。但它仍然不起作用。我还需要做什么? 最佳答案 与SQLite不同,PostgreSQL不将数据库存储在单个文件中。在你拥有createdyourdatabase之后,尝试这样的事情:DataMapper.setup:default,{:

  8. ruby-on-rails - 无法安装 mysql2 0.3.14 gem - 2

    我看到其他人也遇到过类似的问题,但没有一个解决方案对我有用。0.3.14gem与其他gem文件一起存在。我已经完全按照此处指示完成了所有操作:https://github.com/brianmario/mysql2.我仍然得到以下信息。我不知道为什么安装程序指示它找不到include目录,因为我已经检查过它存在。thread.h文件存在,但不在ruby​​目录中。相反,它在这里:C:\RailsInstaller\DevKit\lib\perl5\5.8\msys\CORE\我正在运行Windows7并尝试在Aptana3中构建我的Rails项目。我的Ruby是1.9.3。$gemin

  9. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

  10. ruby-on-rails - 在现有数据库上进行 Rails 迁移 - 2

    我正在创建一个新的Rails3.1应用程序。我希望这个新应用程序重用现有数据库(由以前的Rails2应用程序创建)。我创建了新的应用程序定义模型,它重用了数据库中的一些现有数据。在开发和测试阶段,一切正常,因为它在干净的表数据库上运行,但是当尝试部署到生产环境时,我收到如下消息:PGError:ERROR:column"email"ofrelation"users"alreadyexists***[err::localhost]:ALTERTABLE"users"ADDCOLUMN"email"charactervarying(255)DEFAULT''NOTNULL但是我在迁移中有这

随机推荐