【问题标题】:MYSQL close connect can not halt the insert activityMYSQL 关闭连接不能停止插入活动
【发布时间】:2013-01-31 07:41:05
【问题描述】:
<?php
header('Content-Type: text/html; charset=utf8');
$dbhost = '192.168.1.23';
$dbuser = 'demouser01';
$dbpass = 'demo*PW';
$dbname = 'testdb1';
$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die('Error with MySQL connection');
mysql_select_db($dbname);
mysql_query("SET NAMES 'utf8'");
mysql_query("SET CHARACTER_SET_CLIENT='utf8'");
mysql_query("SET CHARACTER_SET_RESULTS='utf8'");
if(isset($_POST['start'])) {
  $chi = 'chiiiii';
  $id = 1;
  for ($i = 1; $i <= 99999999999; $i++) {
    $eng = substr(str_shuffle(str_repeat("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 5)), 0, 1024);
    $math = substr(str_shuffle(str_repeat("1234567890", 6)), 0, 16);
    $sql = "INSERT INTO test_tb (id,chi,eng,num) VALUES (".$id.",'".$chi."','".$eng."',".$math.")";
    $result = mysql_query($sql) or die('MySQL query error');
    $id++;
  }
  $id = 0;
  sleep(60);
  mysql_close($conn);
} else if(isset($_POST['stop'])) {
  mysql_close($conn);
}
?>
<form action="<?=$_SERVER['PHP_SELF'];?>" method="post">
  <input type="submit" name="start" value="Start Insert">
  <input type="submit" name="stop" value="Stop Insert">
</form>

网站有两个按钮,插入重复插入记录,停止插入。但是,我尝试使用 MySQL 关闭连接,它会在 PHP 中停止运行,但活动仍然存在。插件仍在继续执行。如何解决问题?谢谢。

【问题讨论】:

  • Please, don't use mysql_* functions in new code。它们不再维护and are officially deprecated。看到red box?改为了解prepared statements,并使用PDOMySQLi - this article 将帮助您决定哪个。如果你选择 PDO,here is a good tutorial.
  • ..也就是说,您为什么要尝试将 99,999,999,999 记录插入数据库?您的主要问题是停止命令中引用的$conn 与另一个命令中启动的$conn 不同,因为它们是两个不同的请求。您也许可以将句柄 ($conn) 保存在 $_SESSION 变量中,然后引用它。
  • 您无法使用mysql_close() 停止执行。为此,您必须终止该过程。有关更多信息,请参阅此链接stackoverflow.com/questions/3787651/…
  • @h2ooooooo - 连接句柄等资源无法序列化或存储在会话中
  • 哇哇循环中的查询 for ($i = 1; $i &lt;= 99999999999; $i++) { ??根据该循环,您似乎计划在一个查询中杀死您的服务器....

标签: php mysql database insert


【解决方案1】:

本页的每一个答案都围绕一个点:

  • 在几个 PHP http 请求处理程序之间共享一些东西

当然,主要问题是 php 是 share nothing 的东西。

所以有些人建议使用会话,这可能很难做到,因为在关闭之前不会重新读取会话,并且您可能很容易覆盖会话中的数据。其他人建议使用共享内存或 APC。

我们说的是某种外部semaphore。当然,解决方案不是关闭连接,而是打破外部信号的循环。

但是你已经有了一个大的、简单的、也许太明显的共享系统。 您的数据库连接。

只需在数据库中检查循环指令的早期结束。

数据库通常为此任务提供咨询锁系统。例如使用GET_LOCKRELEASE_LOCK 指令。在主插入循环的每次迭代中使用IS_FREE_LOCK 并通过停止操作获取此锁定将是一种方法。对于释放锁的问题,可能是在来自所有记录的插入循环的另一个信号之后,或者在一段时间之后。但您也可以管理自己的基于表格的系统。

咨询锁系统的一个“优点”是它们忽略事务。如果您构建自己的基于表的系统(如果不是可序列化的事务,则可以),使用事务必须确保其他事务的写入在您的范围内可用。

使用数据库在 PHP 实例之间共享信息通常是 LAMP 中的默认情况,并且保证您在插入情况下拥有此工具,而 APC 则不是这样。

【讨论】:

    【解决方案2】:

    PHP 脚本的每次调用都会打开它自己与 MySQL 的连接,并且它们不会相互干扰。一个例外是使用mysql_pconnect() 打开的连接:它们保持打开状态并将被共享,但也可以使用 mysql_close() 关闭。

    结论:您尝试做的事情不会奏效(无论如何都是个坏主意)。

    您可能想要的是为您的插入创建一个后台任务并检查那里的中断消息(这可能就像一个空文件 .STOP[PID][PID] = 进程 ID 一样简单)。

    更新:

    我可以不使用 APC 吗?

    是的,您可以在此消息中使用 APC,前提是安装了 APC 扩展。事实并非如此,因此出现此错误:

    在第 31 行调用 /home/ext/library/public/testdb/test.php 中未定义的函数 acp_fetch()

    您对服务器有 root 访问权限吗?然后你就可以自己安装扩展了:

    sudo pecl install apc
    

    如果此命令不起作用,则需要先获取 PECL 安装程序,请参见此处:sudo pecl install apc returns error

    【讨论】:

      【解决方案3】:

      根据建议:

      • 在您当前的代码中,您实际上正在关闭一个不同的连接(在if(isset($_POST['stop'])) 分支中)

      • 您无法跨 PHP 脚本共享与 MySQL 的连接,因为您无法在会话中存储资源

      但是,您可以从另一个脚本存储连接 idkill 此连接:

      $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
      
      if(isset($_POST['start'])) {
      
          // store current connection ID
          // store an array of connection ID's in case several connections may run simultaneously
          $result = mysqli_query($conn, 'SELECT CONNECTION_ID()');
          $row = mysql_fetch_row($result);
          $_SESSION['connection_id'] = $row[0];
      
          // close session file
          // or else concurrent scripts using the same session will be blocked
          session_write_close();
      
          // do actual work here
          sleep(10);
      
          // keep in mind the connection may be killed from another script at any time, e.g.
          if (mysqli_query("...") == false) {
              // connection was probably killed
          }
      
          // reopen session (optional, do it only if you need your session data later)
          session_start();
      
      } else if(isset($_POST['stop'])) {
      
          // kill pending connection(s)
          mysqli_kill($conn, $_SESSION['connection_id']);
          // equivalent query in pure (My)SQL : 'KILL ' . $_SESSION['connection_id']        
      }
      

      您可以使用KILL QUERY [connection_id],而不是KILL [connection_id]。这将终止任何正在运行的查询,但不会关闭连接(但在您的情况下,您可能希望完全关闭连接)。

      【讨论】:

        【解决方案4】:

        这是一个完整的解决方案:

        <?php
            header('Content-Type: text/html; charset=utf8');
        
            $dbhost = '192.168.1.23';
            $dbuser = 'demouser01';
            $dbpass = 'demo*PW';
            $dbname = 'testdb1';
        
            $SHMKEY = ftok ( __FILE__, 'a');
            $SHMID  = shm_attach ( $SHMKEY );
        
            if ( !shm_has_var ( $SHMID, 1 ) ) {
              shm_put_var ( $SHMID, 1, true );
            }
        
            $conn = mysql_connect($dbhost, $dbuser, $dbpass) or die('Error with MySQL connection'); 
            mysql_select_db($dbname);
        
            mysql_query("SET NAMES 'utf8'");
            mysql_query("SET CHARACTER_SET_CLIENT='utf8'");
            mysql_query("SET CHARACTER_SET_RESULTS='utf8'");
        
            if(isset($_POST['start'])) { 
              $chi = 'chiiiii';
        
              $id = 1;
        
              // for ($i = 1; $i <= 99999999999; $i++) {
              while ( shm_get_var ( $SHMID, 1) ) { 
        
                $eng = substr(str_shuffle(str_repeat("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 5)), 0, 1024);
        
                $math = substr(str_shuffle(str_repeat("1234567890", 6)), 0, 16);
                $sql = "INSERT INTO test_tb (id,chi,eng,num) VALUES (".$id.",'".$chi."','".$eng."',".$math.")";
                $result = mysql_query($sql) or die('MySQL query error');
                $id++;
              }
        
              $id = 0;
              shm_detach ( $SHMID );
              sleep(60);
        
              mysql_close($conn);
            }
        
          else if(isset($_POST['stop'])) {
            shm_put_var ( $SHMID, 1, false );
            // mysql_close($conn);
          }
        ?>
        
        <form action="<?=$_SERVER['PHP_SELF'];?>" method="post">
          <input type="submit" name="start" value="Start Insert">
          <input type="submit" name="stop" value="Stop Insert">
        </form>
        

        【讨论】:

        • 您可能想改用$SHMKEY = ftok ( __FILE__, session_id() );,以隔离会话。
        • 假设您想允许单独的会话,即。
        • 是的,它适用于不同的会话,我的意思是你可以从一个会话开始它并从不同的会话中终止它。
        【解决方案5】:

        由于 PHP 不允许您在请求之间共享资源 (AFAIK),因此您可以通过几种方法来实现在另一个请求中停止进程的能力:

        首先添加这一行:

        if ( isset ($_POST['start']) ) {
            $_SESSION['continue'] = true;
        

        然后用 while 替换你的 for 语句(看起来你不关心迭代次数,如果是这样你可以改变这种行为):

        for ($i = 1; $i <= 99999999999; $i++) {
        

        替换为:

        while ( $_SESSION['continue'] )
        

        而不是关闭连接以停止插入:

        mysql_close ($con)
        

        将更改为:

        $_SESSION['continue'] = false;
        

        注意:不要忘记在脚本开头调用 session_start ()。 就是这样。

        我假设您想从同一会话中停止页面,如果不是这种情况,您可以使用 ACP 或 SHM 代替。例如:

        替换:

        $_SESSION['continue'] = true
        

        与:

        apc_store( 'continue', true );
        

        while ( $_SESSION['continue'] )
        

        与:

        while ( acp_fetch ('continue') )
        

        $_SESSION['continue'] = false;
        

        与:

        apc_store( 'continue', false );
        

        完成!

        【讨论】:

        • 会话将不起作用,除非您想在工作脚本的每个循环迭代中打开和关闭会话文件(如果可能的话)
        • @fab,是的,你是对的!谢谢。我只是错过了那个帖子。所以最好的方法是使用 APC 或 SHM。
        • @Boynux 和后来的读者。我觉得最好和更简单的方法是使用数据库。
        • 这也可能是一个解决方案。我把它留给读者和程序的上下文。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-12
        • 1970-01-01
        • 2021-09-10
        • 2013-11-13
        • 2015-11-10
        • 2017-09-16
        相关资源
        最近更新 更多