PHP MySQL获取锁定
在一个脚本中,我试图使用MySQLPHP MySQL获取锁定,php,mysql,locking,Php,Mysql,Locking,在一个脚本中,我试图使用MySQLGET\u LOCK检查同一个脚本是否已经在运行。问题是,当脚本尝试获取锁时(锁不是免费的),无论我提供的参数是什么,它都会永远阻塞 <?php class Controller_Refresher extends Controller { public function action_run($key) { echo date('H:i:s'."\n", time()); $this->die_if_run
GET\u LOCK
检查同一个脚本是否已经在运行。问题是,当脚本尝试获取锁时(锁不是免费的),无论我提供的参数是什么,它都会永远阻塞
<?php
class Controller_Refresher extends Controller {
public function action_run($key) {
echo date('H:i:s'."\n", time());
$this->die_if_running();
$this->run();
echo date('H:i:s'."\n", time());
}
private function die_if_running() {
$result = DB::query(Database::SELECT, "SELECT IS_FREE_LOCK('refresher_running') AS free")->execute();
if (! intval($result[0]['free'])) die('Running already');
$result = DB::query(Database::SELECT, "SELECT GET_LOCK('refresher_running', 1)")->execute();
}
private function run() {
echo "Starting\n";
ob_flush();
sleep(10);
DB::query(Database::SELECT, "SELECT RELEASE_LOCK('refresher_running')")->execute();
}
}
而我想做的是让第二个选项卡
die('Running ready')代码>一种选择是依赖文件系统锁而不是数据库。因为需要处理的是脚本执行,所以这不重要。具有非阻塞独占锁的来自的示例:
$fp = fopen('/tmp/lock.txt', 'r+');
/* Activate the LOCK_NB option on an LOCK_EX operation */
if(!flock($fp, LOCK_EX | LOCK_NB)) {
die('Running already');
}
/* ... */
fclose($fp);
编辑
另一种选择是使用在每次执行开始时创建的状态文件,该文件将在脚本完成时自动删除
脚本只需检查状态文件是否存在,如果它已经存在,执行将停止:
define('statusFile', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'myjob.running');
//
// If a process is already running then exit
//
if (file_exists(statusFile)) {
die('Running already');
} else {
file_put_contents(date('Y-m-d H:i:s'), statusFile);
}
//
// Other code here
//
function shutdown() {
unlink(statusFile);
}
//
// Remove the status file on completion
//
register_shutdown_function('shutdown');
注意-此问题实际上可能是由php锁定会话文件引起的:
因此,您应该在需要并发运行的任何代码之前调用session_write_close()。我在尝试这个互斥类后发现:
这个课程做得很好,但是我的php脚本仍然在一个接一个地运行
此外,您不需要IS_FREE_LOCK()。只需调用GET_LOCK('refresher_running',0),如果它给了您锁,它将返回1,如果锁被占用,它将返回0。那样更原子化。当然,锁定超时在某些情况下仍然很有用,比如当您想对任务排队时,但是如果您同时收到太多请求,请注意脚本超时
扎克·莫里斯@roddik:如果flock
失败,则可以手动实现相同的功能。@roddik:True。在Windows上检测异常终止是困难的,但它是可行的。例如,通过不断更新状态文件内的时间戳以指示继续执行,过时的状态文件显示异常终止。
define('statusFile', sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'myjob.running');
//
// If a process is already running then exit
//
if (file_exists(statusFile)) {
die('Running already');
} else {
file_put_contents(date('Y-m-d H:i:s'), statusFile);
}
//
// Other code here
//
function shutdown() {
unlink(statusFile);
}
//
// Remove the status file on completion
//
register_shutdown_function('shutdown');