首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

深入掌握 SQLJ:在 Oracle 資料庫中開發可攜式 Java 資料庫應用

     編輯:關於SqlServer

SQLJ 概述

現代企業級應用程式通常部署在多種資料庫平台上,如 Oracle、DB2、Sybase、SQL Server、Informix 等。在這樣的異構環境中,程式碼的可移植性與可維護性變得至關重要。傳統上,各資料庫廠商使用專有的程序語言(Oracle 採用 PL/SQL,Sybase 與 SQL Server 採用 Transact-SQL),導致跨平台遷移極為複雜且耗時。

Java 憑藉其跨平台特性與強大的網路能力,成為開發可移植資料庫應用的理想選擇。Oracle 在 8i 版本中整合了 Java 虛擬機(JVM),稱為 JServer(或 Aurora JVM),支援兩種程式設計模型:

  • SQL 與 Java 整合:允許使用 Java 編寫傳統的資料庫預存程序、函數與觸發器。
  • 企業 JavaBeans (EJB) 事務伺服器平台:支援開發可重複使用的伺服器端應用組件。

在 Oracle 8i 中,Java 可透過內嵌的 JDBC 驅動程式呼叫 SQL 與 PL/SQL;反之,PL/SQL 與 SQL 也能透過 CREATE PROCEDURE AS JAVA 等擴展 DDL 呼叫 Java 程式碼,實現雙向無縫整合。

什麼是 SQLJ?

SQLJ 是一種允許將靜態 SQL 陳述式以文字形式直接嵌入 Java 程式碼的語言。開發人員遵循特定規則編寫 SQLJ 程式,再經由 SQLJ 轉譯器將嵌入式 SQL 轉換為對 SQLJ 執行階段程式庫的呼叫,產出標準的 Java 原始碼,最後由 Java 編譯器編譯為位元組碼。SQLJ 執行階段環境由輕量級的純 Java 程式庫組成,透過相應資料庫的 JDBC 驅動程式與資料庫通訊。

SQLJ 類似於 Oracle Pro*C 等嵌入式 SQL 實作,旨在協助 Java 開發人員建構資料庫應用。它是 ISO 與 ANSI 標準,由 Oracle、IBM、Sybase、Informix 等廠商共同開發支援,確保跨資料庫的相容性。

SQLJ 的主要優勢

  • 程式碼精簡:SQLJ 程式碼比 JDBC 更簡潔、易讀,減少開發與維護成本。
  • 編譯期檢查:SQLJ 轉譯器在編譯階段執行語法、語義、型別與 Schema 物件檢查,及早發現錯誤,提升程式健壯性。
  • 多廠商互操作性:SQLJ 語法由主流廠商支援,且透過 JDBC 存取資料庫,可連線任何支援 JDBC 的資料庫伺服器。
  • 彈性部署:SQLJ 執行階段基於 Java,可在瘦用戶端、中介層或資料庫伺服器上執行。
  • 廠商專屬客製化:透過位元組碼客製化,可利用特定資料庫的效能擴展功能,而不影響 SQLJ 原始碼。

SQLJ 應用程式開發步驟

  1. 使用 SQLJ 編譯器處理 .sqlj 來源檔案,產生 Java 檔案與二進位描述檔(profile)。
  2. 使用 Java 編譯器編譯產生的 Java 程式碼。
  3. 根據目標資料庫特性客製化描述檔。
  4. 使用 SQLJ 執行階段程式庫與特定資料庫的 JDBC 驅動程式執行應用程式。

必要執行環境:SQLJ 執行階段程式庫、JDBC 驅動程式(如 Oracle Thin、OCI、JDBC-ODBC Bridge 等)、JVM。

SQLJ 與 JDBC 的比較

SQLJ 採用靜態 SQL 模型,提供強型別的編譯期檢查,不僅驗證 SQL 語法與主機變數型別相容性,還能根據資料庫 Schema 驗證查詢正確性。相比之下,JDBC 採用動態模型,錯誤往往只在執行時發現。SQLJ 程式碼更為精簡,例如單一 #sql 區塊即可完成查詢與結果綁定,而 JDBC 需準備 PreparedStatement、逐一綁定參數、處理 ResultSet。

SQLJ 程式可與 JDBC 程式碼在同一來源檔中互操作,支援動態 SQL 需求;Oracle 9i 更直接在 SQLJ 中支援動態 SQL。

Java (SQLJ/JDBC) 與 PL/SQL 的比較

Java 與 PL/SQL 互補而非互斥。Java 儲存程序在數學運算密集型任務上快 5 到 100 倍,且具跨平台可移植性;PL/SQL 則與 Oracle 核心緊密整合,資料型別無需轉換,在 OLTP 與批次處理上分別快 1.5 倍與 2.5 倍,且佔用較少 CPU 資源。

最佳實務:Oracle 提供理想環境結合兩者優勢。PL/SQL 可呼叫 SQLJ/JDBC 程序構建 EJB/CORBA 應用;Java 可透過 JDBC/SQLJ 呼叫 PL/SQL 程序、函數與匿名區塊。例如:

// 呼叫預存程序
#sql { CALL UpdateSalary };

// 呼叫函數
String name;
#sql { name = { VALUES GetName() } };
// 或
#sql { SET :name = GetName() };

// 匿名 PL/SQL 區塊
#sql { BEGIN ... END; };

SQLJ 語言核心元素

連線上下文

用於管理資料庫連線。單一連線可使用 DefaultContext 實例,透過 Oracle.connect() 建立;多重連線則使用 Oracle.getConnection() 建立多個 DefaultContext 實例,並在 SQLJ 陳述式中指定上下文:#sql [myContext] { SQL statement };。程式結束時應在 finally 區塊中提交交易並關閉連線。

迭代器

SQL 查詢結果集以迭代器物件儲存,概念類似 PL/SQL 游標。使用步驟:宣告迭代器類別 → 宣告迭代器物件 → 以 SELECT 陳述式填入資料 → 循環讀取資料 → 關閉迭代器。兩種類型:

  • 具名迭代器:指定欄位名稱與 Java 型別,透過存取器方法(如 empIterator.Ename())讀取資料。
  • 位置迭代器:僅指定欄位型別與順序,透過 FETCH ... INTO 語法與 endFetch() 方法讀取。

兩者效能相當,選擇取決於程式碼風格偏好。

可執行陳述式

在大括號內包含靜態 SQL 操作。不傳回值的陳述式(如 DDL)直接執行;傳回值的陳述式需使用主機變數接收結果,可使用 VALUES 或 SET 運算子呼叫函數。

主機運算式

主機變數是 Java 程式中宣告的變數,嵌入 SQLJ 陳述式中作為主機運算式,實現 Java 與資料庫間的資料交換。支援所有標準 JDBC 型別,Oracle SQLJ 另支援 ROWID、CLOB、BLOB、Object、REF 等 Oracle 專屬型別。

Oracle JDBC 驅動程式簡介

  • 客戶端 Thin 驅動程式:100% 純 Java,適用於未安裝 Oracle Client 的環境,適合 Applet。
  • OCI 驅動程式:需安裝 Oracle Client 與 Net8,透過 OCI 直接存取,相容性最佳。
  • 伺服器端 Thin 驅動程式:功能同客戶端 Thin,但運行於資料庫內部,用於中介層存取遠端資料庫。
  • 伺服器端內部驅動程式 (KPRB):JVM 直接與 SQL 引擎通訊,效能最高,為資料庫內執行 SQLJ 預存程序的預設驅動程式。

程式碼範例

範例 1:使用具名迭代器

public static void listEmployees(String empSalary) throws SQLException {
    EmpIteratorClass empIterator;
    Integer salary = new Integer(empSalary);
    try {
        #sql empIterator = {
            select Ename, Job, HireDate
            from Emp
            where Sal > :salary
        };
        while (empIterator.next()) {
            System.out.println("Name: " + empIterator.Ename());
            System.out.println("Job: " + empIterator.Job());
            System.out.println("Hire Date: " + empIterator.HireDate().toString());
        }
        empIterator.close();
    } catch (SQLException e) {
        System.err.println("SQLException: " + e);
        System.exit(1);
    }
}

範例 2:使用位置迭代器

public static void listEmployees(String empSalary) throws SQLException {
    EmpIteratorClass empIterator;
    Integer salary = new Integer(empSalary);
    String name = null, job = null;
    Timestamp hireDate = null;
    try {
        #sql empIterator = {
            select Ename, Job, HireDate
            from Emp
            where Sal > :salary
        };
        while (true) {
            #sql { FETCH :empIterator INTO :name, :job, :hireDate };
            if (empIterator.endFetch()) break;
            System.out.println("Name: " + name);
            System.out.println("Job: " + job);
            System.out.println("Hire Date: " + hireDate.toString());
        }
        empIterator.close();
    } catch (SQLException e) {
        System.err.println("SQLException: " + e);
        System.exit(1);
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved