Oracle SQL - 使事务原子化
我的程序是这样的:
create or replace
PROCEDURE NEWJOBIDPROC (JOB_ID OUT NUMBER )
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
-- PROCEDURE TO RETRIEVE THE JOB ID
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
IS
BEGIN
-- select the job_id
SELECT VALUE+1 INTO JOB_ID FROM JOB_TABLE WHERE ID = 50;
-- update table JOB_TABLE with the latest job id
UPDATE JOB_TABLE SET VALUE = JOB_ID WHERE ID = 50;
END;
现在我的问题如下。
假设我同时多次调用此过程。 在我们的示例中,让我们同时调用同一个过程。 当它们都运行 select 语句时,它们会收到一些值 - 让它为 200。
现在,它们都将对 job_table 进行更新,具有相同的值 200 - 这不是我想要的。我不想要重复的。
那么,如何将整个代码标记为原子呢?我希望选择和更新同时运行并且线程安全。我希望两个语句一起被标记为原子。
I have a procedure that goes like this:
create or replace
PROCEDURE NEWJOBIDPROC (JOB_ID OUT NUMBER )
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
-- PROCEDURE TO RETRIEVE THE JOB ID
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
IS
BEGIN
-- select the job_id
SELECT VALUE+1 INTO JOB_ID FROM JOB_TABLE WHERE ID = 50;
-- update table JOB_TABLE with the latest job id
UPDATE JOB_TABLE SET VALUE = JOB_ID WHERE ID = 50;
END;
Now my question is the following.
Let us say I have multiple calls to this procedure at the same time.
In our example let us make that two simultaneous calls to the same procedure.
When both of them run the select statement they receive some value - let it be 200.
Now, they will both make an update to the job_table, with the same value of 200 - which is not what I want. I don't want duplicates.
So, how do I mark the whole code as atomic? I want the select and the update to run at the same time and be thread safe. I want two statements together to be marked as atomic.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
请参阅 @derobert 提供的链接以获取更多信息,但对于您的特定示例,您可以这样做:
但是 - 您没有考虑过使用序列吗?
See the link @derobert provided for more information, but for your particular example you could do this:
But - have you not considered using a Sequence instead?
如果您打算稍后更新该行,则应该锁定该行。第二个事务将被阻止并等待您完成事务(默认情况),或者如果它尝试锁定指定为 NOWAIT 的行,则会收到错误。
在任何一种情况下,锁定行都会阻止 “丢失更新” 您所描述的行为。
You should lock the row if you intent to update it afterwards. The second transaction will either be blocked and wait for you to finish the transaction (default case) or will receive an error if it has tried to lock the row with NOWAIT specified.
In either case locking the row prevents the "lost update" behaviour you've described.
虽然序列可能是解决您的问题的最佳解决方案,但我会使用乐观锁定来解决此类问题。
当您在 JOB_TABLE 中添加时间戳列时,您可以在选择查询中获取时间戳,并将其添加为更新查询的 where 子句的约束。
While a Sequence is probably the best solution for your problem, I would use optimistic locking for these kind of problems.
When you add a timestamp column in the JOB_TABLE, you can get the timestamp in the select query, and add it as a contraint to the where-clause of the update query.