服务器端编程介绍
SELECT employee_id, department_id, last_name, salary FROM employees;
- 使用客户端编程, 将 SQL 语句嵌入到由过程化语言如 C、 C++、 或 Java 等编写的应用程序中可以将 SQL 语句置入到源代码中,并在编译之前将其提交给预编译器或 Java 翻译器。或者,您可以消除预编译步骤,而使用如 Java 数据库连接 (JDBC) 或 Oracle 调用接口 (OCI) 这样的 API , 使应用程序能够与数据库进行交互。
-
使用服务器端编程,开发驻留在数据库中的数据逻辑
应用程序可以显式地调用以 PL/SQL (发音为 P L sequel) 或 Java 编写的存储子程序(过程和函数)。您还可以创建一个触发器,它是一个存储在数据库中的命名程序单元, 在响应指定的事件时调用。
在 Oracle 数据库中可以使用以下语言来存储数据逻辑:
-
PL/SQL
PL/SQL 是 Oracle 数据库针对 SQL 的过程化扩展。 PL/SQL 与数据库集成, 支持所有 Oracle SQL 语句、 函数、 和数据类型。 由数据库 API 编写的应用程序, 可以调用 PL/SQL 存储子程序,或发送 PL/SQL 代码块到数据库以被执行。 -
Java
Oracle 数据库还对开发、 存储、 和部署 Java 应用程序提供支持。Java 存储子程序在数据库中运行, 并独立于在中间层上运行的程序。 Java 存储子程序使用与 PL/SQL 类似的运行模型来与 SQL 接口。
See Also:
-
"Client-Side Database Programming"了解如何在预编译器和 API 中嵌入 SQL
-
《Oracle Database 2 Day Developer's Guide》有关数据库应用程序开发的简介
-
《Oracle Database Development Guide》了解如何选择一个编程环境
PL/SQL 概述
PL/SQL 提供了一种服务器端的, 存储的过程化语言,它易于使用并与 SQL无缝集成, 而且健壮、可移植、 且安全。您可以使用被称为 PL/SQL 程序单元的过程化模式对象,来访问和操作数据库数据。
PL/SQL 程序单位一般分为如下几类:
- PL/SQL 子程序,它存储在数据库中,可以从应用程序按名称调用。当你创建一个子程序时,数据库解析该子程序,并将其已解析的表示形式存储在数据库中。您可以将一个子程序声明为一个过程或函数。
- PL/SQL 匿名块,它出现在您的应用程序中, 没有名字,也不存储在数据库中。在很多的应用程序中 , PL/SQL 块可以出现在任何 SQL 语句可以出现的地方。
另见:
-
《Oracle Database PL/SQL Language Reference》有关 PL/SQL 及其包的完整信息
PL/SQL 子程序
PL/SQL 子程序的优势
优势包括:
-
提高性能
- 相比发出一个个 SQL 语句,或将整个 PL/SQL 块的文本发送到数据库中, 应用程序必须通过网络发送的信息的量是很小的,因为信息只发送一次,并随后在使用时才调用它。
- 已编译形式的过程在数据库中是随时可用的, 所以在执行时不需要编译。
- 如果该过程已在 SGA 的共享池中,则数据库不需要从磁盘检索它, 就可以立即开始执行。
-
-
内存分配
因为存储过程利用了数据库的共享内存功能,由对多个用户执行的同一过程,数据库只须将该过程加载一次到内存中。 在多个用户间共享代码,使应用程序对数据库内存的要求大幅减少。 -
提高生产率
存储过程增加了开发生产率。通过围绕一组通用的过程来设计应用程序,您可以避免冗余编码。 例如,您可以编写过程,以处理 employees 表中的行。任何应用程序可以调用这些过程,而无需重写 SQL 语句。如果数据管理方法改变了,则只须修改过程, 而不必修改使用过程的应用程序。存储过程也许是实现代码重用的最好方式。 因为连接到数据库的任何客户端应用程序,无论它是用何种语言编写的, 都可以调用存储过程, 存储过程提供了在所有环境中最大的代码重用。 -
完整性
存储过程能改进您的应用程序完整性和一致性。通过围绕一组公用的过程开发应用程序,您可以减少编码错误的可能性。例如,您可以测试一个子程序, 来保证它将返回一个准确的结果, 验证后, 可以在任意数量的应用程序中重用它, 而无需重新测试。如果该过程所引用的数据结构改变了,则只须重新编译该过程。调用该过程的应用程序不需要修改。 -
定义者权限程序的安全性
存储过程有助于强制执行数据安全。 定义者权限过程按其所有者的权限来执行,而不是按当前用户的权限。因此,您可以通过让用户只通过按定义者权限运行的过程和函数来访问数据,以限制用户执行的数据库操作。
例如,您可以只授予用户访问更新表的过程的权限, 而不授予其访问表本身的权限。当用户调用该过程时,它按其所有者的权限运行。只有权运行该过程(但对其基础表不具有查询、 更新、 或删除权限)的用户可以调用该过程,但不能以除此之外的任何其他方式操作表数据。 -
继承权限与调用者权限过程的模式上下文
调用者权限过程以当前用户的权限在当前用户的模式中执行。换句话说, 调用者权限过程不依赖于特定用户或模式。 调用者权限过程调用使应用程序开发人员更易于集中处理应用程序逻辑, 但是其基础数据可能会分散到多个用户模式。例如, 一个 hr_manager 用户可以运行更新过程来更新在 hr.employees 表中的薪水,而一个 hr_clerk 用户运行相同的过程却只能更新地址数据。
另见:
-
《Oracle Database PL/SQL Language Reference》关于 PL/SQL 子程序的概述
-
《Oracle Database Security Guide》了解更多有关定义者和调用者权限
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 Database 2 Day Developer's Guide》了解如何创建子程序
-
《Oracle Database PL/SQL Language Reference》了解 CREATE PROCEDURE 命令
PL/SQL 子程序的执行
用户可以以多种方式交互式地执行子程序。
选项是:
-
使用 Oracle 工具, 如 SQL * Plus 或 SQL Developer
- 在一个数据库应用程序(如 Oracle Forms 或预编译器应用程序) 代码中显式调用它。
-
在另一个过程或触发器的代码中显式调用它
下图显示了调用 hire_employees 的不同数据库应用程序。
EXECUTE hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);
前面的语句在 employees 表中为 TSMITH 插入一条新记录。
另见:
-
"Tools for Database Developers"了解更多关于SQL*Plus和SQL Developer的信息
-
"Client-Side Database Programming"以了解有关预编译器的更多信息
-
《Oracle Database PL/SQL Language Reference》学习如何使用PL/SQL子程序
-
《SQL*Plus User's Guide and Reference》了解EXECUTE命令
PL/SQL 包
PL/SQL 包的优势
PL/SQL包为应用程序开发人员提供了许多优势。
优势包括:
-
封装
包使您能够封装或分组存储过程、 变量、 数据类型等等, 并存储为命名单元。封装为开发过程提供了更好地组织形式,也提供了更大的灵活性。您可以创建规范,只引用公共过程而无需实际创建包体。封装简化了权限管理。 对包进行授权, 使其结构元素可以由被授权者访问。 -
数据安全
定义包的方法使您能够指定哪些变量、 游标过程是公共的或私有的。公有的意味着包的用户可以直接访问它。私有的意味着它对于包的用户够是隐藏的。例如,一个包可能包含 10 个过程。您可以定义包,使其只有三个过程是公共的,且可由包的用户执行。 其余的过程是私有的, 且只可由包中的过程访问。不要将公有或私有的包变量与对 PUBLIC 的授权相混淆。 -
更好的性能
当包中的某个过程第一次被调用时, 整个包被加载到内存中。 这种加载在一个操作中完成,不同于加载多个独立过程需要分别加载。 当调用到包中的相关过程时,只需直接运行内存中的已编译代码, 而无需额外磁盘 I/O。包体可以被替换并重新编译,而不会影响其规范。 这样,(总是通过该规范)引用包的结构元素的模式对象不需要被重新编译,除非包规范也被替换了。通过使用包,可以将不必要的重新编译减小到最少,结果对数据库的总体性能影响就比较小。
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;
另见:
《Oracle Database PL/SQL Language Reference》了解 CREATE PACKAGE 命令
PL/SQL 包子程序的执行
下图显示了数据库应用程序调用 employees_management 包中的过程和函数。
EXECUTE employees_management.hire_employees ('TSMITH', 'CLERK', 1037, SYSDATE, 500, NULL, 20);
另见:
-
《Oracle Database PL/SQL Language Reference》有关 PL/SQL 包的简介
-
《Oracle Database Development Guide》了解如何编写 PL/SQL 包
PL/SQL 匿名块
匿名块是一个未命名的、 非持久化的 PL/SQL 单元。
-
启动调用子程序和包结构元素
-
隔离例外处理
-
通过在其他 PL/SQL 块中嵌套代码来管理控制
表 8-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 Database Development Guide》了解 PL/SQL 匿名块的更多信息
PL/SQL 语言结构
PL/SQL 块可以包括各种不同的 PL/SQL 语言结构。
这些结构包括:
-
变量和常量
您可以在过程、 函数、 或包内声明这些结构。 在你需要在 SQL 或 PL/SQL 语句中捕获或提供一个值时, 您可以使用变量或常量。 -
游标
您可以在过程、 函数、 或包中显式声明一个游标,以便对 Oracle 数据库数据进行面向记录的处理。 PL/SQL 引擎也可以隐式声明游标。 -
例外
PL/SQL 允许您显式处理例外,即在 PL/SQL 代码的处理过程中抛出的内部的或用户定义的错误。
另见:
-
《Oracle Database PL/SQL Packages and Types Reference》有关动态 SQL 的详细信息
-
《Oracle Database PL/SQL Packages and Types Reference》学习如何通过 DBMS_SQL包使用动态 SQL
PL/SQL 集合和记录
集合
集合是一组有序的、 具有相同类型的元素。
记录
另见:
《Oracle Database PL/SQL Language Reference》学习如何使用PL/SQL记录
PL/SQL 如何运行
PL/SQL 支持本地执行和解释执行。
本机执行为计算密集型程序单元提供了最佳性能,在这种情况下,PL/SQL 程序源代码被直接编译为给定平台的对象代码。该对象代码被链接到 Oracle 数据库中。
PL/SQL 引擎定义、 编译、 和运行 PL/SQL 程序单元。该引擎是包括数据库的许多 Oracle 产品中的一个特殊的组件。虽然许多 Oracle 产品都有 PL/SQL 组件,但本节专门介绍可以存储在数据库中,并使用 Oracle 数据库 PL/SQL 引擎处理的程序单元。每个Oracle工具的文档都描述了其PL/SQL功能。
下图说明了包含在 Oracle 数据库中的 PL/SQL 引擎。
另见:
-
"Shared Pool"以进一步了解共享池的用途和内容
-
《Oracle Database PL/SQL Language Reference》了解 PL/SQL 体系结构
-
《Oracle Database Development Guide》了解外部过程的详细信息
Oracle 数据库中的 Java 概述
Java 已成为面向对象的编程语言的选择。
Java 包括以下特性:
-
Java 虚拟机 (JVM), 提供了平台独立性的基础
-
自动化的存储管理技术,例如垃圾回收
-
从 C 语言借鉴的强类型语言语法
下图显示了传统的两层客户端/服务器配置, 客户端使用与调用 PL/SQL子程序相同的方式, 来调用 Java 存储过程。
另见:
《Oracle Database 2 Day + Java Developer's Guide》关于在 Oracle 数据库中使用Java 的简介
Java 虚拟机 (JVM) 的概述
JVM 是一个运行已编译 Java 代码的虚拟处理器。
Oracle JVM 概述
下图说明了 Oracle Java 应用程序如何驻留在 Oracle JVM 中的 Java 核心类库的基础上。 因为 Oracle Java 支持系统位于数据库内, 所以 JVM 是与数据库的库文件交互, 而不是直接与操作系统交互的。
java classname
另见:
见《Oracle Database Java Developer’s Guide》关于 Oracle JVM 和典型的客户端 JVM 之间的其他差异的描述
Oracle JVM 的主要组件
Oracle JVM 通过共享其内存堆, 并直接访问其关联数据,与数据库内核运行在同一个进程空间。这种设计优化了内存使用并提高了吞吐量。
下图显示 Oracle JVM 的主要组件。
另见:
《Oracle Database Java Developer’s Guide》关于 Oracle JVM 的主要部件的描述
Java 编程环境
Java 编程环境还包括以下额外功能:
- Java 存储过程类似于 Java,经常和 PL/SQL 配合使用。 Java 存储过程与 PL/SQL 紧密集成。您可以从 PL/SQL 包调用 Java 存储过程,或从 Java 存储过程调用 PL/SQL 存储过程。
-
用于访问 SQL 数据的 SQLJ 和 JDBC 编程接口。
-
用于辅助开发、 加载、 和管理 Java 类的工具和脚本。
Java 存储过程
Java 存储过程是一个发布到 SQL、 并存储在数据库中的 Java 方法。
另见:
《Oracle Database Java Developer’s Guide》说明了如何在 Java 中编写存储过程、 如何从 PL/SQL 访问它们、 以及如何从 Java 访问 PL/SQL 功能
Java 和 PL/SQL 集成
JDBC 驱动程序
表 8-2 JDBC 驱动程序
驱动程序 | 描述 |
---|---|
JDBC Thin 驱动程序 |
你可以使用 JDBC Thin 驱动程序来编写纯 Java 应用程序和访问 Oracle SQL 数据的小程序。 JDBC 瘦驱动程序特别适合基于 Web 的应用程序和小程序,因为您可以从 Web 页动态地下载它,与下载任何其他 Java 小程序类似。
|
JDBC OCI 驱动程序 |
JDBC OCI 驱动程序访问特定于 Oracle 的本地代码(即: 非 Java 的代码) 和客户端或中间层上的库,相比 JDBC 瘦驱动程序, 提供了性能的提升,其代价是尺寸明显变大,且需要客户端安装。
|
JDBC 服务器端内部驱动程序 |
当 Java 代码在服务器上运行时, Oracle 数据库使用服务器端内部驱动程序。它允许 Java 应用程序在服务器上的 Oracle JVM 中运行,以访问在本地定义的数据,即与 JDBC 在同一系统上,且在同一进程中的数据。 由于具有使用底层的 Oracle RDBMS 库的能力,而没有 Java 代码和 SQL 数据之间网络连接的开销,其性能大大提高。通过在服务器上支持相同的 Java-SQL 接口, Oracle 数据库不需要你重新编码代码来部署它。
|
数据库触发器是一个已编译的存储程序单元,使用 PL/SQL 或 Java 编写,Oracle数据库在某些情况下会自动调用(“触发”)。
每当发生下列操作之一时,触发器就会触发:
-
由任何用户在一个特定的表或视图上,发出 DML 语句
DML 语句修改模式对象中的数据。例如, 插入和删除行即是 DML 操作。 -
由任何用户或特定用户发出 DDL 语句
DDL 语句定义模式对象。例如, 创建表并添加一列即是 DDL 操作。
-
数据库事件
用户登录或注销、 错误、 和数据库启动或关闭, 是触发器可以调用的事件。
另见:
触发器的优势
您可以使用触发器:
-
自动生成派生列中的值
-
防止无效事务
-
提供审计和事件日志记录
-
记录有关访问表的信息
另见:
-
《Oracle Database PL/SQL Language Reference》用于规划应用程序触发器时的指导原则和限制
触发器类型
触发器可以根据其调用方式和他们所执行的操作类型进行分类。
-
行触发器
行触发器在表每次受到触发语句影响时触发。例如。 如果一个语句更新多个行, 则行触发器为受 UPDATE 影响的每一行触发一次。如果触发语句未影响任何行,则行触发器不会运行。如果触发器操作中的代码依赖于触发语句提供的数据或受影响的行,则行触发器是有用的。 -
语句触发器
语句触发器针对触发语句只触发一次, 而无论受触发语句影响的行数。例如, 如果一个语句从表中删除 100 行, 语句级 DELETE 触发器仅触发一次。 如果触发器操作中的代码并不依赖触发语句所提供的数据或受影响的行,则语句触发器是有用的。 -
INSTEAD OF 触发器
数据库会触发 INSTEAD OF 触发器,而不是执行触发语句。这些触发器可用于透明地修改不能直接通过 DML 语句修改的视图。 -
事件触发器
您可以使用触发器将有关数据库事件的信息发布到订阅服务器。事件触发器可分为以下几类:- 系统事件触发器可以由诸如数据库实例启动和关闭或错误消息之类的事件引起。
- 用户事件触发器会因为与用户登录和注销、 DDL 语句、 和DML 语句等相关的事件而激发。
-
触发时间
-
触发语句之前
-
在受触发语句影响的每行之前
-
在受触发语句影响的每行之后
-
触发语句之后
另见:
创建触发器
使用 CREATE TRIGGER 语句创建或替换数据库触发器。
CREATE TRIGGER trigger_name
triggering_statement
[trigger_restriction]
BEGIN
triggered_action
END;
PL/SQL 触发器具有以下基本组件:
-
触发器名称
在相同的模式中,触发器的名称必须是唯一的。 例如,名称可能是 part_reorder_trigger。 -
触发事件或语句
触发事件或语句是导致触发器被调用的 SQL 语句、 数据库事件、 或用户事件。例如, 用户更新一个表。 -
触发器限制
触发器限制指定一个布尔表达式,其值必须为 true , 触发器才会触发。 例如,某触发器仅当可用部件的数量不足订购量时才触发。 -
触发的操作
触发的操作是包含 SQL 语句和代码的过程,当发出一个触发语句、且触发器限制的计算结果为 true 时将被运行。例如, 用户向待办订单表中插入行。
另见:
-
《Oracle Database 2 Day Developer's Guide》和《Oracle Database PL/SQL Language Reference》了解如何创建触发器
-
《Oracle Database SQL Language Reference》了解 CREATE TRIGGER 命令
例: 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 表中更新计数值。
例: 调用行级触发器
在此场景中,客户发起两个订单,并从订单中添加和删除行项目。
该场景基于Example: CREATE trigger语句中创建的触发器。
表 8-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 数据库在内部使用与执行子程序相同的步骤来执行触发器。
另见:
《Oracle Database PL/SQL Language Reference》了解触发器执行的更多信息
触发器存储
下图显示了一个数据库应用程序,其中的一个 SQL 语句隐式调用了 PL/SQL 触发器。触发器与其相关联的表是分开存储的
另见:
《Oracle Database PL/SQL Language Reference》了解编译和存储触发器