UNIX/Linux 可用 mkfifo 建立命名管道,配合 DB2 LOAD 實現無中間檔案載入。但 Windows 原生不支援 mkfifo,需呼叫 Windows API 建立命名管道,且管道生命週期限於建立會話;Java 建立的管道無法與 Windows Shell 互通,導致 DB2 LOAD 無法直接使用。
本文提供完整 JNI 包裝方案:C 程式呼叫 Windows API 建立/讀寫管道,Java 透過 JNI 驅動資料流向管道,DB2 LOAD 從管道讀取並載入。
TestPipe.java / TestUnixPipe.java):產生資料寫入管道Pipes.java + Pipe.c):對應 Windows API (CreateNamedPipe, ReadFile, WriteFile, CloseHandle 等)db2load.sql):指定管道路徑作為輸入源IBM Data Movement Tool 內建管道選項,若無客製化需求可直接使用。
| 功能 | Windows API | JNI 方法 |
|---|---|---|
| 建立管道 | CreateNamedPipe | CreateNamedPipe |
| 等待連線 | ConnectNamedPipe | ConnectNamedPipe |
| 寫入資料 | WriteFile | WriteFile |
| 讀取資料 | ReadFile | ReadFile |
| 刷新緩衝 | FlushFileBuffers | FlushFileBuffers |
| 斷開/關閉 | DisconnectNamedPipe / CloseHandle | DisconnectNamedPipe / CloseHandle |
Pipes.java)public class Pipes {
static { System.loadLibrary("Pipe"); }
public static final native int CreateNamedPipe(String pipeName, int openMode, int pipeMode, int maxInstances, int outBufferSize, int inBufferSize, int defaultTimeOut, int securityAttributes);
public static final native boolean ConnectNamedPipe(int namedPipeHandle, int overlapped);
public static final native int GetLastError();
public static final native boolean CloseHandle(int object);
public static final native byte[] ReadFile(int file, int numberOfBytesToRead);
public static final native int WriteFile(int file, byte[] buffer, int numberOfBytesToWrite);
public static final native boolean FlushFileBuffers(int file);
public static final native boolean DisconnectNamedPipe(int namedPipeHandle);
public static final native int CreateFile(String fileName, int desiredAccess, int shareMode, int securityAttributes, int creationDisposition, int flagsAndAttributes, int templateFile);
public static final native boolean WaitNamedPipe(String namedPipeName, int timeOut);
public static final native String FormatMessage(int errorCode);
public static final native void Print(String message);
}
javac ibm/Pipes.java
javah -jni ibm.Pipes # 產生 ibm_Pipes.h,複製至 C 專案目錄
Pipe.c 節錄)JNIEXPORT jint JNICALL Java_ibm_Pipes_CreateNamedPipe(JNIEnv *env, jclass cls, JString sPipeName, jint dwOpenMode, jint dwPipeMode, jint nMaxInstances, jint nOutBufferSize, jint nInBufferSize, jint nDefaultTimeOut, jint lpSecurityAttributes) {
LPCSTR pipeName = (*env)->GetStringUTFChars(env, sPipeName, NULL);
HANDLE h = CreateNamedPipe(pipeName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, (LPSECURITY_ATTRIBUTES)lpSecurityAttributes);
(*env)->ReleaseStringUTFChars(env, sPipeName, pipeName);
return (jint)h;
}
// ... 其他方法對應 ReadFile, WriteFile, CloseHandle 等
cl -I"C:\Program Files\IBM\Java50\include" -I"C:\Program Files\IBM\Java50\include\win32" -LD Pipe.c -FePipe.dll
TestPipe.java 關鍵邏輯)private boolean createPipe() {
namedPipeHandle = Pipes.CreateNamedPipe(pipeName, 0x00000003, 0x00000000, 2, pipeBuffer, pipeBuffer, 0xffffffff, 0);
return namedPipeHandle != -1;
}
private boolean connectToPipe() {
boolean connected = Pipes.ConnectNamedPipe(namedPipeHandle, 0);
if (!connected && Pipes.GetLastError() == 535) connected = true; // ERROR_PIPE_CONNECTED
return connected;
}
public void runPipe() {
if (createPipe() && connectToPipe()) {
FileInputStream in = new FileInputStream(srcFile);
byte[] buf = new byte[fileBuffer];
int len;
while ((len = in.read(buf)) > 0) {
int written = Pipes.WriteFile(namedPipeHandle, buf, len);
if (written == -1) log(Pipes.FormatMessage(Pipes.GetLastError()));
}
in.close();
Pipes.FlushFileBuffers(namedPipeHandle);
Pipes.CloseHandle(namedPipeHandle);
Pipes.DisconnectNamedPipe(namedPipeHandle);
}
}
TestUnixPipe.java)直接呼叫 Runtime.exec("mkfifo " + path),再用 FileChannel 寫入,無需 JNI。
java -Djava.library.path=.. ibm.TestPipe → 建立管道 \\.\pipe\mynamedpipe 並等待連線db2 -tf db2load.sqldb2load.sql 範例:
CONNECT TO SAMPLE;
CREATE TABLE PIPE_TABLE (ID NUMBER(10) NOT NULL, NAME VARCHAR2(35), LOC_ID NUMBER(4));
LOAD FROM "\\.\pipe\mynamedpipe" OF DEL MODIFIED BY CODEPAGE=1208 COLDEL~ ANYORDER USEDEFAULTS CHARDEL"" DELPRIORITYCHAR NOROWWARNINGS METHOD P(1,2,3) MESSAGES "db2tabledata.txt" REPLACE INTO PIPE_TABLE (ID, NAME, LOC_ID) NONRECOVERABLE INDEXING MODE AUTOSELECT;
TERMINATE;


同步機制:Java 端 ConnectNamedPipe 阻塞直到 DB2 LOAD 開啟管道;隨後 Java 串流寫入,DB2 同步消費載入,無臨時檔案產生。

勾選 Use Pipe,工具自動建立管道並同步執行 UNLOAD/LOAD,支援多表並行。
管道載入消除中間檔案空間壓力,發揮 DB2 LOAD 平行處理優勢。Windows 下透過 JNI 呼叫原生 API 即可實現,本文提供完整可編譯執行的範例代碼(見下載區),可直接套用或客製化整合至自動化 ETL 流程。