0

我有一个简单的程序,但我不确定如何最好地实施停止死锁或记录锁的策略。我正在更新游标 LOOP 中的许多表,同时调用一个也更新表的过程。

死锁或记录锁存在问题,因此我的任务是解决程序遇到死锁或记录锁时崩溃的问题,但要休眠 5 分钟并继续处理任何新记录。

完美的解决方案是它跳过死锁或记录锁并继续处理其余未锁定的记录,休眠 5 分钟,然后在再次调用游标时拾取该记录。该程序继续运行一整天,直到它被杀死。

我的程序如下,我已经放入了我认为最好的内容,但是我应该在内循环而不是外循环内有异常吗?同时在内循环中有一个保存点?

PROCEDURE process_dist_data_fix
IS

   lx_record_locked             EXCEPTION;
   lx_deadlock_detected         EXCEPTION;
   PRAGMA EXCEPTION_INIT(lx_record_locked, -54);
   PRAGMA EXCEPTION_INIT(lx_deadlock_detected, -60);   


   CURSOR c_files
   IS
        SELECT surr_id
          FROM batch_pre_dist_data_fix 
         WHERE status = 'REQ'
      ORDER BY surr_id;

   TYPE file_type IS TABLE OF batch_pre_dist_data_fix.surr_id%TYPE;
   l_file_tab file_type;

BEGIN

   LOOP

        BEGIN

            OPEN c_files;
            FETCH c_files BULK COLLECT INTO l_file_tab;
            CLOSE c_files;

            IF l_file_tab.COUNT > 0
                THEN

                    FOR i IN 1..l_file_tab.COUNT
                    LOOP    

                    -- update main table with start date
                        UPDATE batch_pre_dist_data_fix
                        SET start_dtm = SYSDATE
                        WHERE surr_id = l_file_tab(i);

                    -- update tables
                        update_soundmouse_tables (l_file_tab(i));

                   END LOOP;

           END IF;

        Dbms_Lock.Sleep(5*60); -- sleep for 5 mins before looking for more records to process

        -- if there is a deadlock or a locked record then log the error, rollback and wait 5 minutes, then loop again 
        EXCEPTION
            WHEN lx_deadlock_detected OR lx_record_locked THEN
                ROLLBACK; 
                Dbms_Lock.Sleep(5*60);   -- sleep for 5 minutes before processing records again

        END;

   END LOOP;

END process_dist_data_fix;
4

1 回答 1

0

首先要了解死锁与“记录锁定”是完全不同的问题。因此,对于“记录锁定”,大多数情况下您不需要做任何事情。9/10 您希望程序等待锁定。如果您等待的时间过长,那么您可能需要重新定义您的事务边界。例如,这里您的代码模式非常典型。你阅读了一份“要做”的清单,然后你“去做”。在这种情况下,您很少会想要为“记录锁定”做一些特殊的事情。如果 batch_pre_dist_data_fix 表行由于某种原因被锁定,您应该等待锁定释放并继续。如果 reverse 为真,那么由于这项工作需要很长时间并且您为另一个进程锁定了很长时间的 batch_pre_dist_data_fix,那么您可能需要重新定义事务边界。即,也许您会说在您提交的每次循环迭代之后。但要注意打开游标在提交时的行为。

死锁是一种完全不同的动物。在这里,您总是有“另一个会话”,并且 db 检测到一种情况,您将永远无法摆脱这种情况,并且它杀死了一个随机会话。因此,当会话 1 正在等待会话 2 的资源而会话 2 正在等待会话 1 的资源时。这是 db 可以检测到的无限等待条件,因此它会杀死一个随机会话。解决这个问题的一种简单方法是,如果处理多个表的所有事务都以相同的顺序锁定它们,我们将不会出现死锁。所以假设我们有表 A、B、C、D。如果我们简单地决定表将按此顺序锁定。即可以做 A,B,D 或 A,C,D 或 C,D - 但绝不可以做 D,C。这样你就不会陷入僵局。

于 2019-04-08T20:37:59.903 回答