[英]Compare-and-swap operation for row with selected id in database (Oracle or ANSI SQL)?
I want to implement failsafe persistent synchronization in application based on database (Oracle in my case, but like to see ANSI SQL solution).我想在基于数据库的应用程序中实现故障安全持久同步(在我的例子中是 Oracle,但喜欢看 ANSI SQL 解决方案)。
I work with tasks which can be run in different threads, applications or servers.我处理可以在不同线程、应用程序或服务器中运行的任务。
Each type of task (I differ them by ID
) may not run in concurrent - that is why I need synchronization.每种类型的任务(我通过
ID
区分它们)可能不会并发运行 - 这就是我需要同步的原因。 All have access to DB so it is good place for synchronization!所有人都可以访问数据库,因此它是同步的好地方!
Each thread/application/server can fail, so I need a way to remove acquired lock from ID
after timeout.每个线程/应用程序/服务器都可能失败,所以我需要一种方法来在超时后从
ID
删除获取的锁。
The first that come to mind is to use table with:首先想到的是使用 table :
ID
STATE
TS
fields.领域。 All I need is atomic operations which:
我所需要的只是原子操作,它:
STATE
value from completed to executing (to synchronize) and set TS
to current time.STATE
值从完成更改为执行(同步)并将TS
设置为当前时间。 Return false if STATE
is not completed .STATE
未完成,则返回 false。STATE
value from executing / recovering to recovering if sysdate - TS > delay
and set TS
to current time (to be failsafe).sysdate - TS > delay
并将TS
设置为当前时间(以确保故障安全),请尝试将STATE
值从执行/恢复更改为恢复。 Else return false. SQL update statement mostly make that I want: SQL更新语句主要是我想要的:
update TASK set STATE = 'executing', TS = sysdate
where ID = :id and STATE = 'completed'
and:和:
update TASK set STATE = 'recovering', TS = sysdate
where ID = :id and STATE in ('executing', 'recovering')
and sysdate - TS > :delay
Only one issue that I see - how to get know (from Java application through JDBC) if update actually performed or not (in order to be true compare-and-swap operation )?我只看到一个问题 - 如何知道(从 Java 应用程序通过 JDBC)更新是否实际执行(为了成为真正的比较和交换操作)? May be by getting updated row number (is this info available through JDBC)?
可能是通过获取更新的行号(此信息是否可通过 JDBC 获得)?
Is I am correct with my assumption that update is atomic for where condition?我假设更新对于where条件是原子的,这是否正确?
Is there another way to implement failsafe persistent synchronization in application based on database?有没有另一种方法可以在基于数据库的应用程序中实现故障安全持久同步?
PS My question is differ from: PS我的问题不同于:
This easiest way might be to create and run a stored procedure which could then return what the result of the change was.这种最简单的方法可能是创建并运行一个存储过程,然后该过程可以返回更改的结果。
Edit (expanded answer): Sorry I thought you were looking for a way to get the answer back.编辑(扩展答案):抱歉,我以为您正在寻找一种方法来获得答案。 I would do something like the following (although I haven't got an oracle instance at home to test it on, sorry)
我会做类似以下的事情(虽然我家里没有一个 oracle 实例来测试它,抱歉)
function GetLockForRun(p_id task.id%TYPE)
return VARCHAR2
declare
l_result VARCHAR2;
begin
select STATE, TS
into l_state, l_ts
from Task
where ID = p_id;
for update; --this locks the row until you commit
if (state == 'completed' or sysdate - TS > delay)
update TASK
set STATE = 'executing', TS = sysdate
where ID = p_id;
l_result := "OK";
else
l_result := "Do not run";
end if
commit; --release for update lock
return l_result;
end;
This function locks the row for the length of its execution so no other process can edit it, this means only one process can run this at a time.该函数在其执行期间锁定该行,因此其他进程无法对其进行编辑,这意味着一次只有一个进程可以运行该行。 Since this procedure will run in the database it will finish so you don't have to worry if the java process dies.
由于此过程将在数据库中运行,它将完成,因此您不必担心 java 进程是否终止。 I guess the only downside is that this is blocking but only for the run of this function which is short.
我想唯一的缺点是这是阻塞的,但仅适用于这个较短的函数的运行。 If you really can't have that then you could try making the select for update not wait;
如果你真的不能,那么你可以尝试让选择更新不等待; off the top of my head I can not remember how to do this.
在我的头顶上,我不记得如何做到这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.