分类:
2008-05-19 16:14:57
构建客户端
现在,您已经针对 ORDERS 和 ORDER_ITEMS 表创建了注册,下面我们将了解一下访问这些表中存储的订单及其订单项的客户端应用程序如何使用更改通知。为此,您可以构建一个 应用程序,它将缓存针对以上表的查询结果,并采取相应的操作来响应有关对这些表所做更改的通知(从服务器中收到这些通知)。一个简单的方法是使用 PEAR::Cache_Lite 程序包,它为您提供了一个可靠的机制来使缓存数据保持最新状态。尤其是,您可以使用 Cache_Lite_Function 类(PEAR::Cache_Lite 程序包的一部分),通过该类您可以缓存函数调用。
例如,您可以创建一个函数来执行下列任务:建立数据库连接、针对该数据库执行 select 语句、获取检索结果并最终以数组形式返回结果。然后,您可以通过 Cache_Lite_Function 实例的 call 方法缓存由该函数返回的结果数组,以便可以从本地缓存而不是从后端数据库读取这些数组,这样可以显著提高应用程序的性能。然后,在收到缓存数据更改的通知时,您将使用 Cache_Lite_Function 实例的 drop 方法删除缓存中的过期数据。
回过头来看看本文的示例,您可能要创建两个函数,用于应用程序与数据库交互:第一个函数将查询 ORDERS 表并返回具有指定 ID 的订单,而另一个函数将查询 ORDER_ITEMS 表并返回该订单的订单项。“清单 4”显示了包含 getOrderFields 函数(该函数接受订单 ID 并返回一个包含所检索到订单的某些字段的关联数组)的 getOrderFields.php 脚本。
清单 4. 获取指定订单的字段
<?php“清单 5”是 getOrderItems.php 脚本。该脚本包含 getOrderItems 函数,该函数接受订单 ID 并返回一个二维数组,该数组包含表示订单的订单项的行。
//File:getOrderFields.php
require_once 'connect.php';
function getOrderFields($order_no) {
if (!$rsConnection = GetConnection()){
return false;
}
$strSQL = "SELECT TO_CHAR(ORDER_DATE) ORDER_DATE, CUSTOMER_ID,
ORDER_TOTAL FROM ORDERS WHERE order_id =:order_no";
$rsStatement = oci_parse($rsConnection,$strSQL);
oci_bind_by_name($rsStatement, ":order_no", $order_no, 12);
if (!oci_execute($rsStatement)) {
$err = oci_error();
print $err['message'];
trigger_error('Query failed:' . $err['message']);
return false;
}
$results = oci_fetch_assoc($rsStatement);
return $results;
}
?>
<?php注意,以上两个函数都需要 connect.php 脚本,该脚本应包含返回数据库连接的 GetConnection 函数。清单 6 就是 connect.php 脚本:
//File:getOrderItems.php
require_once 'connect.php';
function getOrderItems($order_no) {
if (!$rsConnection = GetConnection()){
return false;
}
$strSQL = "SELECT * FROM ORDER_ITEMS WHERE
order_id =:order_no ORDER BY line_item_id";
$rsStatement = oci_parse($rsConnection,$strSQL);
oci_bind_by_name($rsStatement, ":order_no", $order_no, 12);
if (!oci_execute($rsStatement)) {
$err = oci_error();
trigger_error('Query failed:' . $err['message']);
return false;
}
$nrows = oci_fetch_all($rsStatement, $results);
return array ($nrows, $results);
}
?>
<?php现在,您已经创建了与数据库所需的所有函数,下面我们将了解一下 Cache_Lite_Function 类的方式。清单 7 是 testCache.php 脚本,该脚本使用 Cache_Lite_Function 类缓存以上函数的结果。
//File:connect.php
function GetConnection() {
$dbHost = "dbserverhost";
$dbHostPort="1521";
$dbServiceName = "orclR2";
$usr = "oe";
$pswd = "oe";
$dbConnStr = "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$dbHost.")
(PORT=".$dbHostPort."))(CONNECT_DATA=(SERVICE_NAME=".$dbServiceName.")))";
if(!$dbConn = oci_connect($usr,$pswd,$dbConnStr)) {
$err = oci_error();
trigger_error('Failed to connect ' .$err['message']);
return false;
}
return $dbConn;
}
?>
<?php“清单 7”中的 testCache.php 脚本应与 order_no URL 参数(代表 OE.ORDER 表中存储的订单 ID)一起被调用。例如,要检索与 ID 为 2408 的订单相关的信息,需要在浏览器中输入如下所示的 URL:
//File:testCache.php
require_once 'getOrderItems.php';
require_once 'getOrderFields.php';
require_once 'Cache/Lite/Function.php';
$options = array(
'cacheDir' => '/tmp/',
'lifeTime' => 86400
);
if (!isset($_GET['order_no'])) {
die('The order_no parameter is required');
}
$order_no=$_GET['order_no'];
$cache = new Cache_Lite_Function($options);
if ($orderfields = $cache->call('getOrderFields', $order_no)){
print "<h3>ORDER #$order_no</h3>\n";
print "<table>";
print "<tr><td>DATE:</td><td>".$orderfields['ORDER_DATE']."</td></tr>";
print "<tr><td>CUST_ID:</td><td>".$orderfields['CUSTOMER_ID']."</td></tr>";
print "<tr><td>TOTAL:</td><td>".$orderfields['ORDER_TOTAL']."</td></tr>";
print "</table>";
} else {
print "Some problem occurred while getting order fields!\n";
$cache->drop('getOrderFields', $order_no);
}
if (list($nrows, $orderitems) = $cache->call('getOrderItems', $order_no)){
//print "<h3>LINE ITEMS IN ORDER #$order_no</h3>";
print "<table border=1>";
print "<tr>\n";
while (list($key, $value) = each($orderitems)) {
print "<th>$key</th>\n";
}
print "</tr>\n";
for ($i = 0; $i < $nrows; $i++) {
print "<tr>";
print "<td>".$orderitems['ORDER_ID'][$i]."</td>";
print "<td>".$orderitems['LINE_ITEM_ID'][$i]."</td>";
print "<td>".$orderitems['PRODUCT_ID'][$i]."</td>";
print "<td>".$orderitems['UNIT_PRICE'][$i]."</td>";
print "<td>".$orderitems['QUANTITY'][$i]."</td>";
print "</tr>";
}
print "</table>";
} else {
print "Some problem occurred while getting order line items";
$cache->drop('getOrderItems', $order_no);
}
?>
DATE: | 29-JUN-99 06.59.31.333617 AM |
CUST_ID: | 166 |
TOTAL: | 309 |
ORDER_ID | LINE_ITEM_ID | PRODUCT_ID | UNIT_PRICE | QUANTITY |
2408 | 1 | 2751 | 61 | 3 |
2408 | 2 | 2761 | 26 | 1 |
2408 | 3 | 2783 | 10 | 10 |
<?php创建 dropResult.php 脚本后,请确保在通知处理程序中指定的 URL(如清单 2 所示)正确。然后,在 SQL*Plus 或类似工具中以 OE/OE 连接,并执行 UPDATE 语句,这些语句将影响本部分先前通过 testCache.php 脚本访问的同一订单(此处是 ID 为 2408 的订单):
//File:dropResults.php
require_once 'Cache/Lite/Function.php';
$options = array(
'cacheDir' => '/tmp/'
);
$cache = new Cache_Lite_Function($options);
if (isset($_GET['order_no'])&& isset($_GET['table'])) {
if($_GET['table']=='ORDER_ITEMS'){
$cache->drop('getOrderItems', $_GET['order_no']);
}
if ($_GET['table']=='ORDERS'){
$cache->drop('getOrderFields', $_GET['order_no']);
}
}
?>
UPDATE ORDERS SET order_mode = 'direct' WHERE order_id=2408;从“清单 8”中您可以清楚地看到,dropResult.php 脚本在从数据库服务器收到更改通知后并未刷新缓存。它只是删除了包含过期数据的缓存文件。因此,如果现在检查缓存目录,则将看到在使用 order_no=2408 运行 testCache.php 脚本时创建的缓存文件已经消失。这实际上意味着,testCache.php 在下次请求与 ID 为 2408 的订单相关的数据时将从后端数据库而非本地缓存中获取该数据。
UPDATE ORDER_ITEMS SET quantity = 3 WHERE order_id=2408 AND line_item_id=1;
UPDATE ORDER_ITEMS SET quantity = 1 WHERE order_id=2408 AND line_item_id=2;
COMMIT;
为响应以上更新,本文前面介绍的通知处理程序将逐个使用下列 URL 运行 dropResults.php 脚本两次:
<?php如果存储在 ORDERS 和 ORDER_ITEMS 表中的数据很少更改并且应用程序频繁访问它,则以上方法可能很有用。
//File:dropResults.php
require_once 'Cache/Lite/Function.php';
require_once 'getOrderItems.php';
require_once 'getOrderFields.php';
$options = array(
'cacheDir' => '/tmp/',
'lifeTime' => 86400
);
$cache = new Cache_Lite_Function($options);
if (isset($_GET['order_no'])&& isset($_GET['table'])) {
if($_GET['table']=='ORDER_ITEMS'){
$cache->drop('getOrderItems', $_GET['order_no']);
$cache->call('getOrderItems', $_GET['order_no']);
}
if ($_GET['table']=='ORDERS'){
$cache->drop('getOrderFields', $_GET['order_no']);
$cache->call('getOrderFields', $_GET['order_no']);
}
}
?>