Oracle PL/SQL 对象类型教程(附示例)
PL/SQL 中的对象类型是什么?
面向对象编程特别适合构建可重复使用的组件和复杂应用程序。它们围绕“对象”而不是“操作”进行组织,即程序旨在与整个对象而不是单个操作一起工作和交互。此概念允许程序员在对象实体级别填充和操作细节。
下图描述了对象类型的示例,其中银行账户被视为对象实体。对象属性包括持有某些属性值的事物,例如银行账户;它是帐号、银行余额等,而对象方法描述了诸如计算利率、生成银行对账单等需要完成某些流程的事物。
在 PL/SQL 中,面向对象编程基于对象类型。
对象类型可以表示任何现实世界的实体。我们将在本章中讨论更多对象类型。
对象类型的组成部分
PL / SQL 对象类型主要包含两个组件。
- Attributes
- 成员/方法
Attributes
属性是存储数据的列或字段。每个属性都将映射到定义该属性的处理和存储类型的数据类型。属性可以是任何有效的 PL/SQL 数据类型,也可以是其他对象类型。
成员/方法
成员或方法是在对象类型中定义的子程序。它们不用于存储任何数据。它们主要用于定义对象类型内部的过程。例如,在填充对象类型之前验证数据。它们在对象类型部分中声明,并在对象类型的对象类型主体部分中定义。对象类型中的主体部分是可选部分。如果没有成员,则对象类型将不包含主体部分。
在中创建对象 Oracle
对象类型不能在子程序级别创建,只能在架构级别创建。一旦在架构中定义了对象类型,就可以在子程序中使用相同的对象类型。可以使用“CREATE TYPE”创建对象类型。只有在创建对象类型后才能创建类型主体。
CREATE TYPE<object_type_name> AS OBJECT ( <attribute_l><datatype>, . . ); / CREATE TYPE BODY<object_type_name> AS OBJECT ( MEMBER[PROCEDURE|FUNCTION]<member_name> IS <declarative section> BEGIN <execution part> END; . . ); /
语法解释:
- 上述语法显示了创建具有属性的“OBJECT”和创建具有方法的“OBJECT-BODY”。
- 方法也可以在对象体中重载。
对象类型的声明初始化
与 PL/SQL 中的其他组件一样,对象类型在程序中使用之前也需要声明。
一旦创建了对象类型,就可以在子程序声明部分中使用它来声明该对象类型的变量。
每当子程序中将任何变量声明为对象类型时,运行时都会创建该对象类型的一个新实例,并且这个新创建的实例可以引用变量名。通过这种方式,单个对象类型可以在不同的实例下存储多个值。
DECLARE <variable_name> <object_type_name>; BEGIN . . END; /
语法解释:
- 上述语法显示在声明部分中将变量声明为对象类型。
一旦变量在子程序中被声明为对象类型,它将原子地为空,即整个对象本身为空。它需要用值初始化才能在程序中使用它们。它们可以使用构造函数进行初始化。
构造函数是对象的隐式方法,可以使用与对象类型相同的名称引用。以下语法显示了对象类型的初始化。
DECLARE <variable_name> <object_type_name>; BEGIN <variable_name>:=<object_type_name>(); END; /
语法解释:
- 上述语法显示使用空值初始化对象类型实例。
- 现在对象本身不为空,因为它已被初始化,但是对象内部的属性将为空,因为我们没有为这些属性分配任何值。
构造函数
构造函数是对象的隐式方法,可以使用与对象类型相同的名称来引用。每当第一次引用该对象时,都会隐式调用此构造函数。
我们也可以使用这些构造函数来初始化对象。可以通过在对象类型主体中定义与对象类型同名的成员来明确定义构造函数。
例子1:在下面的例子中,我们将使用对象类型成员将记录插入到 emp 表中,其值为 ('RRR', 1005, 20000, 1000) 和 ('PPP', 1006, 20000, 1001)。插入数据后,我们将使用对象类型成员显示相同的数据。我们还将使用显式构造函数默认使用第二条记录的 1001 值填充经理 ID。
我们将按照以下步骤执行它。
- 第一步:
- 创建对象类型
- 对象类型主体
- 步骤2:创建一个匿名块,通过 emp_no 1005 的隐式构造函数调用创建的对象类型。
- 步骤3:创建一个匿名块,通过emp_no 1006 的显式构造函数调用创建的对象类型。
步骤1) 创建对象类型和对象类型主体
CREATE TYPE emp_object AS OBJECT( emp_no NUMBER, emp_name VARCHAR2(50), salary NUMBER, manager NUMBER, CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER, p_emp_name VARCHAR2, p_salary NUMBER) RETURN SELF AS RESULT), MEMBER PROCEDURE insert_records, MEMBER PROCEDURE display_records); /
CREATE OR REPLACE TYPE BODY emp_object AS CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER,p_emp_name VARCHAR2, p_salary NUMBER) RETURN SELF AS RESULT IS BEGIN Dbms_output.put_line(’Constructor fired..'); SELF.emp_no:=p_emp_no;| SELF.emp_name:=p_emp_name; SELF.salary:=p_salary; SELF.managerial:=1001; RETURN; END: MEMBER PROCEDURE insert_records IS BEGIN INSERT INTO emp VALUES(emp_noemp_name,salary,manager); END MEMBER PROCEDURE display_records IS BEGIN Dbms_output.put_line('Employee Name:'||emp_name); Dbms_output.put_line('Employee Number:'||emp_no); Dbms_output.put_line('Salary':'||salary); Dbms_output.put_line('Manager:'||manager); END: END: /
代码说明
- 代码行 1-9:创建具有 4 个属性和 3 个成员的“emp_object”对象类型。它包含仅具有 3 个参数的构造函数的定义。(实际隐式构造函数将包含与对象类型中存在的属性数量相等的参数数量)
- 代码行 10:创建类型主体。
- 代码行 11-21:定义显式构造函数。将参数值分配给属性,并为属性“manager”分配默认值“1001”。
- 代码行 22-26:定义成员“insert_records”,其中属性值插入到“emp”表中。
- 代码行 27-34:定义成员“display_records”,其中显示对象类型属性的值。
输出
创建类型
类型主体已创建
步骤2) 创建匿名块以通过 emp_no 1005 的隐式构造函数调用创建的对象类型
DECLARE guru_emp_det emp_object; BEGIN guru_emp_det:=emp_object(1005,’RRR',20000,1000); guru_emp_det.display_records; guru_emp_det.insert_records; COMMIT; END;
代码说明
- 代码行 37-45:使用隐式构造函数插入记录。对构造函数的调用包含属性值的实际数量。
- 代码行 38:将 guru_emp_det 声明为“emp_object”的对象类型。
- 代码行 41:语句“guru_emp_det.display_records”调用“diplay_records”成员函数并显示属性值
- 代码行 42:语句“guru_emp_det.insert_records”调用“insert_records”成员函数并将属性值插入到表中。
输出
员工姓名:RRR
员工数量:1005
薪水:S$20000
经理:1000
步骤3) 创建匿名块以通过 emp_no 1006 的显式构造函数调用创建的对象类型
DECLARE guru_emp_det emp_object; BEGIN guru_emp_det:=emp_object(1006,'PPP',20000); guru_emp_det.display_records; guru_emp_det.insert_records; COMMIT; END; /
输出
Employee Name:PPP Employee Number:1006 Salary:20000 Manager:1001
代码说明:
- 代码行 46-53:使用显式构造函数插入记录。
- 代码行 46:将 guru_emp_det 声明为“emp_object”的对象类型。
- 代码行 50:语句“guru_emp_det.display_records”调用“display_records”成员函数并显示属性值
- 代码行 51:语句“guru_emp_det.insert_records”调用“insert_records”成员函数并将属性值插入到表中。
对象类型的继承
继承属性允许子对象类型访问超对象类型或父对象类型的所有属性和成员。
子对象类型称为继承对象类型,超级对象类型称为父对象类型。以下语法显示如何创建父对象类型和继承对象类型。
CREATE TYPE <object_type_name_parent> AS OBJECT ( <attribute_l><datatype>, . . )NOT FINAL; /
语法解释:
- 上述语法显示了 SUPER 类型的创建。
CREATE TYPE<object_type_name_sub>UNDER<object_type_name_parent> ( <attribute_l><datatype>, . ); /
语法解释:
- 上述语法显示了 SUB 类型的创建。它包含父对象类型的所有成员和属性。
Example1: 在下面的例子中,我们将使用继承属性将经理 ID 为“1002”的记录插入到以下记录中(‘RRR’,1007,20000)。
我们将按以下步骤执行上述程序
- 步骤1:创建SUPER类型。
- 步骤2:创建SUB类型和主体。
- 步骤3:创建一个匿名块来调用SUB类型。
步骤1) 创建 SUPER 类型或 Parent 类型。
CREATE TYPE emp_object AS OBJECT( emp_no NUMBER, emp_name VARCHAR2(50), salary NUMBER, manager NUMBER, CONSTRUCTOR FUNCTION emp_object(p_emp_no NUMBER,p_emp_name VARCHAR2(50), p_salary NUMBER)RETURN SELF AS RESULT), MEMBER PROCEDURE insert_records, MEMBER PROCEDURE display_records)NOT FINAL; /
代码说明:
- 代码行 1-9:创建具有 4 个属性和 3 个成员的“emp_object”对象类型。它包含仅具有 3 个参数的构造函数的定义。它已被声明为“NOT FINAL”,因此它是父类型。
步骤2) 在 SUPER 类型下创建 SUB 类型。
CREATE OR REPLACE TYPE sub_emp_object UNDER emp_object (default_manager NUMBER,MEMBER PROCEDURE insert_default_mgr); / CREATE OR REPLACE TYPE BODY sub_emp_object AS MEMBER PROCEDURE insert_default_mgr IS BEGIN INSERT INTO emp VALUES(emp_no,emp_name:salary,manager): END; END; /
代码说明:
- 代码行 10-13:创建 sub_emp_object 作为继承类型,并附加一个属性“default_manager”和成员过程声明。
- 代码行 14:为继承的对象类型创建主体。
- 代码行 16-21:定义成员程序,该程序使用来自“SUPER”对象类型的值(经理值除外)将记录插入“emp”表。对于经理值,它使用来自“SUB”类型的“default_manager”。
步骤3) 创建匿名块来调用 SUB 类型
DECLARE guru_emp_det sub_emp_object; BEGIN guru_emp_det:= sub_emp_object(1007,'RRR',20000,1000,1002); guru_emp_det.insert_default_mgr; COMMIT; END; /
代码说明:
- 代码行 25:将“guru_emp_det”声明为“sub_emp_object”类型。
- 代码行 27:使用隐式构造函数初始化对象。构造函数有 5 个参数(4 个来自 PARENT 类型的属性和 2 个来自 SUB 类型的属性)。最后一个参数 (1002) 定义 default_manager 属性的值
- 代码行 28:调用成员“insert_default_mgr”来插入构造函数中传递的带有默认管理器id的记录。
PL/SQL 对象的相等性
可以比较属于同一对象的对象实例是否相等。为此,我们需要在对象类型中使用称为“ORDER”方法的特殊方法。
此 'ORDER' 方法应为返回数值类型的函数。它需要两个参数作为输入,(第一个参数:自身对象实例的 id,第二个参数:另一个对象实例的 id)。
对两个对象实例的id进行比较,并以数值形式返回结果。
- 正值表示 SELF 对象实例大于另一个实例。
- 负值表示 SELF 对象实例小于另一个实例。
- 零表示 SELF 对象实例等于另一个实例。
- 如果任何实例为空,则此函数将返回空。
CREATE TYPE BODY<object_type_name_ 1>AS OBJECT ( ORDER MEMBER FUNCTION match(<parameter> object_type_name_ 1) RETURN INTEGER IS BEGIN IF <attribute_name>parameter <attribute_name>THEN RETURN -1; --any negative number will do ELSIF id>c.id THEN RETURN 1; —any positive number will do ELSE RETURN 0; END IF; END; . . ); /
语法解释:
- 上述语法显示了需要包含在类型主体中以进行相等性检查的 ORDER 函数。
- 该函数的参数应该是同一对象类型的实例。
- 上述函数可以调用为“obj_instance_1.match(obj_instance_2)”,该表达式将返回如图所示的数值,其中 obj_instance_1 和 obj_instance_2 是 object_type_name 的实例。
例1:在下面的例子中,我们将了解如何比较两个对象。我们将创建两个实例,并比较它们之间的属性“薪水”。我们将执行两个步骤。
- 步骤1:创建对象类型和主体。
- 第 2 步:创建匿名块来调用比较对象实例。
步骤1) 创建对象类型和主体。
CREATE TYPE emp_object_equality AS OBJECT( salary NUMBER, ORDER MEMBER FUNCTION equals(c emp_object_equality)RETURN INTEGER); /
CREATE TYPE BODY emp_object_equality AS ORDER MEMBER FUNCTION equals(c emp_object_equality)RETURN INTEGER IS BEGIN IF salary<c.salary THEN RETURN -1; ELSIF salary>c.salary THEN RETURN 1; ELSE RETURN 0; END IF: END; END; /
代码说明:
- 代码行1-4: 创建具有 1 个属性和 1 个成员的“emp_object_equality”对象类型。
- 代码行 6-16:定义 ORDER 函数,比较 SELF 实例和参数实例类型的“salary”属性。如果 SELF 薪水较小,则返回负数;如果 SELF 薪水较大,则返回正数;如果薪水相等,则返回 0。
代码输出:
创建类型
步骤2) 创建匿名块来调用比较对象实例。
DECLARE l_obj_l emp_object_equality; l_obj_2 emp_object_equality; BEGIN l_obj_l:=emp_object_equality(15000); l_obj_2:=emp_object_equality(17000); IF l_obj_1.equalS(l_obj_2)>0 THEN Dbms_output.put_line(’Salary of first instance is greater’): ELSIF l_obj_l.equalS(l_obj_2)<0 THEN Dbms_output.put_line(’Salary of second instance is greater’); ELSE Dbms_output.put_line(’Salaries are equal’); END IF; END; /
输出
Salary of second instance is greater
代码说明:
- 代码行 20:声明 emp_object_equality 类型的 l_obj_1。
- 代码行 21:声明 emp_object_equality 类型的 l_obj_2。
- 代码行 23:将 l_obj_1 初始化为薪资值“15000”
- 代码行 24:将 l_obj_1 初始化为薪资值“17000”
- 代码行 25-33:根据ORDER函数的返回数字打印消息。
总结
在本章中,我们了解了对象类型及其属性。我们还讨论了 PL/SQL 对象中的构造函数、成员、属性、继承和相等性。