Oracle 创建文件的回滚过程

Oracle 创建文件的回滚过程,oracle,plsql,export,procedure,Oracle,Plsql,Export,Procedure,我有几个PL/SQL过程,它们使用UTL_文件导出文件中的表 这里有一个快照: 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 WHER

我有几个PL/SQL过程,它们使用UTL_文件导出文件中的表

这里有一个快照:

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;
所以我有导出t1,导出t2,导出tn程序。此外,我在“main”过程中按顺序调用这些函数

我的问题是……如果我在export_t2中有一个异常,那是第二个 过程中,如何阻止第一个(export_t1)来创建文件

其想法是..在所有程序都完成后创建文件,没有例外

(或
UTL_FILE.FFLUSH
)会直接写入磁盘。如果不想写入磁盘,则不能写入磁盘-在所有数据写入每个缓冲区之前,不要关闭或刷新文件处理程序

根据n的大小,您可能会有许多具有大量缓冲数据的开放文件处理程序。这可不好看

最好创建另一个要调用的过程,该过程将删除一个命名文件(假设有足够的权限)

我将在中这样做,因为每个过程都是链中的一个单独步骤,您可以使用调用该过程来删除te链中错误的文件。

(或
UTL\u FILE.FFLUSH
)直接写入磁盘。如果不想写入磁盘,则不能写入磁盘-在所有数据写入每个缓冲区之前,不要关闭或刷新文件处理程序

根据n的大小,您可能会有许多具有大量缓冲数据的开放文件处理程序。这可不好看

最好创建另一个要调用的过程,该过程将删除一个命名文件(假设有足够的权限)


我将在中这样做,因为每个过程都是链中的一个单独步骤,所以您可以使用调用该过程来删除te链中错误上的文件。

除非您可以让文件系统参与两阶段提交(据我所知,这目前是不可能的),将文件输出与数据库事务协调起来将很困难,因为文件操作超出了数据库事务的范围

也就是说,总有一种理论上的情况,即某些事情在错误的时间发生,而您的数据库和文件系统不同步。(有点让你感激
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)进程在异常处理程序删除它们之前跳入并看到它们,或者(B)异常处理程序由于某种原因无法删除它们

我喜欢这种方法,因为它将所有风险与重命名文件联系在一起,这是一种非常安全的操作(因为它不需要额外的磁盘空间)。有些重命名成功,有些重命名失败的可能性不大


这种方法可能会有很多变化。但要记住的是,你没有在这里实现一个坚如磐石的解决方案。总是有可能出现问题,因此根据您的容错能力,实施所需的任何检查(系统中的其他地方)。

除非您可以让文件系统参与两阶段提交(据我所知,目前不可能),将文件输出与数据库事务协调起来将很困难,因为文件操作超出了数据库事务的范围

也就是说,总有一种理论上的情况,即某些事情在错误的时间发生,而您的数据库和文件系统不同步。(有点让你感激
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)进程在异常处理程序删除它们之前跳入并看到它们,或者(B)异常处理程序由于某种原因无法删除它们

我喜欢这种方法,因为它将所有风险与重命名文件联系在一起,这是一种非常安全的操作(因为它不需要额外的磁盘空间)。有些重命名成功,有些重命名失败的可能性不大

这种方法可能会有很多变化。但要记住的是,你没有在这里实现一个坚如磐石的解决方案。总是有可能出现问题,因此根据您的容错能力,实施所需的任何检查(系统中的其他地方)。

Michael

您可能可以使用-->utl_file.fremove(目录路径,文件名);在异常中删除该文件

下面给出了示例代码

程序1: 程序2: Plsql块调用第一个过程。 这段代码是您所问问题的一个非常简单的示例。如果存在任何异常,您可以检查过程2,确保在异常块中删除了文件“HELLO.TXT”(过程1和过程2都有相同的文件)。我已经亲自检查过了,同样有效。尝试创建自己的异常并自己检查。如有任何疑问,请发表评论

注意:这永远不是B
 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; 
set serveroutput on;
begin
sharefle;
end;