目标是拥有一个具有代码某个部分的PHP脚本,该脚本一次只能由一个线程/进程执行。

一些限制:

  • 我的系统上没有信号量
  • 手册提到的是,羊群不能在多线程服务器中依赖,因此羊群()已熄灭。 (确认)

因此,认为(为什么不呢?)可以使用mySQL进行同步,但是我会得到意外的结果。

要测试,我使用脚本test.php打开了两个浏览器选项卡

mysql_connect($ dbhost,$ dbusername,$ dbpassword); mysql_select_db($ database_name);

$ sql =“从中选择my_val my_table 在哪里 my_var='状态'“”; $ result = mysql_query($ sql)或die(mysql_error()); $ row = mysql_fetch_array($ result,mysql_assoc); echo echo“ echo”状态为:”。$ row ['my_val']。
n“; mysql_free_result($ result);

if($ row ['my_val'] =='running')die('进程已经运行!');

//进入关键部分

$ sql =“更新 my_tablemy_val='运行' my_var='状态'”; mySQL_Query($ sql);

睡眠(10); //在这里做一些工作。回声完成工作
';

//留下关键部分。让其他人知道$ sql =“更新 my_tablemy_val='not_running'在哪里 my_var='状态'”; mySQL_Query($ sql);

表是:

CREATE TABLE `my_table` (
  `my_var` varchar(255) NOT NULL default '',
  `my_val` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`my_var`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `my_table`
VALUES (
'status', 'NOT_RUNNING'
) 

我转到第一个浏览器选项卡并访问脚本。我等待5秒钟,转到另一个选项卡并访问脚本,以便两个脚本并行运行。我希望第一个选项卡会等待,第二个标签应在第一个查询之后退出。但是,两个标签都在睡眠()线上等待。这意味着第一个查询总是返回“ not_running”。

一些奇怪的事情:

  • 当我重复上述实验时,我在Firefox中运行两个选项卡,然后在第三个不同的浏览器类型中(例如Chrome)运行,然后它起作用! (在睡眠时,状态设置为运行,脚本在状态运行时提早退出)
  • 当我使用两个不同命令行窗口重复上述实验并从命令行中运行脚本时,它可以工作!
  • 我在等待时检查phpmyadmin,状态得到正确更新。

我已经尝试了所有内容,锁定表,交易,设置全局交易隔离级别读取未承诺,设置自动加入= 1;,但总是相同的结果。

有人知道这里发生了什么吗?这个问题有很好的解决方案吗?

测试的系统: - Win,MySQL 5.0,PHP 5.3 -Linux,MySQL 5.0.91 -Community -Log,PHP 5.2.12

我完全被困在这里,感谢您的看看!


更新:

感谢您提交答案 - 我仍然无法解决这个问题。这是带有get_lock()和session_write_close()的代码:我还尝试了行级锁定,交易和不同的隔离级别。也许无法完成?

session_write_close();

mysql_connect($dbhost, $dbusername, $dbpassword);
mysql_select_db($database_name);

$sql = "CREATE TABLE IF NOT EXISTS `my_table`  (
  `my_var` varchar(255) NOT NULL default '',
  `my_val` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`my_var`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
";
mysql_query($sql)or die(mysql_error());

mysql_query ("SELECT get_lock('my_lock', 100)");

$sql = "SELECT my_val FROM `my_table` WHERE `my_var`='status' ";
$result = mysql_unbuffered_query($sql)or die(mysql_error());
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "status is:".$row['my_val']."
\n"; mysql_free_result($result); if ($row['my_val']=='RUNNING') die ('process is already running!'); // entering critical section $sql = "UPDATE `my_table` SET `my_val`='RUNNING' WHERE `my_var`='status' "; mysql_query ($sql); sleep(10); // do some work here. echo 'finished work
'; // leave critical section. let the others know //$sql = "UPDATE `my_table` SET `my_val`='NOT_RUNNING' WHERE `my_var`='status' "; $sql = "REPLACE INTO `my_table` (`my_var`,`my_val`) VALUES ('status', 'NOT_RUNNING')"; mysql_query ($sql); $result = mysql_query($sql)or die(mysql_error()); mysql_query ("SELECT release_lock('my_lock')"); die();
有帮助吗?

解决方案

第二个浏览器窗口没有挂在 sleep 命令。由于会话正在阻止(因此它试图打开同一会话),因此之所以阻止。如果您不再需要(因此不希望它阻止),则可以关闭当前会话 session_write_close...

其他提示

mySQL具有称为的函数 get_lock.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top