伺服器端程式設計:PL/SQL、Java 以及 JavaScript

SQL 說明結構化查詢語言 (SQL) 語言,以及資料庫如何處理 SQL 敘述句。本章說明儲存在資料庫中的程序語言 /SQL (PL/SQL) 或 Java 程式如何使用 SQL。

伺服器端程式設計簡介

在非程序語言 (例如 SQL) 中,指定要操作的資料集,但不會指定要執行的作業或執行作業的方式。

在程序語言程式中,大多數的敘述句執行取決於先前或後續的敘述句,以及 SQL 中無法使用的控制結構 (例如迴圈或條件分支)。如需程序語言與非程序語言之間的差異說明,假設下列 SQL 敘述句查詢 employees 表格:

SELECT employee_id, department_id, last_name, salary FROM employees;

前面的陳述式會要求資料,但不會對資料套用邏輯。不過,假設您希望應用程式決定資料集中的每位員工是否應依據薪資和部門績效來加薪。提高的必要條件是員工在過去五年內未收到超過三次的加薪。若呼叫加薪,則應用程式必須調整薪資,並以電子郵件傳送給經理人員;否則,應用程式必須更新報告。

問題在於需要條件邏輯和程式流程控制的程序資料庫應用程式如何使用 SQL。基本開發方法如下:

本章說明第二種方法。伺服器端程式設計的主要優點是,內建於資料庫的功能可以在任何位置部署。資料庫而非應用程式會決定在指定作業系統上執行作業的最佳方式。此外,子程式透過集中伺服器上的應用程式處理來提高可擴展性,讓用戶端可以重複使用程式碼。由於子程式呼叫既快速又有效率,因此單一呼叫可以啟動需要大量運算的預存子程式,從而減少網路流量。

您可以使用下列語言將資料邏輯儲存在 Oracle AI Database 中:

另請參閱:

PL/SQL 概要

PL/SQL 提供易於使用的伺服器端預存程序語言,與 SQL、強大、可攜式且安全無縫。您可以使用程序物件 (稱為 PL/SQL 單位 ) 來存取和操控資料庫資料。

PL/SQL 單位一般分類如下:

PL/SQL 編譯器和解譯器內嵌在 Oracle SQL Developer 中,可讓開發人員在從屬端和伺服器上使用一致的開發模型。此外,PL/SQL 預存程序可以從數個資料庫從屬端 (例如 Pro*C、JDBC、ODBC 或 OCI) 呼叫,也可以從 Oracle Reports 和 Oracle Forms 呼叫。

另請參閱:

PL/SQL 子程式設計

PL/SQL 子程式是指定的 PL/SQL 區塊,可讓呼叫程式提供只能輸入、僅輸出或輸入和輸出值的參數。

子程式可解決特定問題或執行相關工作,並作為模組化、可維護的資料庫應用程式的建置區塊。子程式是 PL/SQL 程序或 PL/SQL 函數。程序和功能完全相同,但功能一律會將單一值傳回給呼叫者,而程序則不會傳回。本章中的 PL/SQL 程序一詞是指程序或函數。

另請參閱:

PL/SQL 子程式的優點

與用戶端程式設計相比,伺服器端程式設計具有許多優點。

優點包括:

另請參閱:

建立 PL/SQL 子程式

獨立儲存的子程式是在綱要層次使用 CREATE PROCEDURE 或 CREATE FUNCTION 敘述句建立的子程式。套裝程式中定義的子程式稱為套裝程式子程式,被視為套裝程式的一部分。

資料庫會將資料說明中的子程式儲存為綱要物件。子程式具有規格,其中包含任何參數的描述與主體。

範例 11-1 PL/SQL 程序

此範例顯示獨立 PL/SQL 程序 hire_employees 之建立敘述句的一部分。程序會在 employees 表格中插入一列。

CREATE PROCEDURE hire_employees
  (p_last_name VARCHAR2, p_job_id VARCHAR2, p_manager_id NUMBER,
   p_hire_date DATE, p_salary NUMBER, p_commission_pct NUMBER,
   p_department_id NUMBER)
IS
BEGIN
.
.
.
  INSERT INTO employees (employee_id, last_name, job_id, manager_id, hire_date,
    salary, commission_pct, department_id)
  VALUES (emp_sequence.NEXTVAL, p_last_name, p_job_id, p_manager_id,
          p_hire_date, p_salary, p_commission_pct, p_department_id);
.
.
.
END;

另請參閱:

執行 PL/SQL 子程式

使用者可以透過多種方式以互動方式執行子程式。

這些選項包括:

下圖顯示呼叫 hire_employees 的不同資料庫應用程式。

圖 1:預存程序的多個執行項目

cncpt073.gif 圖解描述

或者,授權的使用者也可以使用 Oracle Enterprise Manager 或 SQL*Plus,使用下列敘述句來執行 hire_employees 程序:

EXECUTE hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);

上述敘述句會在 employees 表格中插入 TSMITH 的新記錄。

預存程序取決於其主體中參照的物件。資料庫會自動追蹤和管理這些相依性。例如,如果您以會影響此程序的方式來更改 hire_employees 程序所參照之 employees 表格的定義,則必須重新編譯程序,以驗證該程序仍依設計運作。資料庫通常會自動管理這類相依性管理。

另請參閱:

PL/SQL 套裝程式

PL/SQL 套裝程式是一組相關的子程式,以及它們使用的游標和變數,儲存在資料庫中以繼續作為單位使用。套裝程式子程式可由應用程式或使用者明確呼叫。

Oracle AI Database 包含許多提供的套裝程式,可擴充資料庫功能並提供 PL/SQL 存取 SQL 功能。例如,UTL_HTTP 套裝程式可讓 PL/SQL 和 SQL 的 HTTP 對外呼叫存取網際網路上的資料或呼叫 Oracle Web Server 磁帶匣。您可以在建立應用程式時使用提供的套裝程式,或在建立自己的預存程序時作為想法來源。

PL/SQL 套裝程式的優點

PL/SQL 套裝程式可為應用程式開發人員提供一些優點。

優點包括:

建立 PL/SQL 套裝程式

您可以在兩個部分建立套裝程式:規格和主體。套裝程式設定會宣告套裝程式的所有公用建構項目,套裝程式主體則定義套裝程式的所有建構項目 (公用和專用)。

下列範例顯示建立 employees_management 套件規格的陳述式部分,其中包含數個用於管理員工資料庫的子程式。套裝軟體的每個部分都是使用不同的陳述式建立的。

CREATE PACKAGE employees_management AS
  FUNCTION hire_employees (last_name VARCHAR2, job_id VARCHAR2, manager_id NUMBER,
    salary NUMBER, commission_pct NUMBER, department_id NUMBER) RETURN NUMBER;
  PROCEDURE fire_employees(employee_id NUMBER);
  PROCEDURE salary_raise(employee_id NUMBER, salary_incr NUMBER);
.
.
.
  no_sal EXCEPTION;
END employees_management;

規格會宣告函數 hire_employees、程序 fire_employees 和 salary_raise,以及異常狀況 no_sal。所有這些公用程式物件都可供具有套件存取權的使用者使用。

CREATE PACKAGE BODY 敘述句定義在規格中宣告的物件。套裝程式主體必須在與套裝程式相同的綱要中建立。建立套件之後,您可以開發呼叫任何這些公用程序或功能的應用程式,或提出套件的任何公用例外情況。

另請參閱:Oracle AI Database PL/SQL Language Reference,瞭解 CREATE PACKAGE 陳述式

執行 PL/SQL 套裝程式子程式

資料庫觸發程式、預存子程式、3GL 應用程式和 Oracle 工具都可以參照套裝軟體內容。

下圖顯示呼叫 employees_management 套裝程式中的程序和函數的資料庫應用程式。

圖 2:呼叫 PL/SQL 套裝程式中的子程式

cncpt075.gif 圖解描述

資料庫應用程式會視需要明確呼叫封裝程序。授予 employees_management 套裝程式的權限之後,使用者可以明確地執行其中包含的任何程序。例如,SQL*Plus 可以發出下列敘述句來執行 hire_employees 套裝程式程序:

EXECUTE employees_management.hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);

另請參閱:

PL/SQL 匿名封鎖

PL/SQL 匿名區塊是未命名、非永久的 PL/SQL 單位。

一般用於匿名區塊的使用方式包括:

匿名區塊沒有預存子程式的程式碼重複使用優點。表格 11-1 總結列出兩種 PL/SQL 單位類型之間的差異。

表 1 匿名區塊與子程式之間的差異

是 PL/SQL 單位 … 匿名封鎖 子程式
以名稱指定? 否 是
每次重複使用都經過編譯? 否 否
存放於資料庫中? 否 是
其他應用程式是否可呼叫? 否 是
是否可以傳回連結變數值? 是 是
是否可傳回函數值? 否 是
是否能夠接受參數? 否 是

匿名區塊是由選擇性的宣告部分、可執行部分,以及一或多個選擇性的異常狀況處理程式所組成。下列範例匿名區塊會在變數中選取員工姓氏,並列印姓名:

DECLARE
  v_lname VARCHAR2(25);
BEGIN
  SELECT last_name
    INTO v_lname
  FROM employees
  WHERE employee_id = 101;
  DBMS_OUTPUT.PUT_LINE('Employee last name is '||v_lname);
END;

Oracle AI Database 會編譯 PL/SQL 區塊並將其置於 SGA 的共用集區中,但不會將原始程式碼或編譯的版本儲存在資料庫中,以在目前的執行處理之外重複使用。與觸發程式不同,每次將匿名區塊載入記憶體時都會編譯該區塊。共用 SQL 可讓共用集區中的匿名 PL/SQL 區塊重複使用並共用,直到將它們從共用集區排清為止。

另請參閱:Oracle AI Database Development Guide 以深入瞭解匿名 PL/SQL 區塊

PL/SQL 語言建構

PL/SQL 區塊可以包含各種不同的 PL/SQL 語言建構。

這些建構項目包括以下各項:

PL/SQL 可以執行在程式實際執行之前無法辨識完整文字的動態 SQL 敘述句。動態 SQL 敘述句儲存在程式實際執行時輸入或由程式建立的字元字串中。此技術可讓您建立一般用途程序。例如,您可以建立一個在表格上運作的程序,其名稱在執行階段之前是未知的。

另請參閱:

PL/SQL 集合與記錄

許多程式設計技巧都使用陣列、包、清單、巢狀表格、集合和樹狀目錄等集合類型。

為了支援資料庫應用程式中的收集技術,PL/SQL 提供資料類型 TABLE 和 VARRAY。這些類型可讓您宣告關聯陣列、巢狀表格以及可變大小陣列。

催收

PL/SQL 集合是順序的元素群組,所有相同的類型都一樣。

每個元素都有一個決定其在集合中位置的唯一下標。若要建立集合,您必須先定義集合類型,然後宣告該類型的變數。

集合的運作方式就像使用大多數第三代程式設計語言所找到的陣列。此外,集合可以作為參數傳遞。因此,您可以使用它們將資料資料欄移入或移出資料庫表格,或在從屬端應用程式與預存子程式之間移動。

記錄

PL/SQL 記錄是一種複合變數,可儲存不同類型的資料值,類似於 C、C++ 或 Java 中的結構類型。記錄可用於保留表格列的資料,或表格列的特定欄。

假設您有員工相關資料,例如姓名、薪資和僱用日期。這些項目與類型不同,但邏輯上相關。包含每個項目欄位的記錄可讓您將資料視為邏輯單位。

您可以使用 %ROWTYPE 屬性來宣告代表從游標擷取之表格資料列或資料列的記錄。使用使用者定義的記錄,您可以宣告自己的欄位。

另請參閱:Oracle AI Database PL/SQL Language Reference,瞭解如何使用 PL/SQL 記錄

PL/SQL 執行方式

PL/SQL 支援解譯式執行和原生執行。

在解譯式執行中,PL/SQL 原始程式碼會編譯成所謂的位元組碼表示法。作為 Oracle AI Database 一部分實作的可攜式虛擬電腦會執行此位元組碼。

原生執行可在運算密集的單位上提供最佳效能。在此情況下,PL/SQL 單位的原始程式碼會直接編譯為指定平台的物件程式碼。此物件代碼會連結至 Oracle AI Database。

PL/SQL 引擎定義、編譯和執行 PL/SQL 單位。此引擎是許多 Oracle 產品 (包括 Oracle AI Database) 的特殊元件。雖然許多 Oracle 產品都有 PL/SQL 元件,但本主題特別涵蓋可以儲存在 Oracle AI Database 中並使用 Oracle AI Database PL/SQL 引擎處理的 PL/SQL 單位。每項 Oracle 工具的文件說明其 PL/SQL 功能。

下圖說明 Oracle AI Database 中包含的 PL/SQL 引擎。

圖 3:PL/SQL 引擎與 Oracle AI Database

cncpt070.gif 圖解描述

PL/SQL 單元儲存在資料庫中。當應用程式呼叫預存程序時,資料庫會將已編譯的 PL/SQL 單位載入系統整體區域 (SGA) 中的共用集區。PL/SQL 與 SQL 敘述句執行程式會一起運作,以處理程序中的敘述句。

您可以從另一個 PL/SQL 區塊呼叫預存程序,此區塊可以是匿名區塊,或是其他預存程序。例如,您可以從 Oracle Forms 呼叫預存程序。

在 Oracle AI Database 上執行的 PL/SQL 程序,可以呼叫以 C 程式設計語言撰寫並儲存在共用程式庫中的外部程序或函數。C 常式會以與 Oracle AI Database 不同的位址空間執行。

另請參閱:

Oracle AI Database 中的 Java 簡介

Java 已成為物件導向程式設計語言的一員。

Java 包含下列功能:

資料庫為 Java 程式提供動態資料處理引擎,可支援複雜查詢與多重資料檢視。用戶端要求會組合成資料查詢,以便立即處理。查詢結果會動態產生。

Java 和 Oracle AI Database 的組合可協助您建立以元件為基礎的網路為中心應用程式,並隨著業務需求的變化輕鬆更新。此外,您可以將應用程式和資料儲存從桌面移出,並移到智慧型網路和以網路為中心的伺服器上。更重要的是,您可以從任何用戶端裝置存取這些應用程式和資料倉庫。

下圖顯示傳統的兩層從屬端 / 伺服器組態,從屬端呼叫 Java 預存程序的方式與呼叫 PL/SQL 子程式的方式相同。

圖 4:兩層從屬端 / 伺服器組態

cncpt236.gif 圖解描述

Java Virtual Machine (JVM) 簡介

JVM 是執行編譯之 Java 程式碼的虛擬處理器。

Java 原始程式碼會編譯為不受平台影響的低階機器指示 (稱為位元組碼 )。Java 位元組碼會透過 JVM 解譯為平台相依的動作。

Oracle JVM 總覽

Oracle JVM 是執行任何純 Java 應用程式的標準 Java 相容環境。它與 JLS 和 JVM 規格相容。

Oracle JVM 支援標準 Java 二進位格式和 API。此外,Oracle AI Database 遵循標準 Java 語言語意,包括程式實際執行時的動態類別載入。

下圖說明 Oracle Java 應用程式如何位在 Oracle JVM 的最上層 Java 核心類別程式庫。因為 Oracle Java 支援系統位於資料庫內,所以 JVM 會與資料庫程式庫互動,而不是直接與作業系統互動。

圖 5:Java 元件結構

cncpt206.gif 圖解描述

與其他 Java 環境不同,Oracle JVM 會內嵌在 Oracle AI Database 中。Oracle JVM 與一般從屬端 JVM 之間存在一些重要的差異。例如,在標準 Java 環境中,您可以在命令行發出下列命令,透過解譯器執行 Java 應用程式,其中 classname 是 JVM 先解譯的類別名稱:

java classname

上述命令會讓應用程式在您的作業系統上執行處理程序。不過,如果您未使用命令行介面,則必須將應用程式載入資料庫、發佈介面,然後在資料庫資料說明內執行應用程式。

另請參閱:如需 Oracle JVM 與一般從屬端 JVM 之間其他差異的描述,請參閱 Oracle AI Database Java Developer's Guide。

Oracle JVM 的主要元件

Oracle JVM 會在與資料庫核心相同的處理作業空間和位址空間中執行,方法是共用其記憶體堆集並直接存取其關聯式資料。此設計可最佳化記憶體使用量並增加傳輸量。

Oracle JVM 為 Java 物件提供程式實際執行環境。它完整支援 Java 資料結構、方法分配、異常狀況處理,以及語言層次的執行緒。它也支援所有核心 Java 類別程式庫,包括 java.lang、java.io、java.net、java.math 和 java.util。

下圖顯示 Oracle JVM 的主要元件。

圖 6:Oracle JVM 的主要元件

cncpt254.gif 圖解描述

Oracle JVM 會在資料庫綱要中內嵌標準 Java 命名空間。此功能可讓 Java 程式存取儲存在 Oracle AI Database 中的 Java 物件,以及整個企業的應用程式伺服器。

此外,Oracle JVM 也與資料庫的可擴充共用記憶體架構緊密整合。Java 程式不需使用者介入,即可有效率地使用呼叫、階段作業以及物件週期。因此,即使 Oracle JVM 和中間層 Java 商業物件處於階段作業長期狀態,也可加以調整。

另請參閱:Oracle AI Database Java Developer's Guide,瞭解 Oracle JVM 主要元件的說明

Java 程式設計環境

Oracle 為企業應用程式開發人員提供用於建立、部署和管理 Java 應用程式的端對端 Java 解決方案。

此解決方案包含用戶端與伺服器端程式設計介面、支援 Java 開發的工具,以及與 Oracle AI Database 整合的 Java Virtual Machine。所有這些產品均與 Java 標準相容。

Java 程式設計環境包含下列其他功能:

Java 儲存的程序

Java 預存程序是發布至 SQL 並儲存在資料庫中的 Java 方法。

就像 PL/SQL 子程式一樣,您可以直接使用 SQL*Plus 等產品呼叫 Java 程序,也可以使用觸發程式間接呼叫。您可以從任何 Oracle Net 從屬端 -OCI、預先編譯器或 JDBC 存取敘述句。

如果要發佈 Java 方法,您可以撰寫呼叫規格,將 Java 方法名稱、參數類型以及傳回類型對應至其 SQL 對等部份。當從屬端應用程式呼叫時,Java 預存程序會接受引數、參照 Java 類別以及傳回 Java 結果值。

應用程式會透過參照呼叫設定的名稱來呼叫 Java 方法。程式實際執行系統會在 Oracle 資料說明中查詢呼叫設定定義,並執行對應的 Java 方法。

此外,您也可以使用 Java 開發與 PL/SQL 無關的強大程式。Oracle AI Database 提供完全合規的 Java 程式設計語言和 JVM 實作。

另請參閱:Oracle AI Database Java Developer's Guide 說明如何在 Java 中撰寫預存程序、如何從 PL/SQL 存取預存程序,以及如何從 Java 存取 PL/SQL 功能

Java 和 PL/SQL 整合

您可以從 Java 和 Java 程式,從 PL/SQL 呼叫現有的 PL/SQL 程式。此解決方案可保護及運用您的 PL/SQL 與 Java 程式碼。

Oracle AI Database 提供 JDBC 來從從屬端和伺服器上的 Java 存取 SQL 資料。

JDBC 驅動程式

JDBC 是一種資料庫存取協定,可讓您連線資料庫並執行 SQL 敘述句和資料庫查詢。

核心 Java 類別程式庫只提供一個 JDBC API java.sql。不過,JDBC 的設計目的是要讓廠商提供驅動程式,以針對特定資料庫提供必要的專業化。Oracle 提供下表顯示的不同 JDBC 驅動程式。

表格 2 JDBC 驅動程式

驅動程式 說明
JDBC 精簡驅動程式 您可以使用 JDBC Thin 驅動程式,撰寫純 Java 應用程式和存取 Oracle SQL 資料的 Applet。JDBC Thin 驅動程式特別適用於 Web 型應用程式和 Applet,因為您可以從網頁動態下載,類似於其他的 Java Applet。
JDBC OCI 驅動程式 JDBC OCI 驅動程式會存取從屬端或中間層的 Oracle 特定原生程式碼 (亦即非 Java 程式碼和程式庫),可大幅增加與 JDBC Thin 驅動程式相比的效能,並大幅增加大小和從屬端安裝的成本。
JDBC 伺服器端內部驅動程式 當 Java 程式碼在伺服器上執行時,Oracle AI Database 會使用伺服器端內部驅動程式。它可讓伺服器上 Oracle JVM 中執行的 Java 應用程式存取本機定義的資料,亦即相同系統和相同程序中的資料與 JDBC。它可大幅提升效能,因為它能夠直接使用底層的 Oracle RDBMS 程式庫,而不會造成 Java 程式碼與 SQL 資料之間介入網路連線的負荷。藉由在伺服器上支援相同的 Java-SQL 介面,Oracle AI Database 不需要您在部署程式碼時重新編寫程式碼。

另請參閱:

Oracle AI Database 中的 JavaScript 簡介

JavaScript 是當今最受歡迎的程式設計語言之一。部署在 Linux x86-64 或 Linux aarch64 上的 Oracle AI Database,會將 JavaScript 新增至伺服器端開發支援的語言清單中。

您可以將 JavaScript 的模組儲存在資料庫中,處理其存在的資料,以提供比用戶端開發方法更大的改進。JavaScript 由 Multilingual Engine (MLE) 執行。

開發人員可以選擇執行獨立的 JavaScript 程式碼,並將 JavaScript 程式碼以原生方式儲存在資料庫中作為模組。

將商業邏輯儲存為資料庫中的模組

與用戶端開發相關的 JavaScript 一樣,程式碼可以用模組的形式儲存在一起。

具備 PL/SQL 背景的開發人員可以將 JavaScript 模組視為等同於 PL/SQL 套裝程式主體,但以 JavaScript 撰寫。在模組中宣告的函數可以標示為匯出或保持私密。

Oracle AI Database 中的 JavaScript 符合 ECMAScript 2023 標準,為開發人員提供了在資料庫中儲存業務邏輯的廣泛可能性。

備註:

另請參閱:

以下為使用 MLE 建立 JavaScript 模組的範例:

create mle module if not exists example_module
language javascript as

export function string2obj(inputString) {
   if ( inputString === undefined ) {
      throw `must provide a string in the form of key1=value1;...;keyN=valueN`;
   }

   let myObject = {};
   if ( inputString.length === 0 ) {
      return myObject;
   }

   const kvPairs = inputString.split(";");
   kvPairs.forEach( pair => {
      const tuple = pair.split("=");
      if ( tuple.length === 1 ) {
          tuple[1] = false;
      } else if ( tuple.length != 2 ) {
          throw "parse error: you need to use exactly one '=' between key and value and not use '=' in either key or value";
      }
      myObject[tuple[0]] = tuple[1];
  });

  return myObject;
}
/

JavaScript 模組 (也稱為「MLE 模組」) 現在儲存在使用者的綱要中。其唯一函數 string2obj() 可透過建立「呼叫規格」來對 SQL 和 PL/SQL 公開。呼叫規格是 PL/SQL 程式單元,可讓您在任何可呼叫 SQL 和 PL/SQL 的地方呼叫 JavaScript 程式碼。string2obj() 的呼叫規格可寫入如下:

create function if not exists p_string_to_JSON(p_str varchar2) return JSON
as mle module example_module
   signature 'string2obj(string)';
/

建立函數時,可以從 SQL 呼叫函數:

declare
   l_json   JSON;
   l_string VARCHAR2(100);
begin
   l_string := 'a=1;b=2;c=3;d';
   l_json := p_string_to_JSON(l_string);
   dbms_output.put_line(json_serialize(l_json PRETTY));
end;
/

{
  "a" : "1",
  "b" : "2",
  "c" : "3",
  "d" : false
}

PL/SQL procedure successfully completed.

JavaScript 程式碼的動態執行

架構開發人員和任何想要執行獨立 JavaScript 程式碼的人,不需要將程式碼儲存在資料庫中,就可以使用 DBMS_MLE 套裝程式及其子程式。

Oracle Application Express 和 Database Actions (例如整合 DBMS_MLE),以隱藏在封面下呼叫 PL/SQL 套裝程式的事實。

與 MLE 模組相比,使用 DBMS_MLE 使撰寫整個應用程式變得更加困難。例如,邏輯上將應用程式劃分成不同的實體是較難的。「執行後除錯」功能需要可讓模組更難排解程式碼片段中的問題。持續整合 (CI) 管線也可能在同一個檔案中列印 PL/SQL 和 JavaScript 程式碼。同樣,您的整合開發環境 (IDE) 可能發生問題,因為大部分問題都會在同一個視窗中同時使用 PL/SQL 和 JavaScript。

備註:

另請參閱:

內嵌 JavaScript 預存程序

內嵌的 MLE 呼叫規格會直接在 CREATE FUNCTION 和 CREATE PROCEDURE DDL 中內嵌 JavaScript 程式碼。

如果您想要使用 JavaScript 快速導入簡單功能,內嵌的 MLE 呼叫規格可能是不錯的選擇。使用此選項時,您不需要部署包含 JavaScript 程式碼的個別模組。而是將 JavaScript 函數內建於呼叫規格本身的定義中。

MLE LANGUAGE 子句用來指定使用 JavaScript 實行函數。語言名稱之後的字串會被視為實行呼叫規格功能之 JavaScript 函數的主體。執行程式碼時,PL/SQL 參數會自動轉換成預設的 JavaScript 類型,並以相同名稱的參數傳送到 JavaScript 函數。請注意,未加引號的參數名稱會對應至全大寫的 JavaScript 名稱。JavaScript 函數傳回的值會轉換成 PL/SQL 呼叫規格的傳回類型,就像 MLE 模組的呼叫規格一樣。

備註:

另請參閱:

觸發程式概要

資料庫觸發程式是以 PL/SQL、Java 或 JavaScript 撰寫的已編譯預存程式單元,Oracle Database 會在特定情況下自動呼叫 ("fires")。

每當發生下列其中一項作業時,就會觸發程式:

  1. 任何使用者所發出之特定表格或視觀表的 DML 敘述句

    DML 敘述句可修改綱要物件中的資料。例如,插入和刪除資料列都是 DML 作業。

  2. 特定使用者或任何使用者發出的 DDL 敘述句

    DDL 敘述句定義綱要物件。例如,建立表格並新增資料欄為 DDL 作業。

  3. 資料庫活動

    使用者登入或登出、錯誤,以及資料庫啟動或關閉是可以呼叫觸發程式的事件。

觸發程式是類似子程式的綱要物件,但與呼叫子程式的方式不同。子程式是由使用者、應用程式或觸發程式明確執行。觸發器會在觸發事件發生時,由資料庫隱含地呼叫。

另請參閱:

觸發程式的優點

正確使用觸發程式可讓您建置和部署更健全且更有效率地使用資料庫的應用程式。

您可以使用觸發器來:

您可以使用觸發程式強制執行所有用戶端應用程式通用的低階商業規則。例如,數個應用程式可以存取 employees 表格。如果此表格上的觸發程式可確保所插入資料的格式,則不需要在每個用戶端中重現此業務邏輯。因為應用程式無法規避觸發器,所以會自動使用觸發器中的業務邏輯。

您可使用觸發器與完整性限制來定義並強制執行任何類型的完整性規則。不過,Oracle 強烈建議您只使用觸發程式來強制執行無法使用完整性限制條件定義的複雜業務規則。

過度使用觸發程式可能會導致複雜的交互相依性,在大型應用程式中很難維護。例如,呼叫觸發器時,其觸發器動作中的 SQL 陳述式可能會觸發其他觸發器,進而產生可產生非預期效果的重疊觸發器。

另請參閱:

在特定情況下自動執行。」

觸發程式類型

觸發程式可以根據其呼叫方法和其執行的動作類型來分類。

Oracle Database 支援下列類型的觸發程式:

另請參閱:

自動在某些情況下。」

觸發程式的時間

您可以定義觸發程式計時 - 無論觸發程式動作是在觸發程式敘述句之前或之後執行。

簡單觸發程式是表格上的單一觸發程式,可讓您為下列其中一個計時點指定動作:

對於陳述式與列觸發器,BEFORE 觸發器可增強安全性並啟用商業規則,然後再對資料庫進行變更。AFTER 觸發程式適用於記錄動作。

複合觸發器可以在多個時間點觸發。複合觸發程式可幫助程式一種方法,在其中針對各種計時點實作的動作會共用通用資料。

另請參閱:Oracle AI Database PL/SQL Language Reference,瞭解複合觸發程式

自動在某些情況下。」

建立觸發程式

CREATE TRIGGER 敘述句會建立或取代資料庫觸發程式。

PL/SQL 觸發程式具有下列一般語法形式:

CREATE TRIGGER trigger_name
  triggering_statement
  [trigger_restriction]
BEGIN
 triggered_action;
END;

PL/SQL 觸發程式具有下列基本元件:

另請參閱:

在特定情況下自動執行。」

範例:CREATE TRIGGER 敘述句

此範例會建立在行項目表格上執行 INSERT、UPDATE 或 DELETE 敘述句時觸發的觸發程式。

假設您使用下列陳述式建立 orders 和 lineitems 表格。orders 表格包含每個唯一訂單的資料列,而 lineitems 表格則包含訂單中每個項目的資料列。

CREATE TABLE orders
( order_id NUMBER PRIMARY KEY,
  /* other attributes */
  line_items_count NUMBER DEFAULT 0 );

CREATE TABLE lineitems
( order_id REFERENCES orders,
  seq_no   NUMBER,
  /* other attributes */
  CONSTRAINT lineitems PRIMARY KEY(order_id,seq_no) );

下列陳述式會建立範例觸發程式,以訂單中的項目數自動更新 orders 表格:

CREATE OR REPLACE TRIGGER lineitems_trigger
  AFTER INSERT OR UPDATE OR DELETE ON lineitems
  FOR EACH ROW
BEGIN
  IF (INSERTING OR UPDATING)
  THEN
    UPDATE orders SET line_items_count = NVL(line_items_count,0)+1
    WHERE order_id = :new.order_id;
  END IF;
  IF (DELETING OR UPDATING)
  THEN
    UPDATE orders SET line_items_count = NVL(line_items_count,0)-1
    WHERE order_id = :old.order_id;
  END IF;
END;
/

在 lineitems_trigger 中,觸發陳述式是 lineitems 表格上的 INSERT、UPDATE 或 DELETE。沒有觸發限制。每個變更的資料列都會呼叫觸發程式。觸發程式可存取受觸發程式陳述式影響之目前列的舊與新欄值。要修改之表格的每個資料欄都有兩個關聯名稱:舊值 (:old) 和新值 (:new)。如果階段作業針對訂單更新或插入 lineitems 中的資料列,則在動作之後,觸發程式會依此順序計算項目數,並以計數更新 orders 表格。

範例:呼叫資料列層次觸發程式

在此案例中,客戶會起始兩筆訂單,然後新增並移除訂單中的明細行項目。

分析藍本是以範例:CREATE TRIGGER 敘述句中建立的觸發程式為基礎。

表格 3 資料列層次觸發程式案例

SQL 敘述句 觸發的 SQL 敘述句 說明
SQL> INSERT INTO orders
 (order_id) VALUES (78);

  1 row created. 
 

客戶會建立 ID 為 78 的訂單。此時,客戶在訂單中沒有料號。

因為不會對 lineitems 表格執行任何動作,所以不會呼叫觸發程式。

SQL> INSERT INTO orders
 (order_id) VALUES (92);

  1 row created. 
 

客戶會建立 ID 為 92 的個別訂單。此時,客戶在訂單中沒有料號。

因為不會對 lineitems 表格執行任何動作,所以不會呼叫觸發程式。

SQL> INSERT INTO lineitems
  (order_id, seq_no)
 VALUES (78,1);

  1 row created. 
UPDATE orders
  SET line_items_count =
  NVL(NULL,0)+1
 WHERE order_id = 78;

客戶將料號新增至訂單 78。

INSERT 會呼叫觸發程式。觸發的對帳單會將訂單 78 的明細行項目計數從 0 增加到 1。

SQL> INSERT INTO lineitems
  (order_id, seq_no)
  VALUES (78,2);

  1 row created. 
UPDATE orders
  SET line_items_count =
  NVL(1,0)+1
 WHERE order_id = 78; 

客戶將額外料號新增至訂單 78。

INSERT 會呼叫觸發程式。觸發的對帳單會將訂單 78 的明細行項目計數從 1 增加到 2。

SQL> SELECT * FROM orders;

  ORDER_ID LINE_ITEMS_COUNT
 --------- ----------------
 78 2
 92 0
  客戶會查詢兩筆訂單的狀態。訂單 78 包含兩個項目。訂單 92 未包含任何項目。
SQL> SELECT * FROM lineitems;

  ORDER_ID SEQ_NO
 ---------- ----------
 78 1
 78 2
  客戶會查詢明細行項目的狀態。每個料號都是由訂單 ID 與序號所唯一識別。
SQL> UPDATE lineitems
  SET order_id = 92;

  2 rows updated.
UPDATE orders
  SET line_items_count =
  NVL(NULL,0)+1
 WHERE order_id = 92;

  UPDATE orders
  SET line_items_count =
  NVL(2,0)-1
 WHERE order_id = 78; 
UPDATE orders
  SET line_items_count =
  NVL(1,0)+1
 WHERE order_id = 92;

  UPDATE orders
  SET line_items_count =
  NVL(1,0)-1
 WHERE order_id = 78;

客戶將訂單 78 中的明細行項目移至訂單 92。

UPDATE 敘述句會變更 lineitems 表格中的 2 個資料列,這會對每個資料列呼叫觸發程式一次。

每次呼叫觸發程式時,都會同時符合觸發程式中的 IF 條件。第一個條件遞增了訂單 92 的計數,第二個條件則遞減了訂單 78 的計數。因此,會執行四個總計的 UPDATE 陳述式。

SQL> SELECT * FROM orders;

  ORDER_ID LINE_ITEMS_COUNT
 --------- ----------------
 78 0
 92 2
  客戶會查詢兩筆訂單的狀態。淨影響是訂單 92 的明細行項目計數從 0 增加至 2,而訂單 78 的計數則從 2 減少至 0。
SQL> SELECT * FROM lineitems;

  ORDER_ID SEQ_NO
 ---------- ----------
 92 1
 92 2
  客戶會查詢明細行項目的狀態。每個料號都是由訂單 ID 與序號所唯一識別。
SQL> DELETE FROM lineitems;

  2 rows deleted.
UPDATE orders
  SET line_items_count =
  NVL(2,0)-1
 WHERE order_id = 92;

  UPDATE orders
  SET line_items_count =
  NVL(1,0)-1
 WHERE order_id = 92;

客戶現在會從所有訂單中移除所有明細行項目。

DELETE 敘述句會變更 lineitems 表格中的 2 個資料列,這會對每個資料列呼叫觸發程式一次。對於每個觸發程式呼叫,觸發程式中只符合一個 IF 條件。每次條件將訂單 92 的計數減少 1 時。因此,會執行兩個總計的 UPDATE 敘述句。

SQL> SELECT * FROM orders;

  ORDER_ID LINE_ITEMS_COUNT
 --------- ----------------
 78 0
 92 0

  SQL> SELECT * FROM lineitems;

  no rows selected
 

客戶會查詢兩筆訂單的狀態。兩個訂單都未包含明細行項目。

客戶也會查詢明細行項目的狀態。沒有料號。

執行觸發程式

Oracle Database 會使用與子程式執行相同的步驟,在內部執行觸發程式。

唯一的細微差異是,如果使用者帳戶具有執行觸發敘述句的權限,則具有觸發程式的權限。在此例外情況中,資料庫驗證與執行所觸發的方式與儲存的子程式相同。

另請參閱:Oracle AI Database PL/SQL Language Reference,瞭解觸發程式執行的詳細資訊

在特定情況下自動執行。」

觸發器的儲存

Oracle Database 會將 PL/SQL 觸發程式以編譯形式儲存在資料庫綱要中,就像 PL/SQL 預存程序一樣。

當 CREATE TRIGGER 敘述句確認時,編譯的 PL/SQL 程式碼會儲存在資料庫中。共用集區會移除 PL/SQL 觸發程式的原始程式碼。

下圖顯示具有隱含呼叫 PL/SQL 觸發程式之 SQL 敘述句的資料庫應用程式。觸發器與其相關聯的表格分開儲存。

圖 7:觸發程式

cncpt076.gif 圖解描述

Java 觸發程式的儲存方式與 PL/SQL 觸發程式相同。不過,Java 觸發程式會參照以 CALL 敘述句個別編譯的 Java 程式碼。因此,建立 Java 觸發程式涉及建立 Java 程式碼,並建立參照此 Java 程式碼的觸發程式。

另請參閱:Oracle AI Database PL/SQL Language Reference,瞭解編譯和儲存觸發程式

在特定情況下自動執行。」