3
<?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 中停止运行,但活动仍然存在。插件仍在继续执行。如何解决问题?谢谢。

4

5 回答 5

2

此页面中的每个答案都围绕一个点:

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

当然,主要的问题是 php 是一个什么都没有的东西。

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

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

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

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

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

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

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

于 2013-02-19T17:55:43.580 回答
2

由于 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 );

完毕!

于 2013-02-15T11:58:55.437 回答
1

正如已建议的那样:

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

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

但是,您可以存储连接id并从另一个脚本中终止此连接:

$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 [connection_id],您可以使用KILL QUERY [connection_id]. 这将终止任何正在运行的查询,但不会关闭连接(但在您的情况下,您可能希望完全关闭连接)。

于 2013-02-18T20:21:12.380 回答
1

Here is a complete solution:

<?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>
于 2013-02-18T06:07:14.740 回答
1

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 返回错误

于 2013-02-15T10:47:31.307 回答