Sabe-se que armazenar em cache os resultados das consultas ao banco de dados pode reduzir significativamente o tempo de execução do script e minimizar a carga no servidor de banco de dados. Essa técnica funciona muito bem se os dados que você está processando forem essencialmente estáticos. Isso ocorre porque muitas solicitações de dados ao banco de dados remoto podem eventualmente ser atendidas no cache local, eliminando a necessidade de conexão ao banco de dados, execução da consulta e obtenção dos resultados.
Mas armazenar em cache o conjunto de resultados do banco de dados geralmente é uma boa ideia quando o banco de dados que você está usando está em um computador diferente do servidor Web. No entanto, pode ser difícil determinar a melhor estratégia de cache para sua situação. Por exemplo, para aplicações onde é importante usar o conjunto de resultados mais recente do banco de dados, uma abordagem de cache acionada por tempo (comumente usada por sistemas de cache que assumem que o cache é regenerado toda vez que o carimbo de data e hora de expiração é atingido) pode não ser uma solução satisfatória . Nesse caso, você precisa de um mecanismo que notifique o aplicativo sempre que os dados do banco de dados que o aplicativo precisa armazenar em cache forem alterados, para que o aplicativo possa manter os dados expirados armazenados em cache consistentes com o banco de dados. Neste caso, usar "Notificação de alteração de banco de dados" será muito conveniente.
Introdução à notificação de alteração de banco de dados
O uso do recurso Notificação de alteração de banco de dados é muito simples: Crie um manipulador de notificação que execute a notificação – um procedimento armazenado PL/SQL ou uma função de retorno de chamada do cliente OCI. Em seguida, registre uma consulta nos objetos do banco de dados para os quais você deseja receber notificações de alteração, para que o manipulador de notificação seja chamado sempre que uma transação alterar qualquer objeto dentro dela e for confirmada. Normalmente, o manipulador de notificação envia o nome da tabela que foi modificada, o tipo de alteração feita e, opcionalmente, o ID da linha alterada para o ouvinte do cliente para que o aplicativo cliente possa executar ações apropriadas no tratamento de resposta.
Para entender como funciona o recurso Notificação de alteração do banco de dados, considere o exemplo a seguir. Suponha que seu aplicativo PHP acesse pedidos armazenados na tabela OE.ORDERS e itens de pedido armazenados em OE.ORDER_ITEMS. Dado que as informações sobre pedidos feitos raramente mudam, talvez você queira que seu aplicativo armazene em cache os conjuntos de resultados de consultas nas tabelas ORDERS e ORDER_ITEMS. Para evitar o acesso a dados obsoletos, você pode usar Notificações de Alteração de Banco de Dados, que permitem que seu aplicativo seja facilmente notificado sobre alterações nos dados armazenados nas duas tabelas acima.
Você deve conceder a permissão do sistema CHANGE NOTIFICATION e a permissão EXECUTE ON DBMS_CHANGENOTIFICATION ao usuário OE antes de poder registrar consultas para as tabelas ORDERS e ORDER_ITEMS para receber notificações e responder a alterações DML ou DDL nessas tabelas. Para fazer isso, execute o seguinte comando em uma ferramenta de linha de comando SQL, como SQL*Plus.
CONECTAR/COMO SYSDBA;
NOTIFICAÇÃO DE ALTERAÇÃO DE CONCESSÃO PARA oe;
GRANT EXECUTE ON DBMS_CHANGE_NOTIFICATION TO oe;
Certifique-se de que o parâmetro init.ora job_queue_processes esteja configurado com um valor diferente de zero para receber notificações PL/SQL. Como alternativa, você pode usar o seguinte comando ALTER SYSTEM:
ALTER SYSTEM SET "job_queue_processes"=2; Depois de conectar-se como OE/OE, você pode criar um manipulador de notificação. Mas primeiro você deve criar o objeto de banco de dados que será usado pelo manipulador de notificação. Por exemplo, você pode querer criar uma ou mais tabelas de banco de dados nas quais o manipulador de notificação registra alterações no registro. No exemplo a seguir, você cria a tabela nfresults para registrar a data e a hora em que a alteração ocorreu, o nome da tabela que foi modificada e uma mensagem indicando se o manipulador de notificação enviou com êxito a mensagem de notificação ao cliente.
CONNECT oe/oe;
CREATE TABLE nfreults (
operarDATA,
nometabela VARCHAR2(60),
rslt_msg VARCHAR2(100)
);
Em um cenário real, talvez seja necessário criar mais tabelas para registrar informações como eventos de notificação e IDs de linhas alteradas, mas para os propósitos deste artigo, a tabela nfresults será suficiente.
Usando UTL_HTTP para enviar notificações a clientes
Você também pode criar um ou mais procedimentos armazenados PL/SQL e chamar esses procedimentos armazenados a partir do manipulador de notificação, obtendo assim uma solução mais flexível e de fácil manutenção. Por exemplo, talvez você queira criar um procedimento armazenado que implemente o envio de mensagens de notificação aos clientes. A "Listagem 1" é o procedimento PL/SQL sendNotification. Este processo usa o pacote UTL_HTTPPL para enviar notificações de alteração aos aplicativos clientes.
Listagem 1. Enviar notificação ao cliente usando UTL_HTTPCREATE
OR REPLACE PROCEDURE sendNotification(url IN VARCHAR2,
nometabela IN VARCHAR2, order_id IN VARCHAR2) É
requerimento UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
err_msg VARCHAR2(100);
tbl VARCHAR(60);
COMEÇAR
tbl:=SUBSTR(nometabela, INSTR(nometabela, '.', 1, 1)+1, 60);
COMEÇAR
req := UTL_HTTP.BEGIN_REQUEST(url||order_id||'&'||'table='||tbl);
resp := UTL_HTTP.GET_RESPONSE(req);
INSERT INTO nfresults VALUES(SYSDATE, nometabela, resp.reason_phrase);
UTL_HTTP.END_RESPONSE(resp);
EXCEÇÃO QUANDO OUTROS ENTÃO
err_msg := SUBSTR(SQLERRM, 1, 100);
INSERT INTO nfresults VALUES(SYSDATE, nometabela, err_msg);
FIM;
COMPROMETER-SE;
FIM;
/
Conforme mostrado na "Listagem 1", sendNotification envia uma mensagem de notificação ao cliente na forma de uma solicitação HTTP emitida pela função UTL_HTTP.BEGIN_REQUEST. Este URL contém o order_id da linha alterada na tabela ORDERS. Em seguida, usa UTL_HTTP.GET_RESPONSE para obter as informações de resposta enviadas pelo cliente. Na verdade, sendNotification não precisa processar toda a resposta retornada pelo cliente, mas apenas obtém uma mensagem curta (descrevendo o código de status) armazenada no campo reason_phrase do registro RESP.
Criando um manipulador de notificação
Agora você pode criar um manipulador de notificação que enviará notificações de alteração aos clientes com a ajuda do procedimento sendNotification descrito acima. Vamos dar uma olhada no procedimento PL/SQLorders_nf_callback na "Listagem 2".
Listagem 2. Manipulador de notificação que trata notificações de alterações na tabela OE.ORDERS
CREATE OR REPLACE PROCEDUREorders_nf_callback (ntfnds IN SYS.CHNF$_DESC) IS
nometabela VARCHAR2(60);
tabelas numéricas NÚMERO;
tipo_evento NÚMERO;
id_linha VARCHAR2(20);
números NÚMERO;
ordem_id VARCHAR2(12);
url VARCHAR2(256) := 'http://webserverhost/phpcache/dropResults.php?order_no=';
COMEÇAR
tipo_evento := ntfnds.event_type;
numtables := ntfnds.numtables;
SE (event_type = DBMS_CHANGE_NOTIFICATION.EVENT_OBJCHANGE) ENTÃO
FOR i IN 1..numtables LOOP
nometabela:= ntfnds.table_desc_array(i).nome_tabela;
SE (bitand(ntfnds.table_desc_array(i).opflags,
DBMS_CHANGE_NOTIFICATION.ALL_ROWS) = 0) ENTÃO
numrows := ntfnds.table_desc_array(i).numrows;
OUTRO
números :=0;
TERMINAR SE;
SE (nometbl = 'OE.ORDERS') ENTÃO
FOR j IN 1..numrows LOOP
row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
SELECIONE order_id INTO ord_id FROM pedidos WHERE rowid = row_id;
sendNotification(url, nometabela, ord_id);
FIM DO LAÇO;
TERMINAR SE;
FIM DO LAÇO;
TERMINAR SE;
COMPROMETER-SE;
FIM;
/
Conforme mostrado na "Listagem 2", esse manipulador de notificação usa o objeto SYS.CHNF$_DESC como parâmetro e depois usa suas propriedades para obter os detalhes da alteração. Neste exemplo, esse manipulador de notificação tratará apenas notificações postadas pelo banco de dados em resposta a alterações DML ou DDL em objetos registrados (ou seja, somente se o tipo de notificação for EVENT_OBJCHANGE) e ignorará informações sobre outros eventos do banco de dados, como inicialização de instância ou notificação de desligamento da instância). A partir da versão acima, o manipulador pode lidar com notificações de alteração emitidas para cada linha afetada na tabela OE.ORDERS. Posteriormente neste artigo, na seção "Adicionando uma tabela a um registro existente", você adicionará algumas linhas de código ao manipulador para que ele possa manipular notificações de linhas modificadas na tabela OE.ORDER_ITEMS.
Criar um registro para notificações de mudança
Depois de criar um manipulador de notificação, você deverá criar um registro de consulta para ele. Para este exemplo, você deve realizar uma consulta na tabela OE.ORDER durante o processo de registro e especificarorders_nf_callback como o manipulador de notificação. Você também precisa especificar a opção QOS_ROWIDS no pacote DBMS_CHANGE_NOTIFICATION para ativar a granularidade no nível ROWID em mensagens de notificação. A "Listagem 3" é um bloco PL/SQL que cria o registro de consulta para o manipulador de notificação requests_nf_callback.
Listagem 3. Criar registro de consultaDECLARE
para manipulador de notificação
REGDSSYS.CHNF$_REG_INFO;
NÚMERO registrado;
ord_id NÚMERO;
qosflags NÚMERO;
COMEÇAR
qosflags := DBMS_CHANGE_NOTIFICATION.QOS_RELIABLE +
DBMS_CHANGE_NOTIFICATION.QOS_ROWIDS;
REGDS := SYS.CHNF$_REG_INFO ('orders_nf_callback', qosflags, 0,0,0);
regid := DBMS_CHANGE_NOTIFICATION.NEW_REG_START (REGDS);
SELECIONE order_id INTO ord_id FROM pedidos WHERE ROWNUM<2;
DBMS_CHANGE_NOTIFICATION.REG_END;
FIM;
/
Este exemplo cria um registro na tabela ORDERS e usaorders_nf_callback como manipulador de notificação. Agora, se você usar uma instrução DML ou DDL para modificar a tabela ORDERS e confirmar a transação, a funçãoorders_nf_callback será chamada automaticamente. Por exemplo, você pode executar a seguinte instrução UPDATE na tabela ORDERS e confirmar a transação:
UPDATE ORDERS SET order_mode = 'direct' WHERE order_id=2421;
ATUALIZAR PEDIDOS SET order_mode = 'direto' WHERE order_id=2422;
COMPROMETER-SE;
Para garantir que o banco de dados postou notificações em resposta à transação acima, você pode verificar a tabela nfresults:
SELECT TO_CHAR(operdate, 'dd-mon-yy hh:mi:ss') operadate,
nometabela, rslt_msg FROM nfresults;
O resultado deve ficar assim:
OPERDATE TBLNAME RSLT_MSG
---------- ---------- ---------
02-mar-06 04:31:28 OE.ORDERS não encontrados
02-mar-06 04:31:29 OE.ORDERS não encontrados
Fica claro pelos resultados acima queorders_nf_callback já está funcionando, mas o script do cliente não foi encontrado. Isso não é inesperado neste exemplo porque você não criou o script dropResults.php especificado na URL. Para obter instruções sobre o script dropResults.php, consulte a seção Construindo o cliente posteriormente neste artigo.
Adicionando uma tabela a um registro existente
A seção anterior mostrou como usar o Change Notification Service para que o banco de dados notifique você quando um objeto de registro (no exemplo acima, a tabela ORDERS) for alterado. Mas, do ponto de vista do desempenho, o aplicativo cliente pode preferir armazenar em cache o conjunto de resultados da consulta da tabela ORDER_ITEMS em vez da própria tabela ORDERS, porque precisa recuperar apenas uma linha da tabela ORDERS cada vez que acessa o pedido, mas no ao mesmo tempo Várias linhas devem ser recuperadas da tabela ORDER_ITEMS. Na realidade, um pedido pode conter dezenas ou até centenas de itens de linha.
Como você já registrou consultas na tabela ORDERS, não é necessário criar um registro para registrar consultas na tabela ORDER_ITEMS. Em vez disso, você pode usar um registro existente. Para fazer isso, primeiro você precisa recuperar o ID de um registro existente. Você pode executar a seguinte consulta para fazer isso:
SELECT regid, table_name FROM user_change_notification_regs Os resultados podem ser assim:
REGID TABLE_NAME;
----- --------------
241 PEDIDOS OE.
Após obter o ID de registro, você pode adicionar um novo objeto ao registro utilizando a função DBMS_CHANGE_NOTIFICATION.ENABLE_REG da seguinte forma:
DECLARE
ord_id NÚMERO;
COMEÇAR
DBMS_CHANGE_NOTIFICATION.ENABLE_REG(241);
SELECIONE order_id INTO ord_id FROM order_items WHERE ROWNUM <2;
DBMS_CHANGE_NOTIFICATION.REG_END;
FIM;
/
Feito! A partir de agora, o banco de dados irá gerar uma notificação em resposta a quaisquer alterações feitas em ORDERS e ORDER_ITEMS, e chamará o procedimentoorders_nf_callback para tratar a notificação. Portanto, o próximo passo é editarorders_nf_callback para que ele possa lidar com notificações geradas por operações DML na tabela ORDER_ITEMS. Mas antes de recriar o procedimentoorders_nf_callback, é necessário criar o seguinte tipo de tabela que será referenciado durante o processo de atualização:
CREATE TYPE rdesc_tab AS TABLE OF SYS.CHNF$_RDESC Em seguida, retorne à Listagem 2, após a seguinte linha de SYS.CHNF$_RDESC; código:
SE (tblname = 'OE.ORDERS') ENTÃO
FOR j IN 1..numrows LOOP
row_id := ntfnds.table_desc_array(i).row_desc_array(j).row_id;
SELECIONE order_id INTO ord_id FROM pedidos WHERE rowid = row_id;
sendNotification(url, nometabela, ord_id);
FIM DO LAÇO;
TERMINAR SE;
Insira o seguinte código:
IF (tblname = 'OE.ORDER_ITEMS') THEN
FOR rec IN (SELECT DISTINCT(o.order_id) o_id FROM
TABELA(CAST(ntfnds.table_desc_array(i).row_desc_array AS rdesc_tab)) t,
pedidos o, order_items d WHERE t.row_id = d.rowid AND d.order_id=o.order_id)
LAÇO
sendNotification(url, nometabela, rec.o_id);
FIM DO LAÇO;
TERMINAR SE;
Depois de recriar o order_nf_callback, você precisa testar se ele funciona corretamente. Para fazer isso, você pode executar a seguinte instrução UPDATE na tabela ORDER_ITEMS e confirmar a transação:
UPDATE ORDER_ITEMS SET quantidade = 160 WHERE order_id=2421 AND line_item_id=1;
UPDATE ORDER_ITEMS SET quantidade = 160 WHERE order_id=2421 AND line_item_id=2;
COMPROMETER-SE;
Em seguida, verifique a tabela nfresults da seguinte forma:
SELECT TO_CHAR(operdate, 'dd-mon-yy hh:mi:ss') operadate,
rslt_msg FROM nfresults WHERE tblname = 'OE.ORDER_ITEMS' A saída pode ser semelhante a esta:
OPERDATE RSLT_MSG;
-----------------------------------
03-mar-06 12:32:27 Não encontrado
Você pode estar se perguntando por que apenas uma linha foi inserida na tabela nfresults – afinal, você atualizou duas linhas na tabela ORDER_ITEMS. Na verdade, as duas linhas atualizadas têm o mesmo order_id - ou seja, pertencem ao mesmo pedido. Aqui, assumimos que o aplicativo cliente usará uma única instrução para selecionar todos os itens de linha de um pedido, portanto, não será necessário saber exatamente quais itens de linha de um pedido foram alterados. Em vez disso, o cliente precisa saber o ID do pedido no qual pelo menos um item de linha foi modificado, excluído ou inserido.
Construindo o cliente
Agora que você criou registros para as tabelas ORDERS e ORDER_ITEMS, vamos dar uma olhada em como as notificações de alteração são usadas por aplicativos clientes que acessam pedidos e seus itens de linha armazenados nessas tabelas. Para fazer isso, você pode construir um aplicativo PHP que armazenará em cache os resultados das consultas nas tabelas acima e tomará as ações apropriadas em resposta às notificações sobre alterações nessas tabelas (que são recebidas do servidor de banco de dados). Uma maneira fácil é usar o pacote PEAR::Cache_Lite, que fornece um mecanismo confiável para manter os dados do cache atualizados. Em particular, você pode usar a classe Cache_Lite_Function (parte do pacote PEAR::Cache_Lite), que permite armazenar chamadas de função em cache.
Por exemplo, você pode criar uma função que execute as seguintes tarefas: estabeleça uma conexão com o banco de dados, execute uma instrução select no banco de dados, obtenha os resultados da pesquisa e, finalmente, retorne os resultados como uma matriz. Você pode então armazenar em cache as matrizes de resultados retornadas pela função por meio do método de chamada da instância Cache_Lite_Function para que possam ser lidas no cache local em vez de no banco de dados back-end, o que pode melhorar significativamente o desempenho do seu aplicativo. Então, quando for notificado sobre alterações nos dados armazenados em cache, você usará o método drop da instância Cache_Lite_Function para excluir os dados expirados no cache.
Voltando ao exemplo deste artigo, você pode querer criar duas funções para sua aplicação interagir com o banco de dados: a primeira função irá consultar a tabela ORDERS e retornar os pedidos com o ID especificado, enquanto a outra função irá consultar o ORDER_ITEMS table e return Retorna os itens de linha deste pedido. A "Listagem 4" mostra o script getOrderFields.php que contém a função getOrderFields, que aceita um ID de pedido e retorna um array associativo contendo alguns dos campos do pedido recuperado.
Listagem 4. Obtenha os campos da ordem especificada
<?php
//Arquivo:getOrderFields.php
require_once 'conectar.php';
function getOrderFields($order_no) {
if (!$rsConnection = GetConnection()){
retornar falso;
}
$strSQL = "SELECIONE 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();
imprimir $err['mensagem'];
trigger_error('Falha na consulta:' . $err['message']);
retornar falso;
}
$resultados = oci_fetch_assoc($rsStatement);
retornar $resultados;
}
?>
A "Listagem 5" é o script getOrderItems.php. O script contém a função getOrderItems, que aceita um ID de pedido e retorna uma matriz bidimensional contendo linhas que representam os itens de linha do pedido.
Listagem 5. Obtenha os itens de linha do pedido especificado
<?php
//Arquivo:getOrderItems.php
require_once 'conectar.php';
function getOrderItems($order_no) {
if (!$rsConnection = GetConnection()){
retornar falso;
}
$strSQL = "SELECT * FROM ORDER_ITEMS ONDE
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('Falha na consulta:' . $err['message']);
retornar falso;
}
$nrows = oci_fetch_all($rsStatement, $resultados);
array de retorno ($nrows, $resultados);
}
?>
Observe que ambas as funções acima requerem o script connect.php, que deve conter a função GetConnection que retorna a conexão com o banco de dados. A Listagem 6 é o script connect.php:
Listagem 6. Obter conexão com o banco de dados
<?php
//Arquivo:connect.php
função GetConnection() {
$dbHost = "dbserverhost";
$dbHostPort="1521";
$dbServiceName = "orclR2";
$usr = "oe";
$pswd = "oe";
$dbConnStr = "(DESCRIÇÃO=(ENDEREÇO=(PROTOCOLO=TCP)(HOST=".$dbHost.")
(PORT=".$dbHostPort."))(CONNECT_DATA=(SERVICE_NAME=".$dbServiceName.")))";
if(!$dbConn = oci_connect($usr,$pswd,$dbConnStr)) {
$err = oci_error();
trigger_error('Falha ao conectar ' .$err['mensagem']);
retornar falso;
}
return $dbConn;
}
?>
Agora que você criou todas as funções necessárias para se comunicar com o banco de dados, vamos dar uma olhada em como funciona a classe Cache_Lite_Function. A Listagem 7 é o script testCache.php que usa a classe Cache_Lite_Function para armazenar em cache os resultados da função acima.
<?php
usando PEAR::Cache_Lite
//Arquivo:testCache.php
require_once 'getOrderItems.php';
require_once 'getOrderFields.php';
require_once 'Cache/Lite/Function.php'
;
'cacheDir' => '/tmp/',
'tempo de vida' => 86400
);
if (!isset($_GET['order_no'])) {
die('O parâmetro order_no é obrigatório');
}
$order_no=$_GET['order_no'];
$cache = new Cache_Lite_Function($opções);
if ($orderfields = $cache->call('getOrderFields', $order_no)){
imprimir "<h3>ORDER #$order_no</h3>n";
imprimir "<tabela>";
imprimir "<tr><td>DATA:</td><td>".$orderfields['ORDER_DATE']."</td></tr>";
imprimir "<tr><td>CUST_ID:</td><td>".$orderfields['CUSTOMER_ID']."</td></tr>";
imprimir "<tr><td>TOTAL:</td><td>".$orderfields['ORDER_TOTAL']."</td></tr>";
imprimir "</table>";
} outro {
print "Ocorreu algum problema ao obter os campos do pedido!n";
$cache->drop('getOrderFields', $order_no);
}
if (list($nrows, $orderitems) = $cache->call('getOrderItems', $order_no)){
//imprimir "<h3>ITENS DE LINHA EM ORDEM #$order_no</h3>";
imprimir "<borda da tabela=1>";
imprimir "<tr>n";
while (lista($chave, $valor) = cada($orderitems)) {
imprimir "<th>$key</th>n";
}
imprimir "</tr>n";
for ($i = 0; $i < $nrows; $i++) {
imprimir "<tr>";
imprimir "<td>".$orderitems['ORDER_ID'][$i].."</td>";
imprimir "<td>".$orderitems['LINE_ITEM_ID'][$i].."</td>";
imprimir "<td>".$orderitems['PRODUCT_ID'][$i].."</td>";
imprimir "<td>".$orderitems['UNIT_PRICE'][$i].."</td>";
imprimir "<td>".$orderitems['QUANTIDADE'][$i]."</td>";
imprimir "</tr>";
}
imprimir "</table>";
} outro {
print "Ocorreu algum problema ao obter itens de linha do pedido";
$cache->drop('getOrderItems', $order_no);
}
?>
O script testCache.php na "Listagem 7" deve ser chamado com o parâmetro de URL order_no (representando o ID do pedido armazenado na tabela OE.ORDER). Por exemplo, para recuperar informações relacionadas ao pedido com ID 2408, você deve inserir a seguinte URL em seu navegador:
http://webserverhost/phpcache/testCache.php?order_no=2408 Como resultado, o navegador irá gerar a seguinte saída :
PEDIDO #2408
DATA: 29 DE JUNHO DE 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 10Agora
, se você clicar no botão recarregar no navegador, o script testCache.php não chamará as funções getOrderFields e getOrderItems novamente. Em vez disso, ele lerá os resultados do cache local. Portanto, cada chamada getOrderFields ou getOrderItems com order_no=2108 será atendida pelo cache local dentro de 24 horas a partir de agora (porque lifeTime está definido como 86.400 segundos). Observe, entretanto, que a classe Cache_Lite_Function não fornece uma API para testar se um cache está disponível para uma determinada função com determinados parâmetros. Portanto, pode ser um pouco complicado determinar se o aplicativo realmente lê o cache ou ainda executa a função cada vez que é chamado com os mesmos parâmetros. Por exemplo, no exemplo acima, para garantir que o mecanismo de cache funcione corretamente, você pode alterar temporariamente as informações de conexão especificadas no script connect.php para que ele não possa estabelecer a conexão com o banco de dados, por exemplo, especificar um nome de host do servidor de banco de dados incorreto; e, em seguida, use order_no= novamente 2108 Execute o script testCache.php. Se o cache estiver funcionando corretamente, a saída do navegador deverá ser a mesma de antes.
Além disso, você pode verificar o diretório de cache que é passado para o construtor da classe Cache_Lite_Function como o valor da opção cacheDir (/tmp neste exemplo). Nesse diretório você encontrará dois arquivos de cache que acabou de criar com nomes semelhantes a: cache_7b181b55b55aee36ad5e7bd9d5a091ec_3ad04d3024f4cd54296f75c92a359154. Observe que se você for um usuário do Windows, talvez queira usar o diretório %SystemDrive%temp para salvar arquivos de cache. Nesse caso, a opção cacheDir deve ser definida como /temp/.
Depois de verificar se o mecanismo de cache está funcionando corretamente, você poderá criar um PHP para lidar com as notificações de alteração recebidas do servidor de banco de dados. A "Listagem 8" é o script dropResult.php. O servidor de banco de dados chamará esse script em resposta às alterações nas tabelas ORDERS e ORDER_ITEMS.
Listagem 8. Tratamento de notificações de mudança recebidas do servidor de banco de dados
<?php
//Arquivo:dropResults.php
require_once 'Cache/Lite/Function.php'
;
'cacheDir' => '/tmp/'
);
$cache = new Cache_Lite_Function($opções);
if (isset($_GET['número_pedido'])&& isset($_GET['tabela'])) {
if($_GET['tabela']=='ORDER_ITEMS'){
$cache->drop('getOrderItems', $_GET['order_no']);
}
if ($_GET['tabela']=='ORDERS'){
$cache->drop('getOrderFields', $_GET['order_no']);
}
}
?>
Após criar o script dropResult.php, certifique-se de que a URL especificada no manipulador de notificação (mostrado na Listagem 2) esteja correta. Em seguida, conecte-se como OE/OE no SQL*Plus ou ferramenta similar e execute instruções UPDATE que afetarão os mesmos pedidos acessados anteriormente nesta seção através do script testCache.php (aqui o pedido com ID 2408):
UPDATE ORDERS SET order_mode = ' direto' WHERE order_id=2408;
UPDATE ORDER_ITEMS SET quantidade = 3 WHERE order_id=2408 AND line_item_id=1;
UPDATE ORDER_ITEMS SET quantidade = 1 WHERE order_id=2408 AND line_item_id=2;
COMPROMETER-SE;
Em resposta à atualização acima, o manipulador de notificação descrito anteriormente neste artigo executará o script dropResults.php duas vezes, usando os seguintes URLs: http://webserverhost/phpcache/dropResults.php?order_no=2408&table=ORDERS
http://webserverhost/phpcache/dropresults.php?order_no=2408&table=ORDER_ITEMS
Na "Listagem 8" você pode ver claramente que o script dropResult.php não libera o cache após receber a notificação de alteração do servidor de banco de dados. Apenas exclui arquivos de cache contendo dados expirados. Portanto, se você verificar o diretório de cache agora, verá que o arquivo de cache criado ao executar o script testCache.php com order_no=2408 desapareceu. O que isso significa essencialmente é que na próxima vez que testCache.php solicitar dados relacionados ao ID do pedido 2408, ele obterá esses dados do banco de dados back-end em vez do cache local.
Você pode achar esse método útil em situações em que o conjunto de resultados solicitado pelo aplicativo provavelmente será alterado antes que o aplicativo o utilize. Para os fins do exemplo deste artigo, isso significa que os dados relacionados a um pedido específico podem mudar várias vezes antes que testCache.php acesse esse pedido. Dessa forma, o aplicativo realiza muito trabalho desnecessário ao liberar seu cache imediatamente após receber notificações de alteração do servidor de banco de dados.
Mas se você quiser que o script dropResult.php libere o cache assim que for notificado da mudança, você pode chamar o método call da instância Cache_Lite_Function após chamar o método drop, especificando os mesmos parâmetros para ambas as chamadas. Nesse caso, você também deve incluir os scripts getOrderFields.php e getOrderItems.php para que dropResults.php possa chamar as funções getOrderFields e getOrderItems para atualizar o cache. A "Listagem 9" é o script dropResult.php modificado.
Listagem 9. Limpe o cache imediatamente após receber a notificação de alteração
<?php
//Arquivo:dropResults.php
require_once 'Cache/Lite/Function.php';
require_once 'getOrderItems.php';
require_once 'getOrderFields.php';
$opções = array(
'cacheDir' => '/tmp/',
'tempo de vida' => 86400
);
$cache = new Cache_Lite_Function($opções);
if (isset($_GET['número_pedido'])&& isset($_GET['tabela'])) {
if($_GET['tabela']=='ORDER_ITEMS'){
$cache->drop('getOrderItems', $_GET['order_no']);
$cache->call('getOrderItems', $_GET['order_no']);
}
if ($_GET['tabela']=='ORDERS'){
$cache->drop('getOrderFields', $_GET['order_no']);
$cache->call('getOrderFields', $_GET['order_no']);
}
}
?>
A abordagem acima pode ser útil se os dados armazenados nas tabelas ORDERS e ORDER_ITEMS raramente mudam e o aplicativo os acessa com frequência.
Resumo
Se sua aplicação PHP interagir com o Oracle Database 10g Release 2, você poderá aproveitar o recurso Database Change Notification, que permite que sua aplicação receba notificações em resposta a alterações DML no objeto associado à solicitação feita. Usando esse recurso, você não precisa atualizar o cache do seu aplicativo durante um período específico. Em vez disso, a operação será executada somente se o conjunto de resultados da consulta registrada tiver sido alterado.