Oracle 資料庫內建 JVM (Aurora),允許將 Java 類別載入資料庫,並透過 Callable Specification (Call Spec) 發佈為 PL/SQL 可呼叫的存儲過程/函數。流程三步驟:
CREATE JAVA SOURCE)。CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "TransMetaData" AS
import java.io.*;
import java.sql.*;
import java.util.Properties;
import oracle.jdbc.driver.OracleDriver;
public class TransMetaData {
public static void donow(String str)
throws FileNotFoundException, IOException, SQLException, UnsupportedEncodingException {
str = "_" + str;
Properties props = new Properties();
props.load(new FileInputStream("c:/tables.properties"));
String srcUrl = props.getProperty("DATABAST_SOURCE_URL" + str);
String srcUser = props.getProperty("DATABAST_SOURCE_USERNAME" + str);
String srcPwd = props.getProperty("DATABAST_SOURCE_PASSWORD" + str);
String tgtUrl = props.getProperty("DATABAST_TARGET_URL" + str);
String tgtUser = props.getProperty("DATABAST_TARGET_USERNAME" + str);
String tgtPwd = props.getProperty("DATABAST_TARGET_PASSWORD" + str);
String srcTable = props.getProperty("SQL_SOURCE_TABLENAME" + str);
String tgtTable = props.getProperty("SQL_TARGET_TABLENAME" + str);
String fields = props.getProperty("SQL_TABLE_FIELD" + str);
Connection srcConn = null, tgtConn = null;
DriverManager.registerDriver(new OracleDriver());
srcConn = DriverManager.getConnection(srcUrl, srcUser, srcPwd);
tgtConn = DriverManager.getConnection(tgtUrl, tgtUser, tgtPwd);
if (!srcConn.isClosed() && !tgtConn.isClosed()) {
System.out.println("**源與目的資料庫連線成功**");
srcConn.setAutoCommit(false);
tgtConn.setAutoCommit(false);
} else {
throw new Exception("資料庫連線失敗,請檢查!");
}
PreparedStatement pstmt = srcConn.prepareStatement("SELECT " + fields + " FROM " + srcTable);
ResultSet rs = pstmt.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int cols = rsmd.getColumnCount();
String[] data = new String[cols];
String placeholders = "";
PreparedStatement delStmt = tgtConn.prepareStatement("DELETE FROM " + tgtTable);
delStmt.executeUpdate();
delStmt.close();
while (rs.next()) {
placeholders = "";
for (int i = 0; i < cols; i++) {
String val = rs.getString(i + 1);
data[i] = (val != null) ? new String(val.trim().getBytes("ISO-8859-1"), "GBK") : "";
placeholders += (i != cols - 1) ? "?," : "?";
}
String insSql = "INSERT INTO " + tgtTable + " (" + fields + ") VALUES (" + placeholders + ")";
PreparedStatement insStmt = tgtConn.prepareStatement(insSql);
for (int i = 0; i < cols; i++) insStmt.setString(i + 1, data[i]);
insStmt.executeUpdate();
insStmt.close();
}
srcConn.commit();
tgtConn.commit();
System.out.println("**資料遷移完成**");
}
}
/
限制:方法必須為 static;不寫套件名;參數/回傳型別需與 PL/SQL 映射對應。
CREATE OR REPLACE PROCEDURE TransMetaData
AS LANGUAGE JAVA
NAME 'TransMetaData.donow()';
/
CREATE OR REPLACE PROCEDURE TransMetaData(p_str IN VARCHAR2)
AS LANGUAGE JAVA
NAME 'TransMetaData.donow(java.lang.String)';
/
CREATE OR REPLACE FUNCTION TransMetaData(p_str IN VARCHAR2) RETURN NUMBER
AS LANGUAGE JAVA
NAME 'TransMetaData.donow(java.lang.String) return double';
/
-- 無參數
EXEC TransMetaData;
-- 帶參數
EXEC TransMetaData('1');
-- 函數呼叫
DECLARE v_result NUMBER;
BEGIN
v_result := TransMetaData('1');
DBMS_OUTPUT.PUT_LINE(v_result);
END;
/
CREATE OR REPLACE JAVA SOURCE NAMED JS_Rand AS
public class clsRand {
public static double Rand() { return java.lang.Math.random(); }
}
/
CREATE OR REPLACE FUNCTION rand RETURN NUMBER
AS LANGUAGE JAVA
NAME 'clsRand.Rand() return double';
/
BEGIN
DBMS_OUTPUT.PUT_LINE(rand);
END;
/
c:/tables.properties) 是資料庫伺服器端路徑,非客戶端。ISO-8859-1 → GBK) 需視實際字元集調整。GRANT JAVASYSPRIV、檔案讀寫權限 (SYS.DBMS_JAVA.GRANT_PERMISSION)。System.out.println 輸出導向資料庫 Trace 檔,可用 DBMS_JAVA.SET_OUTPUT 導向 PL/SQL 緩衝區。PL/SQL 呼叫 Java 能將複雜邏輯(檔案處理、網路通訊、加密演算等)移至 Java 實作,再透過資料庫原生介面整合,發揮兩者優勢。