Gestion des transactions

Pour défaut, chaque invocation à une méthode d'un service est encapsulée dans sa propre transaction, ceci est configuré via Spring. Pour contrôler l'utilisation des transactions dans votre code source, deux approches sont possibles :

  • Utiliser la déclaration Spring des transactions (recommandée si votre client est également basé sur Spring)
  • Utiliser le support de la transaction utilisateur Alfresco

La méthode 1 est documentée sur le site Spring.

Utilisation de la classe RetryingTransactionHelper

Il s'agit de la meilleure méthode permettant de contrôler les transactions. En utilisant la classe RetryingTransactionHelper, les différentes stratégies d'exécution concurrente sont automatiquement prises en compte, les scénarios d'annulation de la transaction sont correctement gérés.

RetryingTransactionCallback<Object> txnWork = new RetryingTransactionCallback<Object>()
{
  public Object execute() throws Exception
  {
    // Do stuff
    Object result = ...
    return result;
  }
};
TransactionService transactionService = serviceRegistry.getTransactionService();
Object result = transactionService.getRetryingTransactionHelper().doInTransaction(txnWork, true);

Les transactions peuvent être en lecture seule ou en lecture / écriture et il est possible de continuer avec la transaction existante ou bien de démarrer une nouvelle transaction. Pour cela, il faut ajouter un troisième paramètre à la méthode doInTransaction.

Attention à ne pas utiliser de bloc Try / Catch à l'intérieur de la méthode execute() de la classe RetryingTransactionCallback afin de conserver la gestion des exceptions définies dans la classe RetryingTransactionHelper. En effet, certaines exceptions sont ignorées et le code défini dans la méthode execute est réexécuté. Il s'agit notamment des exceptions dues aux exécutions concurrentes (par exemple, verrou mort, violation de contraintes). Il est ainsi préférable de gérer les exceptions en dehors de la méthode execute().

    /**
     * Execute a callback in a transaction until it succeeds, fails
     * because of an error not the result of an optimistic locking failure,
     * or a deadlock loser failure, or until a maximum number of retries have
     * been attempted.
     *
     * It is possible to force a new transaction to be created or to partake in
     * any existing transaction.
     *
     * @param cb                The callback containing the unit of work.
     * @param readOnly          Whether this is a read only transaction.
     * @param requiresNew       <tt>true</tt> to force a new transaction or
     *                          <tt>false</tt> to partake in any existing transaction.
     * @return                  Returns the result of the unit of work.
     * @throws                  RuntimeException  all checked exceptions are converted
     */
    public <R> R doInTransaction(RetryingTransactionCallback<R> cb, boolean readOnly, boolean requiresNew)

Gérer directement la transaction utilisateur

La transaction utilisateur Alfresco peut être accédée via l'utilisation du service ServiceRegistry :

UserTransaction trx = serviceRegistry.getTransactionService().getUserTransaction();

A partir de là, il est possible de marquer le début et la fin d'une transaction, les appels aux services doivent être effectués à l'intérieur de la transaction. Par exemple, les appels au service NodeService sont effectués au sein d'une même transaction. Sans l'utilisation de la transaction utilisateur, le comportement par défaut serait que chaque appel au service NodeService serait fait dans sa propre transaction.

   NodeService nodeService = serviceRegistry.getNodeService();
   try
   {
     trx.begin();
     nodeService.createNode(...);
     nodeService.createNode(...);
     trx.commit();
   }
   catch(Throwable e)
   {
     try
     {
       if (trx.getStatus() == Status.STATUS_ACTIVE)
       {
          trx.rollback();
       }
     }
     catch(Throwable ee)
     {
       // Handle double exception in whatever way is appropriate eg. log it
     }

     throw e;
   }

Bien que l'exemple montre l'utilisation d'un service, il est tout à fait possible de mélanger l'appel à plusieurs services publics d'Alfresco dans une même transaction.

Il est important de noter qu'une transaction utilisateur ne peut être utilisée qu'une seule fois. Cela signifie qu'une fois que la validation ou l'annulation de la transaction a été émise, une nouvelle transaction utilisateur doit être récupérée pour en commencer une autre.

La gestion directe de la transaction utilisateur ne convient pas aux codes sources nécessitant des exécutions concurrentes.

Catégorie: