在PHP中锁定以实现政治部分
目标是让PHP脚本中的代码的某个部分一次只能由一个线程/进程执行。
一些限制:
所以认为这将是可能的(为什么不?)使用MySQL进行同步,但我得到意想不到的结果。
为了测试,我使用脚本test.php打开了两个浏览器选项卡
mysql_connect($dbhost, $dbusername, $dbpassword); mysql_select_db($database_name);
$sql = "SELECT my_val FROM
my_table
WHEREmy_var
='status' "; $result = mysql_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
SETmy_val
='RUNNING' WHEREmy_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
SETmy_val
='NOT_RUNNING' WHEREmy_var
='status' "; 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秒钟,转到另一个选项卡并访问脚本,以便两个脚本并行运行。 我期望第一个选项卡等待,第二个选项卡应在第一个查询后退出。 但是,两个选项卡都在sleep()行上等待。 这意味着第一个查询总是返回'NOT_RUNNING'。
一些奇怪的事情:
我已经尝试了一切,锁定表,事务,SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED,SET autocommit = 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的函数。
链接地址: http://www.djcxy.com/p/69653.html