首页 > 解决方案 > 如何在 Java 中在一个命令中为 Windows 执行多个命令和 psql 查询?

问题描述

我正在用 Java 编写一些代码来自动从云中恢复备份。为此,我需要从 Windows 的(CMD)命令行工具中打开 psql,终止连接,退出 psql 并删除数据库,以便 Java 可以一次执行。这些分别是单独的步骤(我认为);

psql -h localhost -p 5433 -U postgres -w OC_A -c '
SELECT 
    pg_terminate_backend(pid) 
FROM 
    pg_stat_activity 
WHERE 
pid <> pg_backend_pid();
/q postgres-# \q ;'
dropdb -h localhost -p 5433 -U postgres -w OC_A

我已将这些步骤放入一个 cmd 命令中,例如;



// 2 - terminate db connections, delete based on config db's
String terminateSQLconnecitons= "\npsql -h "+ postgresHost + " -p " + postgresPort + " -U " + postgresUsername + " -w " + postgresDbname + " -c "+
"\'\nSELECT pg_terminate_backend(pid)  FROM pg_stat_activity  WHERE  pid <> pg_backend_pid();\n/q postgres-# \\q ;'" ;
int terminateSQLconnecitonsResult = cmdExe(terminateSQLconnecitons);
if (terminateSQLconnecitonsResult == 0) {
    System.out.println("Connections terminated");
} else {
    System.out.println("CONNECTIONS NOT TERMINATED");
}

public static int cmdExe(String cmd) {
    ProcessBuilder processBuilder = new ProcessBuilder();
    processBuilder.redirectErrorStream(true);
    processBuilder.command("cmd.exe", "/c", cmd);
    System.out.println(cmd);
    int exitCode = -1;

    try {
        Process process = processBuilder.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
        }
        exitCode = process.waitFor();
        System.out.println("Result :" + exitCode);

    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return exitCode;
}

在 Java 中的一个命令中执行这些步骤需要更改哪里/什么?

编辑1;我现在已经有单独的步骤,但似乎不起作用..我不明白为什么。

                    // 2 - terminate db connections, delete based on config db's
                    String terminateSQLconnecitons= "\npsql -h "+ postgresHost + " -p " + postgresPort + " -U " + postgresUsername + " -w " + postgresDbname + " -c "+
                    "\'\nSELECT pg_terminate_backend(pid)  FROM pg_stat_activity  WHERE  pid <> pg_backend_pid();\n/q postgres-# \\q ;'" ;
                     int terminateSQLconnecitonsResult = cmdExe(terminateSQLconnecitons);
                     if (terminateSQLconnecitonsResult == 0) {
                        System.out.println("Connections terminated");
                    } else {
                        System.out.println("CONNECTIONS NOT TERMINATED");
                    }

                    String DeleteCMD= "\ndropdb -h "+ postgresHost + " -p " + postgresPort + " -U " + postgresUsername + " -w " + postgresDbname;
                    int cmdResult = cmdExe(DeleteCMD);
                    if (cmdResult == 0) {
                            System.out.println("Database " + postgresDbname + " deleted");
                        } else {
                            System.out.println("Database " + postgresDbname + " NOT deleted");
                        }

标签: javawindowspostgresql

解决方案


通过将所有内容放入单个 SQL 脚本中,您可以大大简化所有操作。要运行脚本,请连接到不同的数据库,例如template1.

-- prevent new connections between the moment you killed everything 
-- and the moment where the database is dropped    
alter database your_db_name allow_connections false;

select pg_terminate_backend(pid)
from pg_stat_activity
where datname = 'your_db_name'
  and pid <> pg_backend_pid();

drop database your_db_name;

并不是真正需要的and pid <> ...,因为该脚本没有连接到要删除的数据库,因此目标数据库上的 where 子句已经删除了您的“自己的”会话。

然后,您只需要运行psql一次(而不是其他命令行工具)传递该脚本,方法是将上述内容写入临时文件并使用-f参数,或者将所有内容作为单个命令传递使用-c

psql -c "alter database your_db_name allow_connections false; select ... where ...; drop database your_db_name"

然而,我认为通过 JDBC 来做这件事Statement.execute()是一个更好的解决方案,它试图与 ProcessBuilder 抗争(它的代码少得多,问题少得多,而且更容易控制)。


推荐阅读