11 Server-Side Programming: PL/SQL, Java, and JavaScript(11 服务器端编程:PL/SQL、Java 和 JavaScript)
SQL 说明了结构化查询语言(SQL)以及数据库如何处理 SQL 语句。本章说明存储在数据库中的过程语言/SQL(PL/SQL)或 Java 程序如何使用 SQL。
-
Introduction to Server-Side Programming(服务器端编程简介)
在诸如 SQL 之类的非过程化语言中,指定了要操作的数据集,但未指定要执行的操作或执行操作的方式。
-
Overview of PL/SQL(PL/SQL 概述)
PL/SQL 提供了一种服务器端存储过程语言,易于使用,与 SQL 无缝集成,健壮,可移植且安全。您可以使用称为 PL/SQL 单元的过程化对象访问和操作数据库数据。
-
Overview of Java in Oracle AI Database(Oracle AI 数据库中的 Java 概述)
Java 已成为首选的面向对象编程语言。
-
Overview of JavaScript in Oracle AI Database(Oracle AI 数据库中的 JavaScript 概述)
JavaScript 是当今最流行的编程语言之一。部署在 Linux x86-64 或 Linux aarch64 上的 Oracle AI 数据库将 JavaScript 添加到支持服务器端开发的语言列表中。
-
Overview of Triggers(触发器概述)
数据库触发器是一种编译的存储程序单元,可以用 PL/SQL、Java 或 JavaScript 编写,Oracle 数据库在某些情况下会自动调用("触发")它。
另请参见
SQL 了解 SQL 语言概述。
Introduction to Server-Side Programming(服务器端编程简介)
在诸如 SQL 之类的非过程化语言中,指定了要操作的数据集,但未指定要执行的操作或执行操作的方式。
在过程化语言程序中,大多数语句的执行依赖于先前或后续的语句以及控制结构(例如循环或条件分支),而这些在 SQL 中是不可用的。为了说明过程化语言和非过程化语言之间的区别,假设以下 SQL 语句查询 employees 表:
sql
SELECT employee_id, department_id, last_name, salary FROM employees;
上述语句请求数据,但不对数据应用逻辑。但是,假设您希望应用程序根据薪水和部门绩效来确定数据集中的每位员工是否应得到加薪。加薪的一个必要条件是,该员工在过去五年内获得加薪的次数不超过三次。如果批准加薪,则应用程序必须调整薪水并通过电子邮件通知经理;否则,应用程序必须更新报告。
问题在于,需要条件逻辑和程序流控制的过程化数据库应用程序如何使用 SQL。基本的开发方法如下:
-
使用客户端编程将 SQL 语句嵌入到用过程化语言(如 C、C++ 或 Java)编写的应用程序中
您可以将 SQL 语句放置在源代码中,并在编译前将其提交给预编译器或 Java 翻译器。或者,您可以消除预编译步骤,并使用诸如 Java 数据库连接(JDBC)或 Oracle 调用接口(OCI)之类的 API 使应用程序能够与数据库交互。
-
使用服务器端编程开发驻留在数据库中的数据逻辑
应用程序可以显式调用存储子程序(过程和函数),这些子程序可以用 PL/SQL、Java 或 JavaScript 编写。您还可以创建触发器,它是一个命名的程序单元,存储在数据库中,并响应指定事件而被调用。
本章解释第二种方法。服务器端编程的主要好处是,内置于数据库中的功能可以部署到任何地方。是数据库而不是应用程序决定了在给定操作系统上执行任务的最佳方式。此外,子程序通过将应用程序处理集中在服务器上,使客户端能够重用代码,从而提高了可伸缩性。因为子程序调用快速而高效,单个调用就可以启动一个计算密集型的存储子程序,从而减少网络流量。
您可以使用以下语言在 Oracle AI 数据库中存储数据逻辑:
-
PL/SQL
PL/SQL 是 Oracle AI 数据库对 SQL 的过程化扩展。PL/SQL 与数据库集成,支持所有 Oracle SQL 语句、函数和数据类型。
用数据库 API 编写的应用程序可以调用 PL/SQL 存储子程序,并将 PL/SQL 代码块发送到数据库执行。
-
Java
Oracle AI 数据库还支持开发、存储和部署 Java 应用程序。Java 存储子程序在数据库中运行,并且独立于在中间层运行的程序。Java 存储子程序使用与 PL/SQL 类似的执行模型与 SQL 交互。
-
JavaScript
当部署在 Linux x86-64 或 Linux aarch64 上时,Oracle AI 数据库允许开发人员使用 JavaScript 表达业务逻辑。通过
DBMS_MLEPL/SQL 包及其子程序,可以实现 JavaScript 的即席执行。将业务逻辑存储为 JavaScript 模式对象使您能够编写更复杂的应用程序。调用规范以类似于 Java 存储过程的方式,将存储在数据库中的 JavaScript 代码公开在 SQL 和 PL/SQL 中。
另请参见
- 《Oracle AI 数据库开发指南》了解有关使用预编译器和 API 嵌入 SQL 的信息
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》了解 Oracle AI 数据库应用程序开发简介
- 《Oracle AI 数据库开发指南》了解如何选择编程环境
- 《Oracle AI 数据库 JavaScript 开发人员指南》了解有关 Oracle AI 数据库中 JavaScript 支持的更多信息。
Overview of PL/SQL(PL/SQL 概述)
PL/SQL 提供了一种服务器端存储过程语言,易于使用,与 SQL 无缝集成,健壮,可移植且安全。您可以使用称为 PL/SQL 单元的过程化对象访问和操作数据库数据。
PL/SQL 单元通常分类如下:
- PL/SQL 子程序是一个 PL/SQL 块,它存储在数据库中,并可以通过应用程序按名称调用。当您创建子程序时,数据库会解析该子程序并将其解析后的表示存储在数据库中。您可以将子程序声明为过程或函数。
- PL/SQL 匿名块是出现在应用程序中的 PL/SQL 块,它没有命名,也不存储在数据库中。在许多应用程序中,PL/SQL 块可以出现在 SQL 语句可以出现的任何位置。
PL/SQL 编译器和解释器嵌入在 Oracle SQL Developer 中,为开发人员在客户端和服务器端提供了一致且高效的开发模型。此外,PL/SQL 存储过程可以从多个数据库客户端(例如 Pro*C、JDBC、ODBC 或 OCI)以及 Oracle Reports 和 Oracle Forms 中调用。
-
PL/SQL Subprograms(PL/SQL 子程序)
PL/SQL 子程序是一个命名的 PL/SQL 块,允许调用者提供参数,这些参数可以是仅输入、仅输出或输入输出值。
-
PL/SQL Packages(PL/SQL 包)
PL/SQL 包是一组相关的子程序,连同它们使用的游标和变量,作为一个单元一起存储在数据库中以供持续使用。包中的子程序可以由应用程序或用户显式调用。
-
PL/SQL Anonymous Blocks(PL/SQL 匿名块)
PL/SQL 匿名块是一个未命名的、非持久性的 PL/SQL 单元。
-
PL/SQL Language Constructs(PL/SQL 语言结构)
PL/SQL 块可以包含各种不同的 PL/SQL 语言结构。
-
PL/SQL Collections and Records(PL/SQL 集合与记录)
许多编程技术使用集合类型,如数组、袋、列表、嵌套表、集合和树。
-
How PL/SQL Runs(PL/SQL 如何运行)
PL/SQL 同时支持解释执行和本机执行。
另请参见
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》
- 《Oracle AI 数据库 PL/SQL 语言参考》了解有关 PL/SQL 的完整信息,包括包
PL/SQL Subprograms(PL/SQL 子程序)
PL/SQL 子程序是一个命名的 PL/SQL 块,允许调用者提供参数,这些参数可以是仅输入、仅输出或输入输出值。
子程序解决特定问题或执行相关任务,并作为模块化、可维护的数据库应用程序的构建块。子程序可以是 PL/SQL 过程或 PL/SQL 函数。过程和函数是相同的,不同之处在于函数总是向调用者返回单个值,而过程则不返回。本章中的术语 PL/SQL 过程指的是过程或函数。
-
Advantages of PL/SQL Subprograms(PL/SQL 子程序的优势)
服务器端编程比客户端编程具有许多优势。
-
Creation of PL/SQL Subprograms(PL/SQL 子程序的创建)
独立的存储子程序是使用
CREATE PROCEDURE或CREATE FUNCTION语句在模式级别创建的子程序。在包中定义的子程序称为包子程序,并被视为包的一部分。 -
Execution of PL/SQL Subprograms(PL/SQL 子程序的执行)
用户可以通过多种方式交互式地执行子程序。
另请参见
- 《ProC/C++ 开发人员指南》和《ProCOBOL 开发人员指南》了解这些语言中有关存储过程的信息
- 《Oracle AI 数据库 PL/SQL 语言参考》
Advantages of PL/SQL Subprograms(PL/SQL 子程序的优势)
服务器端编程比客户端编程具有许多优势。
优势包括:
-
提高性能
-- 与发出单个 SQL 语句或向 Oracle AI 数据库发送整个 PL/SQL 块的文本相比,应用程序必须通过网络发送的信息量很小,因为信息只发送一次,然后在使用时调用。
-- 过程的编译形式在数据库中随时可用,因此在执行时无需编译。
-- 如果该过程存在于系统全局区(SGA)的共享池中,则数据库无需从磁盘检索它,并且可以立即开始执行。
-
内存分配
由于存储过程利用了 Oracle AI 数据库的共享内存功能,因此它只需将过程的单个副本加载到内存中,即可供多个用户执行。在用户之间共享代码可以显著降低应用程序对数据库内存的需求。
-
提高生产力
存储过程提高了开发生产力。通过围绕一组通用过程设计应用程序,可以避免冗余编码。例如,您可以编写过程来操作
employees表中的行。任何应用程序都可以调用这些过程,而无需重写 SQL 语句。如果数据管理方法发生变化,则只需修改过程,而无需修改使用这些过程的应用程序。存储过程可能是实现代码重用的最佳方式。因为任何以任何语言编写并连接到数据库的客户端应用程序都可以调用存储过程,所以它们在所有环境中提供了最大的代码重用。
-
完整性
存储过程提高了应用程序的完整性和一致性。通过围绕一组通用过程开发应用程序,可以降低编码错误的可能性。
例如,您可以测试一个子程序以保证它返回准确的结果,并且在验证之后,在任何数量的应用程序中重用它而无需重新测试。如果过程引用的数据结构被更改,那么您只需要重新编译该过程。调用该过程的应用程序不一定需要修改。
-
使用定义者权限过程的安全性
存储过程有助于加强数据安全性。定义者权限的 PL/SQL 过程使用其所有者(而非当前用户)的权限执行。因此,您可以通过仅允许用户通过以定义者权限运行的过程和函数访问数据来限制用户执行的数据库任务。
例如,您可以授予用户访问更新表的过程的权限,但不授予对表本身的访问权限。当用户调用该过程时,它会以其所有者的权限运行。只有运行该过程的权限(但没有查询、更新或删除基础表的权限)的用户可以调用该过程,但不能以任何其他方式操作表数据。
-
使用调用者权限过程的继承权限和模式上下文
调用者权限的 PL/SQL 过程使用当前用户的权限在当前用户的模式中执行。换句话说,调用者权限过程不绑定到特定的用户或模式。调用者权限过程使应用程序开发人员即使基础数据分布在用户模式之间,也能轻松地集中应用程序逻辑。
例如,对
hr.employees表运行更新过程的hr_manager用户可以更新薪水,而运行相同过程的hr_clerk则被限制为仅更新地址数据。
另请参见
- 《Oracle AI 数据库 PL/SQL 语言参考》了解 PL/SQL 子程序概述
- 《Oracle AI 数据库安全指南》了解有关定义者权限和调用者权限的更多信息
Creation of PL/SQL Subprograms(PL/SQL 子程序的创建)
独立的存储子程序是使用 CREATE PROCEDURE 或 CREATE FUNCTION 语句在模式级别创建的子程序。在包中定义的子程序称为包子程序,并被视为包的一部分。
数据库将子程序作为模式对象存储在数据字典中。子程序具有一个规范,其中包括任何参数的描述,以及一个主体。
示例 11-1 PL/SQL 过程
sql
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;
另请参见
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》了解如何创建子程序
- 《Oracle AI 数据库 PL/SQL 语言参考》了解
CREATE PROCEDURE语句
Execution of PL/SQL Subprograms(PL/SQL 子程序的执行)
用户可以通过多种方式交互式地执行子程序。
选项包括:
- 使用 Oracle 工具,如 SQL*Plus 或 SQL Developer
- 在数据库应用程序(如 Oracle Forms 或预编译器应用程序)的代码中显式调用它
- 在另一个过程或触发器的代码中显式调用它
下图显示了不同的数据库应用程序调用 hire_employees 的情况。
Figure 11-1 Multiple Executions of a Stored Procedure(图11-1 存储过程的多次执行)

程序代码程序代码...程序代码数据库应用程序hire_employees(...); ... hire_employees(...); ... hire_employees(...); 数据库存储过程BEGIN ... END;
或者,特权用户可以使用 Oracle Enterprise Manager 或 SQL*Plus,通过类似以下的语句来运行 hire_employees 过程:
sql
EXECUTE hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);
上述语句在 employees 表中为 TSMITH 插入一条新记录。
存储过程依赖于在其主体中引用的对象。数据库会自动跟踪和管理这些依赖关系。例如,如果您以会影响 hire_employees 过程的方式更改该过程引用的 employees 表的定义,则必须重新编译该过程以验证其是否仍按设计工作。通常,数据库会自动管理此类依赖关系。
另请参见
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》了解有关 SQL*Plus 和 SQL Developer 的更多信息
- 《Oracle AI 数据库开发指南》了解有关预编译器的更多信息
- 《Oracle AI 数据库 PL/SQL 语言参考》了解如何使用 PL/SQL 子程序
- 《SQL*Plus 用户指南和参考》了解
EXECUTE命令
PL/SQL Packages(PL/SQL 包)
PL/SQL 包是一组相关的子程序,连同它们使用的游标和变量,作为一个单元一起存储在数据库中以供持续使用。包中的子程序可以由应用程序或用户显式调用。
Oracle AI 数据库包含许多预置的包,这些包扩展了数据库功能,并提供了从 PL/SQL 访问 SQL 特性的能力。例如,UTL_HTTP 包允许从 PL/SQL 和 SQL 进行 HTTP 调用,以访问 Internet 上的数据或调用 Oracle Web Server Cartridges。您可以在创建应用程序时使用这些预置包,或者将其作为创建自己的存储过程时的思路来源。
-
Advantages of PL/SQL Packages(PL/SQL 包的优势)
PL/SQL 包为应用程序开发人员提供了许多优势。
-
Creation of PL/SQL Packages(PL/SQL 包的创建)
创建包分为两部分:规范和主体。包规范声明包的所有公共结构,而包主体定义包的所有结构(公共和私有)。
-
Execution of PL/SQL Package Subprograms(PL/SQL包子程序的执行)
数据库触发器、存储子程序、3GL 应用程序程序和 Oracle 工具都可以引用包的内容。
Advantages of PL/SQL Packages(PL/SQL 包的优势)
PL/SQL 包为应用程序开发人员提供了许多优势。
优势包括:
-
封装
包使您能够将存储过程、变量、数据类型等封装或分组到一个命名的存储单元中。封装在开发过程中提供了更好的组织,也提供了更大的灵活性。您可以在不实际创建包主体的情况下创建规范并引用公共过程。封装简化了权限管理。授予对包的权限可使得被授权者可以访问包的结构。
-
数据安全
包定义的方法使您能够指定哪些变量、游标和过程是公共的,哪些是私有的。公共意味着包的用户可以直接访问。私有意味着它对包的用户是隐藏的。
例如,一个包可以包含 10 个过程。您可以定义该包,使得只有三个过程是公共的,因此可供包的用户执行。其余过程是私有的,只能由包内的过程访问。不要将公共和私有包变量与对
PUBLIC的授予混淆。 -
更好的性能
当第一次调用包中的某个过程时,整个包会以小数据块的形式加载到内存中。此加载在一次操作中完成,而不是像独立的存储过程那样需要分别加载。当发生对相关包子程序的调用时,无需进行磁盘 I/O 即可运行内存中的已编译代码。
包主体可以被替换和重新编译,而不会影响其规范。因此,引用包结构(总是通过规范)的模式对象无需重新编译,除非包规范也被替换。通过使用包,可以最大限度地减少不必要的重新编译,从而减少对整体数据库性能的影响。
Creation of PL/SQL Packages(PL/SQL 包的创建)
创建包分为两部分:规范和主体。包规范声明包的所有公共结构,而包主体定义包的所有结构(公共和私有)。
以下示例显示了创建 employees_management 包的包规范的部分语句,该包封装了几个用于管理员工数据库的子程序。包的每一部分都使用不同的语句创建。
sql
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 数据库 PL/SQL 语言参考》了解 CREATE PACKAGE 语句
Execution of PL/SQL Package Subprograms(PL/SQL包子程序的执行)
数据库触发器、存储子程序、3GL 应用程序程序和 Oracle 工具都可以引用包的内容。
下图显示了数据库应用程序调用 employees_management 包中的过程和函数。
Figure 11-2 Calling Subprograms in a PL/SQL Package(图11-2 调用 PL/SQL 包中的子程序)

数据库应用程序employees_management 程序代码 ... employees_management.fire_employees(...); 程序代码 ... employees_management.hire_employees(...); ... 程序代码 ... 程序代码 ... employees_management.hire_employees(...); 程序代码 ... employees_management.salary_raise(...); ... 程序代码 ... 数据库BEGIN fire_employees(...) ... END; hire_employees(...) BEGIN ... END; salary_raise(...) BEGIN ... END;
数据库应用程序根据需要显式调用包子程序。在获得 employees_management 包的权限后,用户可以显式运行其中包含的任何过程。例如,SQL*Plus 可以发出以下语句来运行 hire_employees 包过程:
sql
EXECUTE employees_management.hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);
另请参见
- 《Oracle AI 数据库 PL/SQL 语言参考》了解 PL/SQL 包简介
- 《Oracle AI 数据库开发指南》了解如何编写 PL/SQL 包代码
PL/SQL Anonymous Blocks(PL/SQL 匿名块)
PL/SQL 匿名块是一个未命名的、非持久性的 PL/SQL 单元。
匿名块的典型用途包括:
- 发起对子程序和包结构的调用
- 隔离异常处理
- 通过在其他 PL/SQL 块中嵌套代码来管理控制
匿名块不具备存储子程序的代码重用优势。表 11-1 总结了两种 PL/SQL 单元类型之间的区别。
| 比较项目(Is the PL/SQL Unit ...) | 匿名块(Anonymous Blocks) | 子程序(Subprograms) |
|---|---|---|
| 指定了名称? | 否 | 是 |
| 每次重用时都编译? | 否 | 否 |
| 存储在数据库中? | 否 | 是 |
| 可通过其他应用程序调用? | 否 | 是 |
| 能够返回绑定变量值? | 是 | 是 |
| 能够返回函数值? | 否 | 是 |
| 能够接受参数? | 否 | 是 |
表 11-1 匿名块与子程序的区别
一个匿名块由一个可选的声明部分、一个可执行部分以及一个或多个可选的异常处理程序组成。以下示例匿名块将员工姓氏选择到一个变量中并打印该姓名:
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 数据库编译该 PL/SQL 块并将其放入 SGA 的共享池中,但它不会在数据库中存储源代码或编译版本以供当前实例之外重用。与触发器不同,匿名块每次加载到内存时都会被编译。共享 SQL 允许共享池中的匿名 PL/SQL 块被重用和共享,直到它们被从共享池中清除。
另请参见
《Oracle AI 数据库开发指南》了解有关匿名 PL/SQL 块的更多信息
PL/SQL Language Constructs(PL/SQL 语言结构)
PL/SQL 块可以包含各种不同的 PL/SQL 语言结构。
这些结构包括以下内容:
-
变量和常量
您可以在过程、函数或包中声明这些结构。您可以在 SQL 或 PL/SQL 语句中使用变量或常量来捕获或提供所需的值。
-
游标
您可以在过程、函数或包中显式声明游标,以便于对 Oracle AI 数据库数据进行面向记录的处理。PL/SQL 引擎也可以隐式声明游标。
-
异常
PL/SQL 允许您显式处理在处理 PL/SQL 代码期间出现的内部和用户定义的错误条件,称为异常。
PL/SQL 可以运行动态 SQL 语句,这些语句的完整文本直到运行时才知道。动态 SQL 语句存储在字符串中,这些字符串在运行时被输入到程序中或由程序构建。这种技术使您能够创建通用过程。例如,您可以创建一个操作某个表的过程,而该表的名称直到运行时才知道。
另请参见
- 《Oracle AI 数据库 PL/SQL 包和类型参考》了解有关动态 SQL 的详细信息
- 《Oracle AI 数据库 PL/SQL 包和类型参考》了解如何在
DBMS_SQL包中使用动态 SQL
PL/SQL Collections and Records(PL/SQL 集合与记录)
许多编程技术使用集合类型,如数组、袋、列表、嵌套表、集合和树。
为了支持数据库应用程序中的集合技术,PL/SQL 提供了 TABLE 和 VARRAY 数据类型。这些类型使您能够声明关联数组、嵌套表和可变大小数组。
-
Collections(集合)
PL/SQL 集合是一个有序的元素组,所有元素类型相同。
-
Records(记录)
PL/SQL 记录是一种复合变量,可以存储不同数据类型的数,类似于 C、C++ 或 Java 中的 struct 类型。记录对于保存来自表行或表行中某些列的数据非常有用。
Collections(集合)
PL/SQL 集合是一个有序的元素组,所有元素类型相同。
每个元素都有一个唯一的下标,用于确定其在集合中的位置。要创建集合,您首先定义一个集合类型,然后声明一个该类型的变量。集合的工作方式类似于大多数第三代编程语言中的数组。此外,集合可以作为参数传递。因此,您可以使用它们将数据列移入和移出数据库表,或在客户端应用程序和存储子程序之间移动。
Records(记录)
PL/SQL 记录是一种复合变量,可以存储不同数据类型的数,类似于 C、C++ 或 Java 中的 struct 类型。记录对于保存来自表行或表行中某些列的数据非常有用。
假设您有一些关于员工的数据,例如姓名、薪水和入职日期。这些项目在类型上不同,但在逻辑上是相关的。一个为每个项目包含一个字段的记录让您可以像处理逻辑单元一样处理这些数据。
您可以使用 %ROWTYPE 属性声明一个表示表行或从游标获取的行的记录。对于用户定义的记录,您可以声明自己的字段。
另请参见
《Oracle AI 数据库 PL/SQL 语言参考》了解如何使用 PL/SQL 记录
How PL/SQL Runs(PL/SQL 如何运行)
PL/SQL 同时支持解释执行和本机执行。
在解释执行中,PL/SQL 源代码被编译成所谓的字节码表示。一个作为 Oracle AI 数据库一部分实现的可移植虚拟计算机运行此字节码。
本机执行在计算密集型单元上提供最佳性能。在这种情况下,PL/SQL 单元的源代码被直接编译为给定平台的目标代码。此目标代码被链接到 Oracle AI 数据库中。
PL/SWL 引擎定义、编译和运行 PL/SQL 单元。此引擎是许多 Oracle 产品(包括 Oracle AI 数据库)的一个特殊组件。虽然许多 Oracle 产品都有 PL/SQL 组件,但本主题专门讨论可以存储在 Oracle AI 数据库中并使用 Oracle AI 数据库 PL/SQL 引擎处理的 PL/SQL 单元。每个 Oracle 工具的文档都描述了其 PL/SQL 功能。
下图说明了 Oracle AI 数据库中包含的 PL/SQL 引擎。
Figure 11-3 The PL/SQL Engine and Oracle AI Database(图11-3 PL/SQL 引擎与 Oracle AI 数据库)

数据库应用程序系统全局区 (SGA) 数据库实例 PL/SQL 引擎 SQL SQL 语句执行器过程语句执行器 程序代码... hire_employees(...); ... 程序代码 过程 BEGIN 过程化 SQL 过程化 SQL 过程化 SQL END;
PL/SQL 单元存储在数据库中。当应用程序调用存储过程时,数据库将编译后的 PL/SQL 单元加载到系统全局区(SGA)的共享池中。PL/SQL 和 SQL 语句执行器协同工作以处理过程中的语句。
您可以从另一个 PL/SQL 块中调用存储过程,该块可以是匿名块或另一个存储过程。例如,您可以从 Oracle Forms 调用存储过程。
在 Oracle AI 数据库上执行的 PL/SQL 过程可以调用用 C 编程语言编写并存储在共享库中的外部过程或函数。该 C 例程在与 Oracle AI 数据库不同的地址空间中运行。
另请参见
- "共享池"了解有关共享池的用途和内容的更多信息
- 《Oracle AI 数据库 PL/SQL 语言参考》了解 PL/SQL 架构
- 《Oracle AI 数据库开发指南》了解有关外部过程的更多信息
Overview of Java in Oracle AI Database(Oracle AI 数据库中的 Java 概述)
Java 已成为首选的面向对象编程语言。
Java 包含以下特性:
- Java 虚拟机(JVM),它为平台独立性提供了基础
- 自动存储管理技术,例如垃圾收集
- 借鉴了 C 语言并强制执行强类型化的语言语法
注意:本章假设您对 Java 语言有一定的了解。
数据库为 Java 程序提供了一个动态数据处理引擎,支持复杂查询和数据的多视图。客户端请求被组合成数据查询以便立即处理。查询结果是动态生成的。
Java 和 Oracle AI 数据库的结合帮助您创建基于组件的、以网络为中心的应用程序,这些应用程序可以随着业务需求的变化而轻松更新。此外,您可以将应用程序和数据存储从桌面转移到智能网络和以网络为中心的服务器上。更重要的是,您可以从任何客户端设备访问这些应用程序和数据存储。
下图显示了一个传统的两层客户机/服务器配置,其中客户端调用 Java 存储过程的方式与调用 PL/SQL 子程序相同。
Figure 11-4 Two-Tier Client/Server Configuration(图11-4 两层客户机/服务器配置)

客户端 Oracle Net Java 存储过程 PL/SQL 存储过程 关系数据 表 表 表 客户端 Oracle Net 客户端 Oracle Net
-
Overview of the Java Virtual Machine (JVM)(Java 虚拟机(JVM)概述)
JVM 是一个运行已编译 Java 代码的虚拟处理器。
-
Java Programming Environment(Java 编程环境)
Oracle 为企业应用程序开发人员提供了一个端到端的 Java 解决方案,用于创建、部署和管理 Java 应用程序。
另请参见
《Oracle AI 数据库 Java 开发入门》了解在 Oracle AI 数据库中使用 Java 的简介
Overview of the Java Virtual Machine (JVM)(Java 虚拟机(JVM)概述)
JVM 是一个运行已编译 Java 代码的虚拟处理器。
Java 源代码编译为称为字节码的低级机器指令,这些指令是平台独立的。Java 字节码通过 JVM 解释为平台相关的操作。
-
Overview of Oracle JVM(Oracle JVM 概述)
Oracle JVM 是一个标准的、与 Java 兼容的环境,可以运行任何纯 Java 应用程序。它符合 JLS 和 JVM 规范。
-
Main Components of Oracle JVM(Oracle JVM 的主要组件)
Oracle JVM 通过共享其内存堆并直接访问其关系数据,在与数据库内核相同的进程空间和地址空间中运行。这种设计优化了内存使用并提高了吞吐量。
Overview of Oracle JVM(Oracle JVM 概述)
Oracle JVM 是一个标准的、与 Java 兼容的环境,可以运行任何纯 Java 应用程序。它符合 JLS 和 JVM 规范.
Oracle JVM 支持标准的 Java 二进制格式和 API。此外,Oracle AI 数据库遵循标准的 Java 语言语义,包括运行时的动态类加载。
下图说明了 Oracle Java 应用程序如何驻留在 Java 核心类库之上,而后者又驻留在 Oracle JVM 之上。因为 Oracle Java 支持系统位于数据库内部,所以 JVM 与数据库库交互,而不是直接与操作系统交互。
Figure 11-5 Java Component Structure(图11-5 Java 组件结构)

数据/持久化逻辑 Oracle 数据库 JVM JDBC 驱动程序 Java 核心类库 Oracle 数据库库 操作系统
与其他 Java 环境不同,Oracle JVM 嵌入在 Oracle AI 数据库内部。Oracle JVM 与典型的客户端 JVM 之间存在一些重要的区别。例如,在标准 Java 环境中,您可以通过在命令行上发出以下命令来通过解释器运行 Java 应用程序,其中 classname 是 JVM 最先解释的类的名称:
java classname
上述命令使应用程序在您操作系统上的某个进程中运行。但是,如果您不使用命令行界面,则必须将应用程序加载到数据库中,发布接口,然后在数据库数据字典中运行该应用程序。
另请参见
请参阅《Oracle AI 数据库 Java 开发人员指南》了解 Oracle JVM 与典型客户端 JVM 之间其他区别的描述
Main Components of Oracle JVM(Oracle JVM 的主要组件)
Oracle JVM 通过共享其内存堆并直接访问其关系数据,在与数据库内核相同的进程空间和地址空间中运行。这种设计优化了内存使用并提高了吞吐量。
Oracle JVM 为 Java 对象提供了一个运行时环境。它完全支持 Java 数据结构、方法分派、异常处理和语言级线程。它还支持所有核心 Java 类库,包括 java.lang、java.io、java.net、java.math 和 java.util。
下图显示了 Oracle JVM 的主要组件。
Figure 11-6 Main Components of Oracle JVM(图11-6 Oracle JVM 的主要组件)

包含嵌入式 SQL 语句的源程序 Oracle 预编译器 所有 SQL 语句被库调用替换的源程序 编译器 目标程序 Oracle 运行时库 (SQLLIB) 链接器 可执行程序 主机程序编辑器
Oracle JVM 将标准 Java 命名空间嵌入到数据库模式中。此功能允许 Java 程序访问存储在 Oracle AI 数据库和整个企业中的应用服务器中的 Java 对象。
此外,Oracle JVM 与数据库的可伸缩共享内存架构紧密集成。Java 程序无需用户干预即可有效利用调用、会话和对象的生命周期。因此,Oracle JVM 和中间层 Java 业务对象可以实现伸缩,即使它们具有会话长状态。
另请参见
《Oracle AI 数据库 Java 开发人员指南》了解 Oracle JVM 主要组件的描述
Java Programming Environment(Java 编程环境)
Oracle 为企业应用程序开发人员提供了一个端到端的 Java 解决方案,用于创建、部署和管理 Java 应用程序。
该解决方案包括客户端和服务器端编程接口、支持 Java 开发的工具以及与 Oracle AI 数据库集成的 Java 虚拟机。所有这些产品都符合 Java 标准。
Java 编程环境包含以下附加功能:
-
Java 存储过程作为 PL/SQL 的 Java 等价物和伴侣。Java 存储过程与 PL/SQL 紧密集成。您可以从 PL/SQL 包和过程中调用 Java 存储过程,也可以从 Java 存储过程中调用 PL/SQL。
-
JDBC 和 SQLJ 编程接口,用于访问 SQL 数据。
-
协助开发、加载和管理类的工具和脚本。
-
Java Stored Procedures(Java 存储过程)
Java 存储过程是一个发布到 SQL 并存储在数据库中的 Java 方法。
-
Java and PL/SQL Integration(Java 与 PL/SQL 的集成)
您可以从 Java 调用现有的 PL/SQL 程序,也可以从 PL/SQL 调用 Java 程序。此解决方案保护并充分利用了您的 PL/SQL 和 Java 代码。
Java Stored Procedures(Java 存储过程)
Java 存储过程是一个发布到 SQL 并存储在数据库中的 Java 方法。
像 PL/SQL 子程序一样,Java 过程可以使用 SQL*Plus 等产品直接调用,或通过触发器间接调用。您可以从任何 Oracle Net 客户端(OCI、预编译器或 JDBC)访问它。
要发布 Java 方法,您需要编写调用规范,这些规范将 Java 方法名、参数类型和返回类型映射到它们对应的 SQL 形式。在被客户端应用程序调用时,Java 存储过程可以接受参数、引用 Java 类并返回 Java 结果值。
应用程序通过引用调用规范的名称来调用 Java 方法。运行时系统在 Oracle 数据字典中查找调用规范定义,并运行相应的 Java 方法。
此外,您可以使用 Java 独立于 PL/SQL 开发强大的程序。Oracle AI 数据库提供了 Java 编程语言和 JVM 的完全合规的实现。
另请参见
《Oracle AI 数据库 Java 开发人员指南》说明了如何用 Java 编写存储过程,如何从 PL/SQL 访问它们,以及如何从 Java 访问 PL/SQL 功能
Java and PL/SQL Integration(Java 与 PL/SQL 的集成)
您可以从 Java 调用现有的 PL/SQL 程序,也可以从 PL/SQL 调用 Java 程序。此解决方案保护并充分利用了您的 PL/SQL 和 Java 代码。
Oracle AI 数据库在客户端和服务器端都提供 JDBC,用于从 Java 访问 SQL 数据。
- JDBC Drivers(JDBC 驱动程序)
JDBC 是一种数据库访问协议,使您能够连接到数据库并运行 SQL 语句和查询。
JDBC Drivers(JDBC 驱动程序)
JDBC 是一种数据库访问协议,使您能够连接到数据库并运行 SQL 语句和查询。
核心 Java 类库仅提供一个 JDBC API,java.sql。然而,JDBC 被设计为使供应商能够提供为特定数据库提供必要专门化的驱动程序。Oracle 提供了下表中所示的不同 JDBC 驱动程序。
| 驱动程序(Driver) | 描述(Description) |
|---|---|
| JDBC 瘦驱动程序 | 您可以使用 JDBC 瘦驱动程序编写访问 Oracle SQL 数据的纯 Java 应用程序和小程序。JDBC 瘦驱动程序特别适合基于 Web 的应用程序和小程序,因为您可以像下载任何其他 Java 小程序一样,从 Web 页面动态下载它。 |
| JDBC OCI 驱动程序 | JDBC OCI 驱动程序访问 Oracle 特定的本机代码(即非 Java 代码)以及客户端或中间层上的库,与 JDBC 瘦驱动程序相比,它提供了性能提升,但代价是大小明显增大和需要客户端安装。 |
| JDBC 服务器端内部驱动程序 | 当 Java 代码在服务器上运行时,Oracle AI 数据库使用服务器端内部驱动程序。它允许在 Oracle JVM 中运行于服务器上的 Java 应用程序使用 JDBC 访问本地定义的数据,即同一系统上同一进程中的数据。由于它能够直接使用底层的 Oracle RDBMS 库,而无需在 Java 代码和 SQL 数据之间建立中间网络连接的开销,从而提高了性能。通过在服务器上支持相同的 Java-SQL 接口,Oracle AI 数据库不要求您在部署时重写代码。 |
表 11-2 JDBC 驱动程序
另请参见
- 《Oracle AI 数据库开发指南》了解 JDBC 概述
- 《Oracle AI 数据库 Java 开发入门》和《Oracle AI 数据库 JDBC 开发人员指南》
Overview of JavaScript in Oracle AI Database(Oracle AI 数据库中的 JavaScript 概述)
JavaScript 是当今最流行的编程语言之一。部署在 Linux x86-64 或 Linux aarch64 上的 Oracle AI 数据库将 JavaScript 添加到支持服务器端开发的语言列表中。
您可以在数据库中存储 JavaScript 模块,在数据所在的位置处理数据,这可能比客户端开发方法带来显著的改进。JavaScript 由多语言引擎(MLE)执行。
开发人员可以选择执行独立的 JavaScript 代码,或者将 JavaScript 代码作为模块原生地存储在数据库中。
-
Storing Business Logic as Modules in the Database(将业务逻辑作为模块存储在数据库中)
就像与客户端开发相关的 JavaScript 一样,代码可以以模块的形式存储在一起。
-
Dynamic Execution of JavaScript Code(JavaScript 代码的动态执行)
框架开发人员和任何希望执行独立 JavaScript 代码而无需将代码存储在数据库中的人,都可以利用
DBMS_MLE包及其子程序。 -
Inline JavaScript Stored Procedures(内联 JavaScript 存储过程)
内联的 MLE 调用规范将 JavaScript 代码直接嵌入到
CREATE FUNCTION和CREATE PROCEDUREDDL 中。
另请参见
《Oracle AI 数据库 JavaScript 开发人员指南》了解有关 Oracle AI 数据库中 JavaScript 支持的更多信息。
Storing Business Logic as Modules in the Database(将业务逻辑作为模块存储在数据库中)
就像与客户端开发相关的 JavaScript 一样,代码可以以模块的形式存储在一起。
具有 PL/SQL 背景的开发人员可以将 JavaScript 模块视为等效于 PL/SQL 包主体,但是用 JavaScript 编写的。在模块中声明的函数可以标记为导出或保持私有。
Oracle AI 数据库中的 JavaScript 符合 ECMAScript 2023 标准,并为开发人员提供了在数据库中存储业务逻辑的广泛可能性。
注意:另请参见:
- 《Oracle AI 数据库 JavaScript 开发人员指南》第 2 章,了解 MLE 模块的全面介绍。
- 《Oracle AI 数据库 JavaScript 开发人员指南》第 5 章,了解有关调用规范的详细信息。
以下是在 MLE 中创建 JavaScript 模块的示例:
sql
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() 的调用规范可以写成如下形式:
sql
create function if not exists p_string_to_JSON(p_str varchar2) return JSON
as mle module example_module
signature 'string2obj(string)';
/
创建该函数后,可以从 SQL 中调用它:
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.
Dynamic Execution of JavaScript Code(JavaScript 代码的动态执行)
框架开发人员和任何希望执行独立的 JavaScript 代码而无需将代码存储在数据库中的人,都可以利用 DBMS_MLE 包及其子程序。
例如,Oracle Application Express 和 Database Actions 集成了 DBMS_MLE,隐藏了在底层调用 PL/SQL 包的事实。
与 MLE 模块相比,使用 DBMS_MLE 会使得编写整个应用程序更加困难。例如,逻辑上更难将应用程序划分为独立实体。执行后调试功能需要使用模块,这使得排查代码片段中的问题更加困难。持续集成(CI)流水线也可能难以在同一文件中进行 PL/SQL 和 JavaScript 代码的静态检查。同样,您的集成开发环境(IDE)也可能存在潜在问题,因为大多数 IDE 都难以在同一窗口中同时处理 PL/SQL 和 JavaScript。
注意:另请参见:
- 《Oracle AI 数据库 PL/SQL 包和类型参考》了解有关
DBMS_MLE及其子程序的更多详细信息。- 《Oracle AI 数据库 JavaScript 开发人员指南》第 3 章,了解有关动态 JavaScript 调用的更多详细信息。
Inline JavaScript Stored Procedures(内联 JavaScript 存储过程)
内联的 MLE 调用规范将 JavaScript 代码直接嵌入到 CREATE FUNCTION 和 CREATE PROCEDURE DDL 中。
如果您想使用 JavaScript 快速实现简单的功能,内联 MLE 调用规范可能是一个不错的选择。使用此选项,您无需部署包含 JavaScript 代码的单独模块。相反,JavaScript 函数直接内置在调用规范的定义中。
MLE LANGUAGE 子句用于指定该函数是用 JavaScript 实现的。语言名称后面的字符串被视为实现调用规范功能的 JavaScript 函数体。当代码被执行时,PL/SQL 参数会自动转换为默认的 JavaScript 类型,并作为同名参数传递给 JavaScript 函数。请注意,未加引号的参数名称映射为全大写的 JavaScript 名称。JavaScript 函数返回的值将转换为 PL/SQL 调用规范的返回类型,就像处理 MLE 模块的调用规范一样。
注意:另请参见:
- 《Oracle AI 数据库 JavaScript 开发人员指南》第 5 章,了解有关内联 JavaScript 存储过程的更多详细信息。
Overview of Triggers(触发器概述)
数据库触发器是一个编译的存储程序单元,可以用 PL/SQL、Java 或 JavaScript 编写,Oracle 数据库在某些情况下会自动调用("触发")它。
只要发生以下任一操作,就会触发触发器:
-
任何用户对特定表或视图发出的 DML 语句
DML 语句修改模式对象中的数据。例如,插入和删除行都是 DML 操作。
-
由特定用户或任何用户发出的 DDL 语句
DDL 语句定义模式对象。例如,创建表和添加列都是 DDL 操作。
-
数据库事件
用户登录或注销、错误、数据库启动或关闭等都是可以调用触发器的事件。
触发器是与子程序相似的模式对象,但其调用方式不同。子程序由用户、应用程序或触发器显式运行。触发器在触发事件发生时由数据库隐式调用。
-
Advantages of Triggers(触发器的优势)
正确使用触发器使您能够构建和部署更健壮且更有效地使用数据库的应用程序。
-
Types of Triggers(触发器的类型)
可以根据调用方式及其执行的操作类型对触发器进行分类。
-
Timing for Triggers(触发器的时机)
您可以定义触发器时机------触发操作是在触发语句之前还是之后运行。
-
Creation of Triggers(触发器的创建)
CREATE TRIGGER语句创建或替换数据库触发器。 -
Execution of Triggers(触发器的执行)
Oracle 数据库使用与子程序执行相同的步骤在内部执行触发器。
-
Storage of Triggers(触发器的存储)
Oracle 数据库将 PL/SQL 触发器以编译形式存储在数据库模式中,就像 PL/SQL 存储过程一样。
另请参见
- "SQL 语句概述"了解 DML 和 DDL
- "数据库实例启动与关闭概述"
Advantages of Triggers(触发器的优势)
正确使用触发器使您能够构建和部署更健壮且更有效地使用数据库的应用程序。
您可以使用触发器来:
- 自动生成派生列值
- 防止无效事务
- 提供审计和事件记录
- 记录表访问信息
您可以使用触发器来强制执行所有客户端应用程序通用的低级业务规则。例如,多个应用程序可能访问 employees 表。如果此表上的一个触发器确保了插入数据的格式,那么此业务逻辑不需要在每个客户端中重现。因为触发器无法被应用程序绕过,所以触发器中的业务逻辑会自动被使用。
您可以使用触发器和完整性约束来定义和强制执行任何类型的完整性规则。但是,Oracle 强烈建议您仅使用触发器来强制执行无法使用完整性约束定义的复杂业务规则。
过度使用触发器可能导致复杂的相互依赖关系,这在大型应用程序中可能难以维护。例如,当调用触发器时,其触发操作中的 SQL 语句可能会触发其他触发器,从而导致级联触发器,这可能会产生意外效果。
另请参见
- "数据完整性简介"
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》
- 《Oracle AI 数据库 PL/SQL 语言参考》了解为应用程序规划触发器时的指南和限制
Types of Triggers(触发器的类型)
可以根据调用方式及其执行的操作类型对触发器进行分类。
Oracle 数据库支持以下类型的触发器:
-
行触发器
每次触发语句影响表时,行触发器都会触发。例如,如果一个语句更新多行,那么行触发器会为受到
UPDATE影响的每一行触发一次。如果触发语句未影响任何行,则不会运行行触发器。如果触发器操作中的代码依赖于触发语句提供的数据或受影响的行,则行触发器非常有用。 -
语句触发器
语句触发器代表触发语句触发一次,而不管触发语句影响了多少行。例如,如果一个语句从表中删除了 100 行,语句级
DELETE触发器只会触发一次。如果触发器操作中的代码不依赖于触发语句提供的数据或受影响的行,则语句触发器非常有用。 -
INSTEAD OF触发器Oracle 数据库触发
INSTEAD OF触发器,而不是执行触发语句本身。这些触发器对于透明地修改无法通过 DML 语句直接修改的视图非常有用。 -
事件触发器
您可以使用触发器向订阅者发布有关数据库事件的信息。事件触发器分为以下几类:
-- 系统事件触发器可以由诸如数据库实例启动和关闭或错误消息等事件引起。
-- 用户事件触发器由于与用户登录和注销、DDL 语句以及 DML 语句相关的事件而触发。
另请参见
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》
- 《Oracle AI 数据库 PL/SQL 语言参考》
Timing for Triggers(触发器的时机)
您可以定义触发器时机------触发操作是在触发语句之前还是之后运行。
简单触发器是表上的单个触发器,它使您能够为以下恰好一个时间点指定操作:
- 在触发语句之前
- 在触发语句影响的每一行之前
- 在触发语句影响的每一行之后
- 在触发语句之后
对于语句触发器和行触发器,BEFORE 触发器可以在对数据库进行更改之前增强安全性并启用业务规则。AFTER 触发器非常适合记录操作。
复合触发器可以在多个时间点触发。复合触发器有助于规划一种方法,使您为各个时间点实现的操作共享公共数据。
另请参见
《Oracle AI 数据库 PL/SQL 语言参考》了解复合触发器
Creation of Triggers(触发器的创建)
CREATE TRIGGER 语句创建或替换数据库触发器。
PL/SQL 触发器具有以下通用语法形式:
sql
CREATE TRIGGER trigger_name
triggering_statement
[trigger_restriction ]
BEGIN
triggered_action ;
END;
PL/SQL 触发器具有以下基本组件:
-
触发器名称
该名称在同一模式内的其他触发器名称中必须是唯一的。例如,名称可能是
part_reorder_trigger。 -
触发事件或语句
触发事件或语句是导致触发器被调用的 SQL 语句、数据库事件或用户事件。例如,用户更新了一个表。
-
触发器限制
触发器限制指定了一个布尔表达式,该表达式必须为真触发器才会触发。例如,除非可用零件数量少于当前的再订购数量,否则不会调用触发器。
-
触发操作
触发操作是包含 SQL 语句和代码的过程,当发出触发语句且触发器限制评估为真时运行。例如,用户向待处理订单表中插入一行。
-
Example: CREATE TRIGGER Statement(示例:CREATE TRIGGER 语句)
此示例创建一个触发器,当对
lineitems表执行INSERT、UPDATE或DELETE语句时,该触发器会触发。 -
Example: Invoking a Row-Level Trigger(示例:调用行级触发器)
在此场景中,客户发起两个订单,并从订单中添加和删除订单行项目。
另请参见
- 《Oracle AI 数据库 Oracle AI 数据库开发入门》和《Oracle AI 数据库 PL/SQL 语言参考》了解如何创建触发器
- 《Oracle AI 数据库 SQL 语言参考》了解
CREATE TRIGGER语句
Example: CREATE TRIGGER Statement(示例:CREATE TRIGGER 语句)
此示例创建一个触发器,当对 lineitems 表执行 INSERT、UPDATE 或 DELETE 语句时,该触发器会触发。
假设您使用以下语句创建 orders 和 lineitems 表。orders 表为每个唯一订单包含一行,而 lineitems 表为订单中的每个项目包含一行。
sql
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 表:
sql
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 表。
Example: Invoking a Row-Level Trigger(示例:调用行级触发器)
在此场景中,客户发起两个订单,并从订单中添加和删除订单行项目。
此场景基于在"示例:CREATE TRIGGER 语句"中创建的触发器。
| SQL 语句(SQL Statement) | 触发的 SQL 语句(Triggered SQL Statement) | 描述(Description) |
|---|---|---|
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 |
客户查询了两个订单的状态。两个订单都不包含行项目。 客户还查询了行项目的状态。不存在任何项目。 |
表 11-3 行级触发器场景
Execution of Triggers(触发器的执行)
Oracle 数据库使用与子程序执行相同的步骤在内部执行触发器。
唯一的细微差别是,如果用户账户具有运行触发语句的权限,则该账户有权触发触发器。除此例外,数据库验证和运行触发器的方式与存储子程序相同。
另请参见
《Oracle AI 数据库 PL/SQL 语言参考》了解有关触发器执行的更多信息
Storage of Triggers(触发器的存储)
Oracle 数据库将 PL/SQL 触发器以编译形式存储在数据库模式中,就像 PL/SQL 存储过程一样。
当 CREATE TRIGGER 语句提交时,编译后的 PL/SQL 代码被存储在数据库中。共享池会移除 PL/SQL 触发器的源代码。
下图显示了一个数据库应用程序,其中包含隐式调用 PL/SQL 触发器的 SQL 语句。触发器与它们关联的表分开存储。
Figure 11-7 Triggers(图11-7 触发器)

Oracle 数据库 数据字典 表 t Update 触发器 BEGIN ... Insert 触发器 BEGIN ... Delete 触发器 BEGIN ... 数据库应用程序 程序代码 ... UPDATE t SET ...; ... INSERT INTO t ...; ... DELETE FROM t ...;
Java 触发器的存储方式与 PL/SQL 触发器相同。但是,Java 触发器会引用使用 CALL 语句单独编译的 Java 代码。因此,创建 Java 触发器涉及创建 Java 代码和创建引用此 Java 代码的触发器。
另请参见
《Oracle AI 数据库 PL/SQL 语言参考》了解有关编译和存储触发器的信息