提供された答えは良いです、ファイルロックはうまくいきます、しかし、あなたがMySQLを使っているので、私も答えると思いました。MySQLでは、 GET_LOCKおよびRELEASE_LOCKを使用して協調非同期ロックを実装できます。
*免責事項:以下の例はテストされていません。私は以前にこれに非常に近いものをうまく実装しました、そして以下は一般的な考えでした。
このGET_LOCK関数をMutexというPHPクラスでラップしたとしましょう。
class Mutex {
private $_db = null;
private $_resource = '';
public function __construct($resource, Zend_Db_Adapter $db) {
$this->resource = $resource;
$this->_db = $db;
}
// gets a lock for $this->_resource; you could add a $timeout value,
// to pass as a 2nd parameter to GET_LOCK, but I'm leaving that
// out for now
public function getLock() {
return (bool)$this->_db->fetchOne(
'SELECT GET_LOCK(:resource)',
array(
':resource' => $this->_resource
));
}
public function releaseLock($resource) {
// using DO because I really don't care if this succeeds;
// when the PHP process terminates, the lock is released
// so there is no worry about deadlock
$this->_db->query(
'DO RELEASE_LOCK(:resource)',
array(
':resource' => $resource
));
}
}
A()がテーブルからメソッドをフェッチする前に、ロックを要求します。リソース名として任意の文字列を使用できます。
class JobA {
public function __construct(Zend_Db_Adapter $db) {
$this->_db = $db;
}
public function A() {
// I'm assuming A() is a class method and that the class somehow
// acquired access to a MySQL database - pretend $this->db is a
// Zend_Db instance. The resource name can be an arbitrary
// string - I chose the class name in this case but it could be
// 'barglefarglenarg' or something.
$mutex = new Mutex($this->db, get_class($this));
// I choose to throw an exception but you could just as easily
// die silently and get out of the way for the next process,
// which often works better depending on the job
if (!$mutex->getLock())
throw new Exception('Unable to obtain lock.');
// Got a lock, now select the rows you need without fear of
// any other process running A() getting the same rows as this
// process - presumably you would update/flag the row so that the
// next A() process will not select the same row when it finally
// gets a lock. Once we have our data we release the lock
$mutex->releaseLock();
// Now we do whatever we need to do with the rows we selected
// while we had the lock
}
}
複数のプロセスが同じデータを選択および変更するシナリオを設計する場合、この種のことは非常に便利です。MySQLを使用する場合、移植性のために、ファイルロックメカニズムよりもこのデータベースアプローチを好みます。ロックメカニズムがファイルシステムの外部にある場合は、さまざまなプラットフォームでアプリをホストする方が簡単です。確かにそれは可能であり、それはうまく機能しますが、私の個人的な経験では、これは使いやすいと思いました。
アプリをデータベースエンジン間で移植可能にすることを計画している場合、このアプローチはおそらくうまくいきません。