2017-01-03 7 views
0

UTL_FILEを使用してファイル内の表をエクスポートするPL/SQLプロシージャがいくつかあります。ここでファイルを作成するロールバックプロシージャ

は、スナップです:

PROCEDURE export_t1 
    AS 
    l_file  UTL_FILE.FILE_TYPE; 
    record  VARCHAR2(4096); 
    BEGIN 

    l_file := UTL_FILE.FOPEN(DIRECTORY_PATH, FILENAME, 'A'); 

    FOR j IN 
    (SELECT * FROM PRODUCTS WHERE HANDLE = '0') 
    LOOP 
    l_record := j.id || ',' || j.code || ',' || j.desc ....... [others fields]; 
    UTL_FILE.PUT_LINE(l_file,l_record); 
    END LOOP; 

    UTL_FILE.FCLOSE(l_file); 
    UPDATE PRODUCTS SET HANDLE = '1' WHERE HANDLE = '0'; 

    EXCEPTION 
    WHEN OTHERS THEN 
    -- log 
    RAISE; 
    END export_t1; 

だから私はexport_t1、export_t2、export_tn手順を持っています。さらに、私はこれらを「メイン」プロシージャーと呼びます。

私の質問は2番目の プロシージャーであるexport_t2に例外があります。どのようにして最初のブロック(export_t1)を作成するかをブロックすることができますこれらのすべての手順がOKなくなっているだけで、ファイル

アイデアis..createファイル、例外なく

答えて

2

ファイルシステムを2フェーズコミットに参加させることができない限り(これは私の知るところでは不可能です)、ファイル操作をデータベーストランザクションと調整することは、ファイル操作が外部にあるため困難になりますデータベーストランザクションのスコープ

つまり、何かが間違った時刻に起こり、データベースとファイルシステムが同期していないという理論的なシナリオがあります。 (一種のものは、すべてCOMMITが私たちのためにしてくれたことに感謝します)。

とにかく、何かが間違っているためにウィンドウができるだけ短くなるように物事を設計することが考えられます。たとえば、

begin 
    delete_real_files; -- delete leftovers. 
    write_temp_file_n1; 
    write_temp_file_n2; 
    write_temp_file_n3; 
    ... 
    write_temp_file_nx; 

    rename_temp_files_to_real; 

    commit; 

    -- don't do anything else with the files after this point 

exception 
    when others then 
    remove_real_files; 
    remove_temp_files; 
    rollback; 
end; 

ここでのアイデアは、すべてのファイルを一時ファイルに書き込むことです。障害が発生した場合は、それらをクリーンアップします。プロセスを作成したことがないため、「実」ファイルをプロセスで見ることはできませんでした。最後には、テンポラリファイルを名前を変更して実際に作成します。

ここでは、最初のいくつかの一時ファイルの名前が変更されますが、後続の一時ファイルの名前が変更されず、(A)プロセスがジャンプして例外ハンドラを削除する前にプロセスを表示するか、例外ハンドラは何らかの理由でそれらを削除できません。

私はこのアプローチが好きです。これはファイルの名前を変更するリスクがあるためです(余分なディスクスペースを必要としないため)。名前の変更の一部が成功し、失敗する可能性はほとんどありません。

このアプローチのバリエーションはたくさんあります。しかし、覚えておくべきことは、ここでは堅実なソリューションを実装していないことです。何かが間違っている可能性が常にあるので、フォールトトレランスの程度に応じて、(システム内の他の場所に)何らかのチェックが必要なものを実装してください。

+0

こんにちは、私は状況 を最小限にするために持っているので、何かがhappen..Iがすべてを扱うことができない可能性が事実途中、私はいくつかのアイデアを得ました –

0

UTL_FILE.FCLOSE(またはUTL_FILE.FFLUSH)は文字通りディスクに書き込みます。ディスクに書き込まない場合は、ディスクに書き込まないでください。すべてのデータが個々のバッファに書き込まれるまで、ファイルハンドラを閉じたりフラッシュしたりしないでください。

どれくらい大きいかによっては、nの場合は、多くのデータをバッファリングして開いているファイルハンドラがたくさんある可能性があります。これはきれいではありません。

UTL_FILE.FREMOVEを呼び出す別のプロシージャを作成すると、名前付きファイルが削除される(十分な権限があると仮定します)。

Oracle schedulerでこれを実行していますが、それぞれの手順がdefine a rulescheduler chain condition syntaxを使用してチェーン内のエラーでファイルを削除することができます。

0

マイケル、

あなたはおそらく使用することができます - > utl_file.fremove(DIRECTORY_PATH、ファイル名);例外でファイルを削除します。

コード例を以下に示します。

手順1:

CREATE OR REPLACE PROCEDURE SHAREFLE IS 
v_MyFileHandle UTL_FILE.FILE_TYPE; 
BEGIN 
v_MyFileHandle := UTL_FILE.FOPEN('TEST_DIR','HELLO.TXT','a'); 
UTL_FILE.PUT_LINE(v_MyFileHandle, 'Hello Again for the Second Time! ' ||  
TO_CHAR(SYSDATE,'MM-DD-YY HH:MI:SS AM')); 
UTL_FILE.FCLOSE(v_MyFileHandle); 
SHAREFLE1; 
EXCEPTION 
WHEN OTHERS THEN 
DBMS_OUTPUT.PUT_LINE 
('ERROR ' || TO_CHAR(SQLCODE) || SQLERRM); 
NULL; 
END; 

手順2:最初のプロシージャを呼び出す

CREATE OR REPLACE PROCEDURE SHAREFLE1 IS 
v_MyFileHandle UTL_FILE.FILE_TYPE; 
BEGIN 
v_MyFileHandle := UTL_FILE.FOPEN('TEST_DIR','HELLO.TXT','a'); 
    UTL_FILE.PUT_LINE(v_MyFileHandle, 'Hello Again for the Third Time! ' || TO_CHAR(SYSDATE,'MM-DD-YY HH:MI:SS AM')); 
    UTL_FILE.FCLOSE(v_MyFileHandle); 
    EXCEPTION 
    WHEN OTHERS THEN 
    DBMS_OUTPUT.PUT_LINE 
    ('ERROR ' || TO_CHAR(SQLCODE) || SQLERRM); 
    utl_file.fremove('TEST_DIR','HELLO.TXT'); 
    NULL; 
    END; 

PLSQLブロック。

set serveroutput on; 
begin 
sharefle; 
end; 

このコードは、あなたが尋ねたもののかなり単純な例です。例外がある場合は、例外ブロックでファイル 'HELLO.TXT'が削除されていることを手順2で確認できます(手順1と手順2の両方に同じファイルがあります)。私は個人的にそれをチェックし、同じものが働いています。独自の例外を作成して自分で確認してください。ご不明な点がございましたら、ご意見ください。

注:これは決して最良の方法です。私はこのようにすることができることをあなたに示しました。 );答えてくれてありがとう感謝:)

関連する問題