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