我需要创建一个接收方法(databaseIp,databaseName,端口,用户,密码,filePath)。这个想法是在终端这样的数据库中导入一个sql文件:
psql -h databaseIp -p port -U user -d databaseName
Password for user postgres: password
databaseName=# \\i filePath
databaseName=# \\q
我使用以下方法将命令发送到终端
public static String execute(String command) {
StringBuilder sb = new StringBuilder();
String[] commands = new String[]{"/bin/sh", "-c", command};
try {
Process proc = new ProcessBuilder(commands).start();
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
sb.append(s);
sb.append("\n");
}
while ((s = stdError.readLine()) != null) {
sb.append(s);
sb.append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
但是它看到它一次只发送一个命令,并且当psql要求输入密码时,给出的结果不正确。如何使用Java将相关命令发送到终端?
最佳答案
gh,你为什么要这么做?
使用PgJDBC从Java与PostgreSQL通信。
如果确实必须调用psql
,请说是否要采购使用\
命令的SQL文件,build a command with ProcessBuilder
并以批处理方式非交互地调用psql
。您可以提示用户输入密码,然后将其传递给psql
环境变量中的PGPASSWORD
,因此您无需与进程进行交互,只需启动它并等待其终止即可。
像(未经测试的)之类的东西:
cmd = new List<String>();
cmd.add(path_to_psql);
cmd.add("-q"); // Quiet mode
cmd.add("-w"); // no password prompt
cmd.add("-X"); // ignore any user psqlrc
cmd.add("-1"); // Run in a single transaction
cmd.add("-v"); // Set a variable as follows:
cmd.add("ON_ERROR_STOP=1"); // If anything goes wrong, abort the whole job
cmd.add("-f"); // input file is:
cmd.add(input_file_path);
if (username_arg != null) {
cmd.add("-U");
cmd.add(username_arg);
}
// and so on for database name, etc, then:
ProcessBuilder pb = new ProcessBuilder(cmd);
Map<String, String> env = pb.environment();
if (psql_password != null) {
// User supplied a password
env.put("PGPASSWORD", psql_password);
}
// ... blah blah, the usual execute it, wait for it to finish,
// check return value, etc.
如果
psql
首次连接失败,错误代码为2,则可以提示用户输入密码并重试。不幸的是,错误代码2不是很具体。它还将返回与无效主机名等相关的错误,因此,您可能希望捕获psql
的stderr并将其与提示一起显示给用户。