oracle spool 脚本在 cmd.exe 中工作,但在从代码调用时挂起

Posted

技术标签:

【中文标题】oracle spool 脚本在 cmd.exe 中工作,但在从代码调用时挂起【英文标题】:oracle spool script works in cmd.exe, but hangs when called from code 【发布时间】:2021-04-13 08:09:12 【问题描述】:

我正在尝试使用 Oracle 的SQLcl 以编程方式创建 Oracle 数据转储文件。脚本如下:

SET SQLFORMAT XML

SPOOL 'ABC.XML'
SELECT * FROM ABC;
SPOOL OFF

SPOOL 'XYZ.XML'
SELECT * FROM XYZ;
SPOOL OFF

//MORE TABLES BELOW

命令如下:

exit | "path\to\sqlcl\folder\bin\sql.exe" username/password@connection_string @"path\to\data\dump\script\datadumpscript.sql"

通过在CMD(windows 10)中执行命令,它工作得很好。

代码执行逻辑来自this thread,转换为vb.net:

Private Shared Sub ExecuteCommand(ByVal command As String)
    Dim exitCode As Integer
    Dim processInfo As ProcessStartInfo
    Dim process As Process
    processInfo = New ProcessStartInfo("cmd.exe", "/c """ & command & """")
    processInfo.CreateNoWindow = True
    processInfo.UseShellExecute = False
    processInfo.RedirectStandardError = True
    processInfo.RedirectStandardOutput = True
    process = Process.Start(processInfo)
    process.WaitForExit()
    Dim output As String = process.StandardOutput.ReadToEnd()
    Dim [error] As String = process.StandardError.ReadToEnd()
    exitCode = process.ExitCode
    System.Diagnostics.Debug.WriteLine("output>>" & (If(String.IsNullOrEmpty(output), "(none)", output)))
    System.Diagnostics.Debug.WriteLine("error>>" & (If(String.IsNullOrEmpty([error]), "(none)", [error])))
    System.Diagnostics.Debug.WriteLine("ExitCode: " & exitCode.ToString(), "ExecuteCommand")
    process.Close()
End Sub

当从代码调用时,通过传入上面的命令,程序确实会转到“process.WaitForExit()”并阻塞,但只有 spool 脚本中的第一个文件被创建,大小为 0,文件被锁定通过 JAVA 二进制文件,之后没有任何反应。导出过程似乎没有运行。

感谢任何建议。谢谢。

【问题讨论】:

您可以尝试您链接的线程中提到的异步日志记录选项吗?或尝试WriteLine(processInfo.Arguments) 以确保引用正常... 您是管理员吗? VS 不会默认为管理员权限。如果您在 VS 中运行,则必须右键单击 VS 快捷方式并选择以管理员身份运行。 【参考方案1】:

调整参数后,我发现当设置processInfo.UseShellExecute = True 修复了无法运行的问题。但是,即使使用processInfo.CreateNoWindow = True,也会显示控制台窗口。

我正在寻找一种方法来隐藏控制台窗口,但如果我不能,它仍然可以接受。

【讨论】:

【参考方案2】:

创建一个使用 UTL_FILE 实用程序将数据从表转储到文件的存储过程/匿名 PL/SQL 块将是另一种选择。下面的脚本是从表的一列中提取数据的基本脚本,但是可以扩展到多于一列或所有列。

DECLARE
  fhandle  utl_file.file_type;

BEGIN 

// File1
 BEGIN
  fhandle := utl_file.fopen(
                '/user/home'     -- Folder location or an Oracle directory
               , 'filename1.XML' -- File name
               , 'w' -- writemode Mode 
                  );
 
   FOR V1 IN (Select colA from TableA)
   LOOP 
    utl_file.put_line(fhandle, v1.COLA);
   END LOOP;
   utl_file.fclose(fhandle);
 exception
  when others then
    dbms_output.put_line('ERROR: ' || SQLCODE 
                      || ' - ' || SQLERRM);
    raise;
 end;

// File 2
BEGIN

  fhandle := utl_file.fopen(
                '/user/home'     -- Folder location or an Oracle directory
               , 'filename2.XML' -- File name
               , 'w' -- Write Mode 
                  );
 
   FOR V1 IN (Select colA from TableA)
   LOOP 
    utl_file.put_line(fhandle,v1.COLA);
   END LOOP;
   utl_file.fclose(fhandle);
 exception
  when others then
    dbms_output.put_line('ERROR: ' || SQLCODE 
                      || ' - ' || SQLERRM);
    raise;
 end;

END;

【讨论】:

以上是关于oracle spool 脚本在 cmd.exe 中工作,但在从代码调用时挂起的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Oracle APEX 中设置 SPOOL 脚本以将视图数据导出为 CSV?

Linux sh脚本用spool导出oracle数据库指定表表数据

SPOOL 命令使用实例oracle导出纯文本格式文件

zabbix 使用spool监控oracle锁表

oracle数据量巨大表查询时间太长,sqlplus有的不能spool出结果

如何找出CMD.exe进程在远程计算机上运行的脚本?