首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免用于更新的死锁

避免用于更新的死锁
EN

Stack Overflow用户
提问于 2020-07-05 05:47:18
回答 2查看 915关注 0票数 0

如何释放另一个会话的行级锁,以避免的死锁用于更新?我有张桌子

这是密码,

代码语言:javascript
复制
DECLARE
CURSOR c1 IS
    SELECT id
      FROM tasks;
ls_id NUMBER;
vaf varchar2(1000);
BEGIN
OPEN c1;
LOOP
    FETCH c1
        INTO ls_id;
  vaf := 'select * from  tasks where id =''' || ls_id ||
           ''' for update of id';
    EXECUTE IMMEDIATE vaf;
    UPDATE tasks
       SET status = 'B'
     WHERE id = ls_id;
    EXIT WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
commit;
END;

如果我首先运行for update --在一个会话中运行id=4行的表tasks,然后在plsql developer ide测试窗口中的另一个会话中运行上面的块,然后继续执行line.The循环的执行行,然后在循环后提交死锁,那么在id=1,2和3中就不会出现更新。如果在update语句之后输入commit,它将把记录更新到id =3,并在id=4上陷入死锁。是的,在循环中提交提交并不是个好主意。

因此,为了避免死锁,我使用了跳过锁定。

代码语言:javascript
复制
SELECT id FROM tasks FOR UPDATE SKIP LOCKED;

它解决了id=4上的死锁,但却跳过了锁定的记录id=4并更新了剩余的记录。

不允许杀死会话。有没有其他可能的方法来更新锁定的记录?因为我正在运行一个调度程序,它正在更新重要的转换。因此,我不需要避免或跳过锁定的记录,以及调度程序没有死锁。有可能吗?

EN

回答 2

Stack Overflow用户

发布于 2020-07-05 19:48:02

因此,您正在对任务表进行更新,将上每一行上的值设置为'B‘。代码的问题是,您从任务中选择所有行来驱动处理,而不管它们是否被锁定,然后在循环中处理每个单独的行时尝试锁定它们。从逻辑上讲,您似乎想要做的是每次运行任务时更新任务中的所有行。那么,唯一可靠的方法就是从一开始就锁定所有行。

代码的逻辑可以简化为:

代码语言:javascript
复制
DECLARE
   CURSOR c1 IS
      SELECT *
      FROM tasks
      FOR UPDATE NOWAIT;
   row_locked EXCEPTION;
   PRAGMA EXCEPTION_INIT(row_locked, -54);
BEGIN
   OPEN c1;
   UPDATE tasks SET status = 'B';
   COMMIT;
EXCEPTION
   WHEN row_locked THEN
      DBMS_OUTPUT.PUT_LINE ( 'Table is busy' );
      ROLLBACK;
      IF c1%ISOPEN THEN CLOSE c1;
END;

但是,如果您希望在不同的会话中同时执行此代码,则可能会导致阻塞锁(潜在的死锁)。

也许添加一个WHERE status != 'B'条件可能会减少这种可能性。

如果没有,请考虑使用AQ来序列化更新请求,这将有助于排序进程队列。这是一般性的建议,因为我们需要更多关于这个表的全部用法的详细信息来提供具体的建议。

票数 1
EN

Stack Overflow用户

发布于 2020-07-05 10:21:34

您是否尝试过选择用于更新、跳过锁定的

代码语言:javascript
复制
DECLARE
CURSOR c1 IS
    SELECT id
      FROM tasks;
ls_id NUMBER;
vaf varchar2(1000);
BEGIN
OPEN c1;
LOOP
    FETCH c1
        INTO ls_id;
  vaf := 'select * from  tasks where id =''' || ls_id ||
           ''' for update of id skip locked';
    EXECUTE IMMEDIATE vaf;
    UPDATE tasks
       SET status = 'B'
     WHERE id = ls_id;
    EXIT WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
commit;
END;

如果要避免死锁,请尝试使用“锁定”子句。还请记住,如果指定跳转锁定,并且表被另一个会话锁定为独占模式,那么数据库将不会返回SELECT语句的结果,直到表上的锁被释放。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62737290

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档