【问题标题】:How do I use a database to manage a semaphore?如何使用数据库来管理信号量?
【发布时间】:2012-02-25 07:19:56
【问题描述】:

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

我可能会想出一些使用 Oracle 事务处理、锁存器或其他东西的可行 SQL 命令,但我宁愿找到一些已经尝试过且真实的东西。

几年前,一个 SQL 专家的开发人员有一个 SQL 事务,它获取信号量,如果它得到它则返回 true,如果它没有得到它则返回 false。然后在我的处理结束时,我需要运行另一个 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.
---------------------------------------------------------------------

【问题讨论】:

  • 为避免手动使记录过期,您可以将锁设为时间戳。获取锁将时间戳设置为现在。要获取锁,对锁的查询需要添加条件 WHERE locktime
  • 感谢 Glenn...timestamp 而不是 Y/N 是对上述内容的一个很好的补充。

标签: sql oracle transactions locking semaphore


【解决方案1】:

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

我想它会做你想做的。

希望对您有所帮助。

【讨论】:

  • 我喜欢这有一个超时。我以前从未使用过 DBMS_LOCK,而且我也不是真正的 SQL 骑师,所以要让它工作对我来说可能是一场艰苦的战斗,呵呵。
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2011-07-15
  • 2011-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多