如何使用数据库管理信号量?

时间:2012-02-02 16:09:48

标签: sql oracle transactions locking semaphore

如果同一代码的多个实例在不同的服务器上运行,我想使用数据库来确保一个服务器上的进程如果已经在另一台服务器上运行就不会启动。

我可能会提出一些可行的SQL命令,这些命令使用了Oracle事务处理,锁存器或其他任何东西,但我宁愿找到一些已经尝试过的东西。

多年前,一个SQL wiz的开发人员只有一个SQL事务,它获取了信号量,如果得到它则返回true,如果没有得到它则返回false。然后在我处理结束时,我需要运行另一个SQL事务来释放信号量。这很酷,但我不知道数据库支持的信号量是否有可能超时。如果超时,那将是一个巨大的好处!

编辑:

这可能是一些可行的SQL命令,但除了通过cron job hack之外没有超时:

---------------------------------------------------------------------
--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.
---------------------------------------------------------------------

1 个答案:

答案 0 :(得分:11)

您应该查看DBMS_LOCK。本质上,它允许Oracle在内部使用的入队锁定机制,除了它允许您定义锁定类型“UL”(用户锁定)。锁可以保持共享或独占,并且锁定或将锁从一种模式转换为另一种模式的请求支持超时。

我认为它会做你想要的。

希望有所帮助。