仅当所有这些事务都成功时才提交并发事务

时间:2018-02-02 20:17:56

标签: oracle plsql oracle11g parallel-processing

我想要的是同时执行一个过程(将在Oracle 11g上运行),并且只有当所有并发事务都成功时才提交整个操作。

我想到的两种并行执行方式是$ git fsck --full Checking object directories: 100% (256/256), done. Checking objects: 100% (37/37), done. $ git gc fatal: error ummapping packed-refs file .git/packed-refs: Invalid argument error: failed to run pack-refs DBMS_PARALLEL_EXECUTE,但据我所知,在这两种情况下,创建的进程都在各自的会话中运行,每个进程都会在终止(或者如果出现错误,可以回滚自己的更改)。

我想要的是启动并行进程,等待每个进程完成,检查它们是否都成功,然后提交更改(如果至少一个进程失败则回滚)。

上述情况是否可行? (以及如何实施)

感谢。

1 个答案:

答案 0 :(得分:2)

我很好奇为什么会出现这个要求;我可能会质疑是否真的有必要来找我。但如果你不能质疑这个要求,我就是这样做的。

-- We need to have a common persistent location for all of the jobs to read
CREATE TABLE test_tab
(
   job_name VARCHAR2(30),
   status   VARCHAR2(30)
)
/

-- The procedure writing to our table must be autonomous so that updates occur 
-- without committing the rest of the work
CREATE OR REPLACE PROCEDURE test_log
(
   i_job_name IN VARCHAR2,
   i_status   IN VARCHAR2
) IS
   PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
   MERGE INTO test_tab tgt
   USING dual
   ON (tgt.job_name = i_job_name)
   WHEN MATCHED THEN
      UPDATE SET status = i_status
   WHEN NOT MATCHED THEN
      INSERT VALUES (i_job_name, i_status);
   COMMIT;
END test_log;
/

CREATE OR REPLACE PROCEDURE test_proc(i_job_name IN VARCHAR2) IS
   l_complete_cnt INTEGER;
   l_error_cnt    INTEGER;
   l_waiting      BOOLEAN := TRUE;
BEGIN
   -- !!! Your code here !!!

   /* -- Uncomment this block to prove the rollback scenario.
   IF i_job_name LIKE '%8' THEN
      raise_application_error(-20001, 'Throwing an error to prove rollback.');
   END IF;*/

   test_log(i_job_name, 'COMPLETE');

   WHILE l_waiting LOOP
      SELECT SUM(CASE WHEN status IN ('COMPLETE', 'COMMITTED') THEN 1 ELSE 0 END)
            ,SUM(CASE WHEN status = 'ERROR' THEN 1 ELSE 0 END)
        INTO l_complete_cnt
            ,l_error_cnt
        FROM test_tab
       WHERE REGEXP_LIKE(job_name, 'TEST_JOB_\d');

      IF l_complete_cnt = 8 THEN
         COMMIT;
         test_log(i_job_name, 'COMMITTED');
         l_waiting := FALSE;
      ELSIF l_error_cnt > 0 THEN
         ROLLBACK;
         test_log(i_job_name, 'ROLLBACK');
         l_waiting := FALSE;
      ELSE
         dbms_lock.sleep(seconds => 5);
      END IF;
   END LOOP;
EXCEPTION
   WHEN OTHERS THEN
      test_log(i_job_name, 'ERROR');
      RAISE;
END;
/

-- Begin test section
BEGIN
   FOR i IN 1..8 LOOP
      dbms_scheduler.create_job('TEST_JOB_'||i
                               ,'PLSQL_BLOCK'
                               ,'BEGIN test_proc(''TEST_JOB_'||i||'''); END;'
                               ,start_date => SYSDATE
                               ,enabled => TRUE);
   END LOOP;
END;
/

SELECT * FROM test_tab;
TRUNCATE TABLE test_tab; --the table should be cleared between tests