<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/book.oci8.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'fr',
  ),
  'this' => 
  array (
    0 => 'oci8.taf.php',
    1 => 'Le support de la reprise transparente d\'application (TAF) d\'OCI8',
    2 => 'Le support de la reprise transparente d\'application (TAF) d\'OCI8',
  ),
  'up' => 
  array (
    0 => 'book.oci8.php',
    1 => 'OCI8',
  ),
  'prev' => 
  array (
    0 => 'oci8.fan.php',
    1 => 'Support de FAN (Fast Application Notification : Application de notification Rapide) OCI8',
  ),
  'next' => 
  array (
    0 => 'oci8.dtrace.php',
    1 => 'OCI8 et le suivi dynamique DTrace',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'fr',
    'path' => 'reference/oci8/taf.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="oci8.taf" class="chapter">
 <h1 class="title">Le support de la reprise transparente d&#039;application (TAF) d&#039;OCI8</h1>

 <p class="para">
  TAF est une fonctionnalité de la base de données Oracle qui fournit une haute disponibilité.
  Elle permet aux applications PHP OCI8 de se reconnecter automatiquement à une
  base de données préconfigurée lorsque la connectivité à la base de données échoue en raison
  d&#039;une panne d&#039;instance ou de réseau.
 </p>
 <p class="para">
  Dans un système de base de données Oracle configuré, TAF se produit lorsque l&#039;application PHP
  détecte que l&#039;instance de base de données est hors service ou injoignable. Elle établit une connexion
  à un autre nœud dans une configuration Oracle <a href="https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-DEF850F6-27E9-428E-B8FC-530230D78AD2" class="link external">&raquo;&nbsp;RAC</a>,
  une base de données de secours à chaud, ou la même instance de base de données
  elle-même. Consulter le <a href="https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-F7817CD2-4A2C-4D37-BD36-56DBABD4725F" class="link external">&raquo;&nbsp;Guide du programmeur de l&#039;interface d&#039;appel Oracle</a>
  pour plus d&#039;informations sur OCI TAF.
 </p>
 <p class="para">
  Une fonction de rappel d&#039;application peut être enregistrée
  avec <span class="function"><a href="function.oci-register-taf-callback.php" class="function">oci_register_taf_callback()</a></span>. Pendant
  la reprise, le traitement normal de l&#039;application s&#039;arrête et le rappel enregistré est invoqué.
  La fonction de rappel notifie l&#039;application des événements de reprise. Si la reprise réussit,
  le traitement normal reprendra. Si la reprise est abandonnée, toutes les opérations de base de données
  suivantes dans l&#039;application échoueront en raison de l&#039;absence de connexion disponible.
 </p>
 <p class="para">
  Lorsque la connexion échoue sur une autre base de données, la fonction de rappel peut
  réinitialiser tout état de connexion nécessaire, par exemple en rejouant
  les commandes ALTER SESSION nécessaires si le service de base de données n&#039;avait pas
  -failover_restore activé.
 </p>
 <p class="para">
  Une fonction de rappel d&#039;application peut être supprimée en appelant <span class="function"><a href="function.oci-unregister-taf-callback.php" class="function">oci_unregister_taf_callback()</a></span>.
 </p>

 <div class="section">
  <h2 class="title">Configuration de la reprise transparente d&#039;application</h2>
  <p class="para">
   TAF peut être configuré du côté PHP OCI8 ou dans la configuration de la
   base de données. Si les deux sont configurés, les paramètres côté base de données
   ont la priorité.
  </p>
  <p class="para">
   Configurer TAF dans PHP OCI8 (le côté client) en incluant le
   paramètre FAILOVER_MODE dans la partie CONNECT_DATA d&#039;un
   descripteur de connexion. Consulter la section
   Configuration de la reprise transparente d&#039;application
   du <a href="https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-8F532535-C401-4B51-BE0B-04FD74BB0621" class="link external">&raquo;&nbsp;
   Guide de l&#039;administrateur Oracle Database Net Services</a>
   pour plus d&#039;informations sur la configuration côté client de TAF.
  </p>
  <p class="para">
   Un exemple de tnsnames.ora pour configurer TAF reconnectant à
   la même instance de base de données :
  </p>
  <p class="para">
    <div class="informalexample">
     <div class="example-contents screen">
<div class="cdata"><pre>
    ORCL =
      (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521))
        (CONNECT_DATA =
          (SERVICE_NAME = orclpdb1)
          (FAILOVER_MODE =
            (TYPE = SELECT)
            (METHOD = BASIC)
            (RETRIES = 20)
            (DELAY = 15))))
 </pre></div>
     </div>
   </div>
  </p>
  <p class="para">
   Il est également possible de configurer TAF du côté de la base de données
   en modifiant le service cible avec
   <a href="https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-8DC4D5E0-CA9D-47BC-BAD0-8769405AFEC5" class="link external">&raquo;&nbsp;srvctl</a>
   (pour RAC) ou la procédure empaquetée
   <a href="https://www.oracle.com/pls/topic/lookup?ctx=dblatest&id=GUID-C11449DC-EEDE-4BB8-9D2C-0A45198C1928" class="link external">&raquo;&nbsp;
   DBMS_SERVICE.MODIFY_SERVICE</a>
   (pour les bases de données à instance unique).
  </p>
 </div>
 <div class="section">
  <h2 class="title">Utilisation des fonctions de rappels TAF dans OCI8</h2>
  <p class="para">
   Une fonction de rappel TAF est une fonction d&#039;application qui peut être
   enregistrée pour être appelée pendant la reprise. Elle est appelée
   plusieurs fois pendant la reprise de la connexion de l&#039;application.
  </p>
  <p class="para">
   La fonction de rappel est appelée pour la première fois lorsqu&#039;une perte de connexion est détectée.
   Cela permet à l&#039;application d&#039;agir en conséquence pour
   les retards à venir de la reprise. Si la reprise est réussie,
   la fonction de rappel est invoquée après que la connexion soit rétablie
   et utilisable. À ce moment, l&#039;application peut resynchroniser
   les paramètres de session et prendre des actions telles que
   informer l&#039;utilisateur qu&#039;une reprise a eu lieu. Si la reprise
   est infructueuse, un rappel se produit pour informer l&#039;application
   qu&#039;une reprise n&#039;a pas eu lieu et que la connexion n&#039;est pas utilisable.
  </p>
  <p class="para">
   L&#039;interface d&#039;une fonction de rappel TAF définie par l&#039;utilisateur est la suivante :
  </p>
  <div class="methodsynopsis dc-description">
   <span class="methodname"><strong>userCallbackFn</strong></span>(<span class="methodparam"><span class="type"><a href="language.types.resource.php" class="type resource">resource</a></span> <code class="parameter">$connection</code></span>, <span class="methodparam"><span class="type"><a href="language.types.integer.php" class="type int">int</a></span> <code class="parameter">$event</code></span>, <span class="methodparam"><span class="type"><a href="language.types.integer.php" class="type int">int</a></span> <code class="parameter">$type</code></span>): <span class="type"><a href="language.types.integer.php" class="type int">int</a></span></div>

  <p class="para">
   <dl>
    
     <dt><code class="parameter">connection</code></dt>
     <dd>
      <p class="para">
       La connexion Oracle sur laquelle le rappel TAF a été
       enregistré via <span class="function"><a href="function.oci-register-taf-callback.php" class="function">oci_register_taf_callback()</a></span>.
       La connexion n&#039;est pas valide tant que la
       reprise n&#039;est pas terminée avec succès.
      </p>
     </dd>
    
    
     <dt><code class="parameter">event</code></dt>
     <dd>
      <p class="para">
       L&#039;événement de reprise indique l&#039;état actuel de
       la reprise.
      </p>
      <p class="para">
       <ul class="itemizedlist">
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-begin">OCI_FO_BEGIN</a></code></strong> indique que
          la reprise a détecté une perte de connexion et que
          la reprise commence. 
         </p>
        </li>
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-end">OCI_FO_END</a></code></strong> indique que la
          reprise a réussi.
         </p>
        </li>
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-abort">OCI_FO_ABORT</a></code></strong> indique que
          la reprise a échoué et qu&#039;il n&#039;y a pas d&#039;option
          de réessayer.
         </p>
        </li>
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-error">OCI_FO_ERROR</a></code></strong> indique également
          que la reprise a échoué, mais il donne à
          l&#039;application l&#039;opportunité de gérer l&#039;erreur
          et de retourner OCI_FO_RETRY pour réessayer la reprise.
         </p>
        </li>
        <li class="listitem">
         <p class="para">
           <strong><code><a href="oci8.constants.php#constant.oci-fo-reauth">OCI_FO_REAUTH</a></code></strong> indique que
           un utilisateur Oracle a été réauthentifié.
         </p>
        </li>
       </ul>
      </p>
     </dd>
    
    
     <dt><code class="parameter">type</code></dt>
     <dd>
      <p class="para">
       Le type de reprise. Cela permet au rappel de savoir
       quel type de reprise l&#039;application a demandé. Les
       valeurs habituelles sont les suivantes :
      </p>
      <p class="para">
       <ul class="itemizedlist">
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-session">OCI_FO_SESSION</a></code></strong> indique que
          l&#039;utilisateur a demandé uniquement la reprise de session.
          Par exemple, si la connexion d&#039;un utilisateur est perdue,
          une nouvelle session est automatiquement créée pour
          l&#039;utilisateur sur la base de secours. Ce type de reprise
          ne tente pas de récupérer les SELECT.
         </p>
        </li>
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-select">OCI_FO_SELECT</a></code></strong> indique que
          l&#039;utilisateur a demandé la reprise SELECT également.
          Il permet aux utilisateurs avec des curseurs ouverts
          de continuer à les récupérer après une défaillance.
         </p>
        </li>
       </ul>
      </p>
     </dd>
    
    
     <dt><code class="parameter">return value</code></dt>
     <dd>
      <p class="para">
       <ul class="itemizedlist">
        <li class="listitem">
         <p class="para">
          <code class="literal">0</code> indique que les étapes de reprise
          doivent continuer normalement.
         </p>
        </li>
        <li class="listitem">
         <p class="para">
          <strong><code><a href="oci8.constants.php#constant.oci-fo-retry">OCI_FO_RETRY</a></code></strong> indique que
          la reprise doit être tentée à nouveau par Oracle.
          En cas d&#039;erreur lors de la reprise vers une nouvelle
          connexion, TAF est capable de réessayer la reprise.
          En général, le code de l&#039;application doit dormir
          pendant un certain temps avant de retourner OCI_FO_RETRY.
         </p>
        </li>
       </ul>
      </p>
     </dd>
    
   </dl>
  </p>
  <div class="example" id="example-1">
   <p><strong>Exemple #1 Enregistrement d&#039;une fonction de rappel TAF</strong></p>
   <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">// Définition de la fonction de rappel de l'espace utilisateur<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">MyClass </span><span style="color: #007700">{<br />    public static </span><span style="color: #0000BB">$retry_count</span><span style="color: #007700">;<br />    public static function </span><span style="color: #0000BB">TAFCallback</span><span style="color: #007700">(</span><span style="color: #0000BB">$conn</span><span style="color: #007700">, </span><span style="color: #0000BB">$event</span><span style="color: #007700">, </span><span style="color: #0000BB">$type</span><span style="color: #007700">)<br />    {<br />        switch (</span><span style="color: #0000BB">$event</span><span style="color: #007700">) {<br />            case </span><span style="color: #0000BB">OCI_FO_BEGIN</span><span style="color: #007700">:<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">" Failing Over ... Please stand by\n"</span><span style="color: #007700">);<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">" Failover type was found to be %s \n"</span><span style="color: #007700">,<br />                       ((</span><span style="color: #0000BB">$type</span><span style="color: #007700">==</span><span style="color: #0000BB">OCI_FO_SESSION</span><span style="color: #007700">) ? </span><span style="color: #DD0000">"SESSION"<br />                        </span><span style="color: #007700">:((</span><span style="color: #0000BB">$type</span><span style="color: #007700">==</span><span style="color: #0000BB">OCI_FO_SELECT</span><span style="color: #007700">) ? </span><span style="color: #DD0000">"SELECT" </span><span style="color: #007700">: </span><span style="color: #DD0000">"UNKNOWN!"</span><span style="color: #007700">)));<br />                </span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">$retry_count </span><span style="color: #007700">= </span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />                break;<br />            case </span><span style="color: #0000BB">OCI_FO_ABORT</span><span style="color: #007700">:<br />                </span><span style="color: #FF8000">// L'application ne peut pas continuer à utiliser la base de données<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">" Failover aborted. Failover will not take place.\n"</span><span style="color: #007700">);<br />                break;<br />            case </span><span style="color: #0000BB">OCI_FO_END</span><span style="color: #007700">:<br />                </span><span style="color: #FF8000">// Reprise réussie. Informer les utilisateurs qu'une reprise a eu lieu.<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">" Failover ended ... resuming services\n"</span><span style="color: #007700">);<br />                break;<br />            case </span><span style="color: #0000BB">OCI_FO_REAUTH</span><span style="color: #007700">:<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">" Failed over user ... resuming services\n"</span><span style="color: #007700">);<br />                </span><span style="color: #FF8000">// Rejouer toutes les commandes ALTER SESSION associées à cette connexion<br />                // par exemple oci_parse($conn, 'ALTER SESSION ...');<br />                </span><span style="color: #007700">break;<br />            case </span><span style="color: #0000BB">OCI_FO_ERROR</span><span style="color: #007700">:<br />                </span><span style="color: #FF8000">// Stopper les tentatives si nous avons déjà essayé 20 fois.<br />                </span><span style="color: #007700">if (</span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">$retry_count </span><span style="color: #007700">&gt;= </span><span style="color: #0000BB">20</span><span style="color: #007700">)<br />                    return </span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">" Failover error received. Sleeping...\n"</span><span style="color: #007700">);<br />                </span><span style="color: #0000BB">sleep</span><span style="color: #007700">(</span><span style="color: #0000BB">10</span><span style="color: #007700">);<br />                </span><span style="color: #0000BB">self</span><span style="color: #007700">::</span><span style="color: #0000BB">$retry_count</span><span style="color: #007700">++;<br />                return </span><span style="color: #0000BB">OCI_FO_RETRY</span><span style="color: #007700">; </span><span style="color: #FF8000">// retry failover<br />                </span><span style="color: #007700">break;<br />            default:<br />                </span><span style="color: #0000BB">printf</span><span style="color: #007700">(</span><span style="color: #DD0000">"Bad Failover Event: %d.\n"</span><span style="color: #007700">, </span><span style="color: #0000BB">$event</span><span style="color: #007700">);<br />                break;<br />        }<br />        return </span><span style="color: #0000BB">0</span><span style="color: #007700">;<br />    }<br />}<br /><br /></span><span style="color: #0000BB">$fn_name </span><span style="color: #007700">= </span><span style="color: #DD0000">'MyClass::TAFCallback'</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$conn </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_connect</span><span style="color: #007700">(</span><span style="color: #DD0000">'hr'</span><span style="color: #007700">, </span><span style="color: #DD0000">'welcome'</span><span style="color: #007700">, </span><span style="color: #DD0000">'orcl'</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$sysconn </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_connect</span><span style="color: #007700">(</span><span style="color: #DD0000">'system'</span><span style="color: #007700">, </span><span style="color: #DD0000">'oracle'</span><span style="color: #007700">, </span><span style="color: #DD0000">'orcl'</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">// Utiliser une connexion privilégiée pour construire une instruction SQL qui initiera la reprise<br /></span><span style="color: #0000BB">$sql </span><span style="color: #007700">= &lt;&lt;&lt; 'END'<br /></span><span style="color: #DD0000">select unique 'alter system disconnect session '''||sid||','||serial#||''''<br />from v$session_connect_info<br />where sid = sys_context('USERENV', 'SID')<br /></span><span style="color: #007700">END;<br /><br /></span><span style="color: #0000BB">$s </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_parse</span><span style="color: #007700">(</span><span style="color: #0000BB">$conn</span><span style="color: #007700">, </span><span style="color: #0000BB">$sql</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">oci_execute</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$r </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_fetch_array</span><span style="color: #007700">(</span><span style="color: #0000BB">$s</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">$disconnectssql </span><span style="color: #007700">= </span><span style="color: #0000BB">$r</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">];<br /><br /></span><span style="color: #0000BB">oci_register_taf_callback</span><span style="color: #007700">(</span><span style="color: #0000BB">$conn</span><span style="color: #007700">, </span><span style="color: #0000BB">$fn_name</span><span style="color: #007700">); </span><span style="color: #FF8000">// Register TAFCallback to Oracle TAF<br /><br /></span><span style="color: #007700">print </span><span style="color: #DD0000">"Parsing user query\n"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$sql </span><span style="color: #007700">= </span><span style="color: #DD0000">"select systimestamp from dual"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$stmt </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_parse</span><span style="color: #007700">(</span><span style="color: #0000BB">$conn</span><span style="color: #007700">, </span><span style="color: #0000BB">$sql</span><span style="color: #007700">);<br /><br /></span><span style="color: #FF8000">// Par exemple, si une perte de connexion se produit à ce moment, oci_execute() détectera<br />// la perte et la reprise commencera. Pendant la reprise, oci_execute() invoquera<br />// la fonction de rappel TAF plusieurs fois. Si la reprise réussit,<br />// une nouvelle connexion est créée de manière transparente et oci_execute() continuera comme<br />// d'habitude. Les paramètres de session de la connexion peuvent être réinitialisés dans la fonction de rappel TAF.<br />// Si la reprise est abandonnée, oci_execute() renverra une erreur<br />// car une connexion valide n'est pas disponible.<br /><br />// Déconnecter l'utilisateur, ce qui initie la reprise<br /></span><span style="color: #007700">print </span><span style="color: #DD0000">"Disconnecting the user\n"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$discsql </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_parse</span><span style="color: #007700">(</span><span style="color: #0000BB">$sysconn</span><span style="color: #007700">, </span><span style="color: #0000BB">$disconnectssql</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">oci_execute</span><span style="color: #007700">(</span><span style="color: #0000BB">$discsql</span><span style="color: #007700">);<br /><br />print </span><span style="color: #DD0000">"Executing user query\n"</span><span style="color: #007700">;<br /></span><span style="color: #0000BB">$e </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_execute</span><span style="color: #007700">(</span><span style="color: #0000BB">$stmt</span><span style="color: #007700">);<br />if (!</span><span style="color: #0000BB">$e</span><span style="color: #007700">) {<br />    </span><span style="color: #0000BB">$m </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_error</span><span style="color: #007700">(</span><span style="color: #0000BB">$stmt</span><span style="color: #007700">);<br />    </span><span style="color: #0000BB">trigger_error</span><span style="color: #007700">(</span><span style="color: #DD0000">"Could not execute statement: "</span><span style="color: #007700">. </span><span style="color: #0000BB">$m</span><span style="color: #007700">[</span><span style="color: #DD0000">'message'</span><span style="color: #007700">], </span><span style="color: #0000BB">E_USER_ERROR</span><span style="color: #007700">);<br />}<br /></span><span style="color: #0000BB">$row </span><span style="color: #007700">= </span><span style="color: #0000BB">oci_fetch_array</span><span style="color: #007700">(</span><span style="color: #0000BB">$stmt</span><span style="color: #007700">);<br />print </span><span style="color: #0000BB">$row</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">] . </span><span style="color: #DD0000">"\n"</span><span style="color: #007700">;<br /><br /></span><span style="color: #FF8000">// faire d'autres instructions SQL avec la nouvelle connexion, si elle est valide<br />// $stmt = oci_parse($conn,  . . .);<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>
 </div>

 <div class="section">
  <h2 class="title">Voir aussi</h2>
  <ul class="simplelist">
   <li><span class="function"><a href="function.oci-register-taf-callback.php" class="function">oci_register_taf_callback()</a></span></li>
   <li><span class="function"><a href="function.oci-unregister-taf-callback.php" class="function">oci_unregister_taf_callback()</a></span></li>
  </ul>
 </div>


</div>
<?php manual_footer($setup); ?>