简体   繁体   中英

How can I execute multiple commands and psql queries in one command for Windows in Java?

I am writing in Java some code to automatically restore a backup from the cloud. Herefor I need to open psql, terminate connections, exit psql and drop database in one command from (CMD) command line tool at Windows, so that Java can execute this in once. Respectively these are the seperate steps (I think);

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

I have put these steps into one single cmd command like;



// 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;
}

Where/what do I need to change to execute these steps in one command in Java?

EDIT 1; I have now already seperate steps but seems not working..I don't get it why.

                    // 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");
                        }

You can simplify all that drastically, by putting everything into a single SQL script. To run the script, connect to a different database, eg 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;

The and pid <> ... isn't really needed as that script does not connect to the database to be dropped, so the where clause on the target database will already remove your "own" session.

Then all you need is to run psql once (and no other command line tool) passing that script, either by writing the above into a temporary file and using the -f parameter or by passing everything as a single command using -c

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

However I think that doing that through JDBC with Statement.execute() is a much better solution that trying to fight ProcessBuilder (it's far less code, far less problems and way easier to control).

What you want is impossible; clearly the reason you want 'one command' is you want this operation to be instantaneous; that there is no time in between force-killing all open PSQL connections and running dropdb. That's not how it works, the shell just executes these commands one after another.

So.. do the same thing: First run the one command (Make a processbuilder as you are doing and run the command; you don't need cmd.exe /c for it either then), then wait for that to complete, then make another processbuilder and run the dropdb command.

Separately, you really don't need processbuilder at all for the first command; you can use JDBC to send that query too. You can also use JDBC to send a DROP DATABASE query, which is what the dropdb command does under the hood. Then there's no need for processbuilder whatsoever.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM