运行 SQL PostgreSQL 脚本,提供密码

Run SQL script on PostgreSQL with password supplied

我正在尝试从我的 Java 应用程序中 运行 一个 SQL 脚本。这是我的代码:

Runtime rt = Runtime.getRuntime();
rt.exec("setx PGPASSWORD \"" + password + "\"");
String command = String.format("psql -d %s -h %s -p %s -U %s -w -f %s",
        database, host, port, user, "create_tables.sql");
System.out.println("Executing command " + command);
Process p = rt.exec(String.format(command));
p.waitFor();

这会打印

psql -d routes -h localhost -p 5432 -U postgres -w -f create_tables.sql

符合预期。

但是在我的数据库日志中,我看到以下内容:

psql: fe_sendauth: no password supplied

如何将密码提供给 psql 作为进程调用它?

您的环境变量应在执行 psql 的同一进程中设置。当您执行两个不同的进程时,这不会发生在您的代码中。

问题是,环境变量对于进程上下文是本地的。

一个新进程获得了 parent 环境的副本,但每个副本都是独立的。 在您的情况下,Java 进程创建了 child 进程,该进程通过 setx 命令修改了 PGPASSWORD - 到目前为止一切顺利。

但是,这不会影响 Java 进程。您的第二个 child 进程未 运行 在 shell 中,因此它忽略了 PGPASSWORD 变量,因为该进程是使用 OS 服务创建的。这些服务,考虑到 Java 进程的旧上下文,它不知道 PGPASSWORD,除非你在启动原始(parent 之前更改 shell 中的环境) Java 进程。

因此,要解决您的问题,您必须设置环境变量,然后 运行 将 child 作为 shell 命令 (cmd /c)。 要设置环境变量,我们可以遵循@Little Santi 的建议。

所以代码看起来像下面这样

Runtime rt = Runtime.getRuntime();
String setCommand="PGPASSWORD=" + password;

String command = String.format("psql -d %s -h %s -p %s -U %s -w -f %s", 
        database, host, port, user, "create_tables.sql");

String finalCommand = "cmd /c \" " + command +"\"";
System.out.println("Executing command " + finalCommand);

Process p = rt.exec(finalCommand ,new String[]{setCommand});
p.waitFor();

编辑 2:

@Plirkee 的诊断是正确的:您启动 psql 的过程缺少所需的环境变量。但要正确设置它,最好使用 Runtime.exec(String[] cmdarray, String[] envp) 方法。