2012-02-02 8 views
7

同じコードの複数のインスタンスが異なるサーバーで実行されている場合、データベースを使用して、別のサーバーで既に実行されているプロセスがあるサーバーで開始しないようにしたいと考えています。データベースを使用してセマフォを管理するにはどうすればよいですか?

Oracleのトランザクション処理、ラッチなどを使用する実行可能なSQLコマンドが出てきている可能性がありますが、試したことがあります。

年前、SQLウィズであった開発者は、セマフォを取得した場合はtrueを返し、取得できなかった場合はfalseを返す単一のSQLトランザクションを持っていました。その後、私の処理の最後に、セマフォを解放するために別のSQLトランザクションを実行する必要があります。クールですが、データベースがサポートされているセマフォがタイムアウトする可能性があるかどうかはわかりません。それはタイムアウトを持っている巨大なボーナスでしょう!

編集:ここでは

は、いくつかの実行可能なSQLコマンドのかもしれないものではないが、cronジョブハックを通じて以外にはタイムアウト:

--------------------------------------------------------------------- 
--Setup 
--------------------------------------------------------------------- 
CREATE TABLE "JOB_LOCKER" ("JOB_NAME" VARCHAR2(128 BYTE), "LOCKED" VARCHAR2(1 BYTE), "UPDATE_TIME" TIMESTAMP (6)); 
CREATE UNIQUE INDEX "JOB_LOCKER_PK" ON "JOB_LOCKER" ("JOB_NAME") ; 
ALTER TABLE "JOB_LOCKER" ADD CONSTRAINT "JOB_LOCKER_PK" PRIMARY KEY ("JOB_NAME"); 
ALTER TABLE "JOB_LOCKER" MODIFY ("JOB_NAME" NOT NULL ENABLE); 
ALTER TABLE "JOB_LOCKER" MODIFY ("LOCKED" NOT NULL ENABLE); 

insert into job_locker (job_name, locked) values ('myjob','N'); 
commit; 

--------------------------------------------------------------------- 
--Execute at the beginning of the job 
--AUTOCOMMIT MUST BE OFF! 
--------------------------------------------------------------------- 
select * from job_locker where job_name='myjob' and locked = 'N' for update NOWAIT; 
--returns one record if it's ok. Otherwise returns ORA-00054. Any other thread attempting to get the record gets ORA-00054. 
update job_locker set locked = 'Y', update_time = sysdate where job_name = 'myjob'; 
--1 rows updated. Any other thread attempting to get the record gets ORA-00054. 
commit; 
--Any other thread attempting to get the record with locked = 'N' gets zero results. 
--You could have code to pull for that job name and locked = 'Y' and if still zero results, add the record. 

--------------------------------------------------------------------- 
--Execute at the end of the job 
--------------------------------------------------------------------- 
update job_locker set locked = 'N', update_time = sysdate where job_name = 'myjob'; 
--Any other thread attempting to get the record with locked = 'N' gets no results. 
commit; 
--One record returned to any other thread attempting to get the record with locked = 'N'. 

--------------------------------------------------------------------- 
--If the above 'end of the job' fails to run (system crash, etc) 
--The 'locked' entry would need to be changed from 'Y' to 'N' manually 
--You could have a periodic job to look for old timestamps and locked='Y' 
--to clear those. 
--------------------------------------------------------------------- 
+2

手動でレコードが期限切れにならないように、ロックをタイムスタンプにすることができます。ロックを取得すると、タイムスタンプが設定されます。ロックを取得するには、ロックのクエリで条件WHERE locktime <(SYSDATE - timeToExpire)を追加する必要があります。その後、ロックは自動的に期限切れになります。 – Glenn

+0

ありがとうGlenn ... Y/Nの代わりにタイムスタンプを使うと、上のほうがいい。 – Dale

答えて

11

あなたはDBMS_LOCKになっているはずです。本質的に、Oracleが内部的に使用するエンキュー・ロック・メカニズムを可能にしますが、ロック・タイプの「UL」(ユーザー・ロック)を定義できる点が異なります。ロックは共有または排他的に保持することができ、ロックを取るか、あるモードから別のモードにロックを変換する要求は、タイムアウトをサポートします。

あなたがしたいと思うと思います。

希望に役立ちます。

+0

私はこれにタイムアウトがあるのが好きです。以前はDBMS_LOCKを使用したことはありませんでした。実際SQL騎手ではないので、それを稼働させるうえでの難しい戦いかもしれません。 – Dale

関連する問題