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

这是密码,
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上陷入死锁。是的,在循环中提交提交并不是个好主意。
因此,为了避免死锁,我使用了跳过锁定。
SELECT id FROM tasks FOR UPDATE SKIP LOCKED;它解决了id=4上的死锁,但却跳过了锁定的记录id=4并更新了剩余的记录。
不允许杀死会话。有没有其他可能的方法来更新锁定的记录?因为我正在运行一个调度程序,它正在更新重要的转换。因此,我不需要避免或跳过锁定的记录,以及调度程序没有死锁。有可能吗?
发布于 2020-07-05 19:48:02
因此,您正在对任务表进行更新,将上每一行上的值设置为'B‘。代码的问题是,您从任务中选择所有行来驱动处理,而不管它们是否被锁定,然后在循环中处理每个单独的行时尝试锁定它们。从逻辑上讲,您似乎想要做的是每次运行任务时更新任务中的所有行。那么,唯一可靠的方法就是从一开始就锁定所有行。
代码的逻辑可以简化为:
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来序列化更新请求,这将有助于排序进程队列。这是一般性的建议,因为我们需要更多关于这个表的全部用法的详细信息来提供具体的建议。
发布于 2020-07-05 10:21:34
您是否尝试过选择用于更新、跳过锁定的
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语句的结果,直到表上的锁被释放。
https://stackoverflow.com/questions/62737290
复制相似问题