【php精品源码栏目提醒】:本文主要为网学会员提供“PHP中关于Oracle存储过程的应用介绍 - 讲义教程”,希望对需要PHP中关于Oracle存储过程的应用介绍 - 讲义教程网友有所帮助,学习一下!
PHP中关于Oracle存储过程的应用介绍 存储过程是实际位于 Oracle 中的程序。
大多数存储过程都是用 PL/SQL 编写的在 Oracle 数据库 10g 第 2 版和更高版本中您可以用 Java、.NET 或其他语言将它们编写为外部过程。
存储过程通常将一系列相关操作组成一个 API。
存储过程执行的操作包括由 SQL 语句以及 PL/SQL 语句执行的操作SQL 语句用于获取和修改数据PL/SQL 语句将对这些数据进行相应操作如执行某些数学运算、对值进行详细验证值以及处理错误条件。
它们降低了调用程序与数据库之间的“往返”次数并简化了客户端 中的数据管理逻辑从而有利于提高性能。
如果考虑一下管理表之间的多对多关系通常需要的代码则会发现对现有数据执行更新通常涉及三个不同的查询。
通过将该进程封装在单个存储过程中将减少客户端与数据库之间的通信量而通常需要在客户端代码分多个步骤执行的操作将减化为一个数据库调用。
PHP OCI8 扩展支持对存储过程的调用您可以将参数绑定到过程语句与将参数绑定到普通的 SQL 语句方法相同并可以访问结果游标和 Oracle 集合。
本方法文档中提供了存储过程的常见操作示例。
存储过程输入和输出 调用 Oracle 存储过程时所有输入和输出数据均以参数形式传递给过程。
如果您习惯于使用某些参数调用
PHP 函数并让它返回一个值的过程那么起初您可能对此感到有些迷惑不解但通过示例却可以一目了然。
假设有以下存储过程签名 sayHello name IN VARCHAR2 greeting OUT VARCHAR2 调用此过程时第一个参数名将包含一个在调用时提供的输入值而 greeting 将由该过程填充作为一个“返回”值在该过程完成后使用。
阅读规范 PL/SQL 编程不是本方法文档的范畴但您需要对存储过程有一个大致的了解并能够阅读接口规范但不必深究。
对于存储过程的源代码开始都需要先定义接受的参数例如 PROCEDURE edit_entry status_out OUT NUMBER status_msg_out OUT VARCHAR2 id_inout IN OUT INTEGER title_in IN VARCHAR2 text_out OUT CLOB categories_in IN list_of_numbers 该过程名为 edit_entry。
圆括号中定义了可以传递给该过程的各参数由逗号分隔。
每个参数中你会看到用于在该过程内部引用其值的名称不需要在
PHP 脚本中使用同一名称、参数的模式如下所示以及该参数的类型。
对于该示例中的第一个参数 status_out OUT NUMBER 内部名称为 status_out模式为 OUT类型为 NUMBER它是一个原生的 Oracle 数据类型。
后面有一个 id_inout 参数。
id_inout IN OUT INTEGER 它的模式为 IN OUT类型为 INTEGER。
最后是 categories_in 参数 categories_in IN list_of_numbers 此处的类型是由用户定义的稍后将对该类型进行详细介绍。
参数模式 参数模式描述了数据从调用方到过程的“流”向 IN – 该模式的参数由调用方提供。
OUT – 参数可以由过程分配值并返回至调用方。
IN OUT – 参数可以在两个“方向”使用即调用方可以为该参数提供值而过程也可以修改参数值。
参数项是必选项。
从
PHP 调用过程时必须将
PHP 变量绑定到它定义的所有参数。
您不必向
PHP 变量分配值即使它们是输入参数 – 如果未向标量类型分配值Oracle 将把它视为 NULL 值。
值得注意的是存储过程可以在 Oracle 中“重载”。
换言之可以有两个名称相同但参数签名不同的过程。
将依据
PHP 变量绑定到的参数的数目和类型来决定要调用哪个过程。
复杂类型 存储过程使用的参数并不只局限于 VARCHAR2 和 INTEGER 等标量类型。
也可以传递并接收复杂的数据类型如值列表或与从表中选择的行集相对应的结果游标。
一般说来如果存在要迭代的数据行则您将通常会收到从存储过程返回的游标而如果您需要传入值列表则通常将使用集合。
以下示例通过
PHP 演示了这些复杂类型。
调用方与定义方权限。
Oracle 对“调用方”执行存储过程的用户和定义方以其身份执行 CREATE PROCEDURE 语句的用户进行了区分。
默认情况下存储过程是以定义方的权限执行的即使调用方是不同的用户。
这意味着表的所有访问权限例如在过程中的访问权限将由定义方的权限控制因此调用方只需要执行过程的权限而非它使用的表的权限。
可以在过程定义中用关键字 AUTHID CURRENT_USER 更改此模型。
设置该指令后执行存储过程时所需的权限将在运行时依据执行该过程的当前用户来决定。
该方法的一个用途是测试一个修改表数据但实际上不修改实时数据的过程。
这种情况下调用方在他们自己的模式中定义一个表该表与从他们需要执行的过程中访问的表同名而过程依据本地表而非提供给定义方的表执行。
从
PHP 中调用存储过程 对于要从
PHP 中执行以调用过程的 SQL 语句而言您将通常在 Oracle BEGIN ...END 块称作匿名块中嵌入调用。
例如 Blog 示例程序包。
为演示调用存储过程方面的某些技巧您将在此处使用以下名为 blog 的程序包该程序包提供了一个 API用于获取和修改假设的网志应用程序中的条目。
程序包用于通过其自身的作用域将过程、函数和数据封装在其自身的命名空间内部并使它们独立于全局数 据库命名空间中的其他过程。
调用程序包中的过程时将使用句号来分隔程序包名称与过程名称。
可以使用以下语句指定 blog 程序包 CREATE OR REPLACE PACKAGE blog AS TYPE cursorType IS REF CURSOR RETURN blogsROWTYPE / Fetch the latest num_entries_in from the blogs table populating entries_cursor_out with the result / PROCEDURE latest num_entries_in IN NUMBER entries_cursor_out OUT cursorType / Edit a blog entry.If id_inout is NULL results in an INSERT otherwise attempts to UPDATE the existing blog entry. status_out will have the value 1 on success otherwise a negative number on failure with status_msg_out containing a description categories_in is a collection where list_of_numbers is described by TYPE list_of_numbers AS VARRAY50 OF NUMBER / PROCEDURE edit_entry status_out OUT NUMBER status_msg_out OUT VARCHAR2 id_inout IN OUT INTEGER title_in IN VARCHAR2 text_out OUT CLOB categories_in IN list_of_numbers END blog / 该程序包提供了两个过程blog.latest返回包含最新 num_entries 网志条目的结果游标和 blog.edit_entry允许插入新的网志条目以及修改现有的网志条目。
如果为 id_inout 参数提供值则该过程将尝试更新具有该 id 的相应网志条目。
否则它将插入一个新的网志条目并使用新行的主键填充 id_inout。
该过程还接受与网志条目的主体相对应的 CLOB 对象以及与该条目归档到的类别列表相对应的集合对象。
此处引用的集合类型 list_of_numbers 由以下语句定义 CREATE OR REPLACE TYPE list_of_numbers AS VARRAY50 OF NUMBER 下面显示了该程序包的主体。
您可以通过其中的注释了解它的功能而不必深入了解 PL/SQL CREATE OR REPLACE PACKAGE BODY blog AS /------------------------------------------------/ PROCEDURE latest num_entries_in IN NUMBER entries_cursor_out OUT cursorType AS BEGIN OPEN entries_cursor_out FOR SELECT FROM blogs WHERE rownum num_entries_in ORDER BY date_published DESC END latest /------------------------------------------------/ PROCEDURE edit_entry status_out OUT NUMBER status_msg_out OUT VARCHAR2 id_inout IN OUT INTEGER title_in IN VARCHAR2 text_out OUT CLOB categories_in IN list_of_numbers AS ENTRY_NOT_FOUND EXCEPTION entry_found INTEGER : 0 BEGIN / Default status to success / status_out : 1 / If id_inout has a value then attempt to UPDATE / IF id_inout IS NOT NULL THEN / Check the id exists - raise ENTRY_NOT_FOUND if not / SELECT COUNT INTO entry_found FROM blogs b WHERE b.id id_inout IF entry_found 1 THEN RAISE ENTRY_NOT_FOUND END IF / Update the blogs table returning the CLOB field / UPDATE blogs b SET b.title title_in b.text EMPTY_CLOB WHERE b.id id_inout RETURNING b.text INTO text_out / Remove any existing relationships to categories - new categories inserted below / DELETE FROM blogs_to_categories WHERE blog_id id_inout status_msg_out : Blog entry id_inout updated / id_inout was null so INSERT new record / ELSE INSERT INTO blogs b b.id b.title b.date_published b.text VALUES blog_id_seq.nextval title_in SYSDATE EMPTY_CLOB RETURNING b.id b.text INTO id_inout text_out status_msg_out : Blog entry id_inout inserted END IF / Now handle assignment to categories. Loop over the categories_in collection inserting the new category assignments / FOR i IN 1 .. categories_in.count LOOP INSERT INTO blogs_to_categories blog_idcategory_id VALUES id_inoutcategories_ini END LOOP status_msg_out : status_msg_out - added to categories_in.count categories EXCEPTION / Catch the exception when id_inout not found / WHEN ENTRY_NOT_FOUND THEN status_out : -1001 status_msg_out : No entry found in table blogs with id id_inout / Catch any other exceptions raised by Oracle / WHEN OTHERS THEN status_out : -1 status_msg_out : Error: TO_CHAR SQLCODE SQLERRM END edit_entry END blog / The underlying table structure the procedures are using is: CREATE SEQUENCE blog_id_seq INCREMENT BY 1 / CREATE TABLE blogs id NUMBER PRIMARY KEY title VARCHAR2200 date_published DATE text CLOB / CREATE SEQUENCE category_id_seq INCREMENT BY 1 CREATE TABLE categories id NUMBER PRIMARY KEY name VARCHAR230 UNIQUE / CREATE TABLE blogs_to_categories blog_id INTEGER NOT NULL REFERENCES blogsid category_id INTEGER NOT NULL REFERENCES categoriesid PRIMARY KEY blog_id category_id / 存储过程和引用游标 看一下 blog.latest 过程您将看到它返回一个用于迭代 blogs 表行的引用游标。
与直接从 SELECT 语句中访问行相比在
PHP 中使用游标需要两个额外的步骤。
第一步是使用 oci_new_cursor 函数该函数随后用于绑定到相应的参数在
PHP 中准备一个游标资源。
执行 SQL 语句后第二步是对游标资源调用 oci_execute。
以下
PHP 脚本演示了该过程 存储过程和 LOB Oracle Long 对象与存储过程之间可以进行相互传递方法与内部的 SQL 之间进行的相互传递几乎相同。
以下示例演示了如何使用 CLOB 调用 blog.edit_entry 过程。
该示例未向 id 参数分配值因此它相当于插入一个新的网志条目 正如该脚本所演示的关键问题是如何在使用 LOB 时处理事务。
由于更新 LOB 是一个分为两阶段的过程因此您在此处选择将所有事务处理委托给
PHP 脚本。
注意默认情况下Oracle 只允许在任何给定的会话中一次运行一个事务。
这意味着从
PHP 调用的过程中发出的 commit 或 rollback 语句将覆盖对 oci_commit 或 oci_rollback 的调用。
可以使用匿名事务使用位于过程定义内部的 pragma PRAGMA AUTONOMOUS_TRANSACTION 启用更改此行为。
例如您可以在从其他过程中调用的日志记录程序包中使用匿名事务使用这一方法您可以记录有关存储过程调用的信息而不会干扰正在会话中运行的事务。
存储过程和集合 集合是一种用于将复杂数据类型传递到存储过程中的机制。
在网志应用程序中可以将网志条目归档到多个分类中与“blogs”表和“categories”表之间的多对多关系相对应。
必须在数据库中全局定义 Oracle 中的集合类型在本示例中您将使用以下定义 CREATE OR REPLACE TYPE list_of_numbers AS VARRAY50 OF NUMBER 该定义允许您一次最多向 50 个类别分配一个网志条目方法是将该类型的实例传递给 blog.edit_entry 过程。
在
PHP 中集合由预定义的
PHP 类 OCI-Collection 表示。
可以通过调用 oci_new_collection 函数创建此类实例。
OCI-Collection 对象提供了以下方法 append将元素添加到集合末尾 assign从现有集合中将元素添加到某个集合 assignElem将值分配给集合并标识应将该元素置于的集合中的索引位置 free释放与集合句柄关联的资源 getElem从集合中的特殊索引位置检索元素 max返回集合中的最大元素数 size返回集合的当前大小 trim从集合末尾删除一些元素 此处您只希望使用 append 方法因此可以将类别 ID 列表附加到过程调用。
在以下示例中您将更新在前一个示例中创建的现有网志条目方法是将它的 ID 传递给 blog.edit_entry 过程以及类别 id 列表 结论 您现在已经了解了有关如何从
PHP 中调用存储过程既包括只涉及标量数据类型的简单过程也包含更复杂的使用 LOB、游标和集合的过程的示例。
还对存储过程的定义进行了足够的了解能读懂它们的 PL/SQL 规范这样您就可以从
PHP 中正确地调用它们并绑定相应的类
上一篇:
购物网站设计代码html
下一篇:
视觉素养教育对高中英语教学的影响