首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 更多程式設計知識

Java 執行 SQL 腳本 .bat 檔案:Runtime.exec 完整範例與同步等待、退出碼判斷

     編輯:更多程式設計知識

Java 應用常需呼叫外部批次檔執行資料庫維護腳本 (如 SQL*Plus 執行 .sql)。本文提供完整範例:Runtime.getRuntime().exec() 呼叫 cmd.exe /C start /b 背景執行 .bat、waitFor() 同步阻塞、exitValue() 判斷成敗、異常處理與日誌輸出。

檔案結構


D:\sqlplus\
├── test.sql      -- SQL 腳本
└── sql.bat       -- 批次啟動器

SQL 腳本 test.sql


insert into ss values(11);
insert into ss values(12);
insert into ss values(13);
commit;
exit;

批次檔 sql.bat


@ECHO OFF
sqlplus -s username/password@sid @D:\sqlplus\test.sql
exit
  • -s:靜默模式 (隱藏版權資訊)。
  • @:指定腳本檔路徑。
  • 需確保 sqlplus 在系統 PATH 中,或使用完整路徑。

Java 完整程式碼


package com.tdxx.sqlplus;

import java.io.IOException;

public class ExecComm {
    public static void main(String[] args) {
        System.out.println("開始執行.");
        runBat();
    }

    public static void runBat() {
        Runtime rt = Runtime.getRuntime();
        Process ps = null;
        try {
            // cmd.exe /C 執行命令後結束
            // start /b 不開新視窗、背景執行
            ps = rt.exec("cmd.exe /C start /b D:\\sqlplus\\sql.bat");
            ps.waitFor();  // 同步等待結束
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();  // 重設中斷旗標
        } catch (IOException e) {
            e.printStackTrace();
        }

        int exitCode = ps.exitValue();  // 非零即異常
        if (exitCode == 0) {
            System.out.println("執行完成.");
        } else {
            System.err.println("執行失敗,退出碼: " + exitCode);
        }
    }
}

關鍵 API 解析

進階改良:擷取輸出與超時控制 (Java 8+)


ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", "D:\\sqlplus\\sql.bat");
pb.redirectErrorStream(true);  // 合併 stderr 到 stdout
Process ps = pb.start();

// 非同步讀取輸出避免緩衝區滿死鎖
new Thread(() -> {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()))) {
        String line;
        while ((line = br.readLine()) != null) System.out.println("[BAT] " + line);
    } catch (IOException e) { e.printStackTrace(); }
}).start();

// Java 8: waitFor(long, TimeUnit) 支援超時
boolean finished = ps.waitFor(60, TimeUnit.SECONDS);
if (!finished) {
    ps.destroyForcibly();
    System.err.println("執行超時,強制終止");
}
int code = ps.exitValue();

常見坑與對策

方法用途
Runtime.exec(String)啟動子進程,回傳 Process 控制代碼
Process.waitFor()阻塞當前執行緒直到子進程終止
Process.exitValue()取得退出碼 (0=成功),若進程未結束拋 IllegalThreadStateException
Process.getInputStream()讀取子進程標準輸出 (若需擷取輸出)
Process.getErrorStream()讀取子進程標準錯誤

安全性提醒

  • 避免在命令字串中拼接未驗證的使用者輸入 (命令注入風險)。
  • 優先使用 ProcessBuilder 陣列形式傳參,自動處理引號跳脫。
  • 生產環境考慮改用 JDBC 直接執行 SQL,減少外部相依與部署複雜度。

掌握 Runtime.exec / ProcessBuilder 正確用法,即能穩健整合外部腳本與工具。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
現象原因解決
程式卡住不返回子進程輸出緩衝區滿,未讀取必須非同步讀取 getInputStream()/getErrorStream(),或用 ProcessBuilder.redirectErrorStream(true)
找不到 sqlplusPATH 未包含 Oracle Client bin 目錄批次檔使用完整路徑 D:\oracle\bin\sqlplus.exe
退出碼永遠為 0批次檔未正確傳遞 sqlplus 退出碼批次檔末尾加 exit /b %ERRORLEVEL%
中文亂碼主控台編碼與 Java 預設編碼不符new InputStreamReader(is, "MS950") (繁中) 或 GBK (簡中)