2 votes

Comment attraper une exception lors d'un RollBack

Quelle est la meilleure façon d'implémenter la gestion des erreurs pour un SqlTransaction RollBack qui existe déjà dans une clause catch ? Mon code est à peu près le suivant :

using (SqlConnection objSqlConn = new SqlConnection(connStr)) {
  objSqlConn.Open();

  using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction()) {
    try {
      // code
      // more code
      // and more code
    }
    catch (Exception ex) {
      // What happens if RollBack() has an exception?
      objSqlTrans.Rollback();
      throw ex;
    }
  }
}

Je pense que mon application avait une exception dans le bloc try, qui à son tour a été attrapée dans le bloc catch et ensuite le RollBack a été tenté. Cependant, l'erreur que je vois mentionne un SqlTransaction.ZombieCheck(), ce qui me fait me demander si le RollBack() lui-même n'a pas également déclenché une exception. Alors, dois-je mettre en place un type de gestion des erreurs au niveau de la fonction RollBack() ? Comment puis-je le faire tout en conservant l'exception qui a entraîné l'exécution dans le bloc catch en premier lieu ?

EDIT - Tout mon code :

using (SqlConnection objSqlConn = new SqlConnection(connStr)) {

    objSqlConn.Open();

    // Begin Transaction
    using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction()) {

        try {
            // Create file in db (which in turn creates it on disk according to where the 
            // ...FileStream points)
            SqlCommand objSqlCmd = new SqlCommand("usp_FileAdd", objSqlConn, objSqlTrans);
            objSqlCmd.CommandType = CommandType.StoredProcedure;

            // Sql parameter - report name
            SqlParameter objSqlParam1 = new SqlParameter("@ObjectID", SqlDbType.Int);
            objSqlParam1.Value = objID;

            // Sql out parameter - returns the file path
            SqlParameter objSqlParamOutput = new SqlParameter("@filepath", SqlDbType.VarChar, -1);
            objSqlParamOutput.Direction = ParameterDirection.Output;

            // Add Sql parameters to command obj
            objSqlCmd.Parameters.Add(objSqlParam1);
            objSqlCmd.Parameters.Add(objSqlParamOutput);

            // Execute command object
            objSqlCmd.ExecuteNonQuery();

            // Path to the FileStream
            string path = objSqlCmd.Parameters["@filepath"].Value.ToString();

            // Reset command object to get FileStream
            objSqlCmd = new SqlCommand(
                "SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()",
                objSqlConn,
                objSqlTrans);

            // Execute command object
            Object obj = objSqlCmd.ExecuteScalar();

            if (obj != DBNull.Value) {
                // Byte array representing the FileStream
                byte[] fsBytes = (byte[])obj;

                SqlFileStream sqlFS = new SqlFileStream(path, fsBytes, FileAccess.Write);

                using (FileStream fs = fi.OpenRead()) {
                    //byte[] b = new byte[1024];
                    byte[] b = new byte[4096];
                    int read;

                    fs.Seek(0, SeekOrigin.Begin);

                    while ((read = fs.Read(b, 0, b.Length)) > 0) {
                        sqlFS.Write(b, 0, read);
                    }
                }

                sqlFS.Close();
            }

            // Commit the transaction
            objSqlTrans.Commit();
        }
        catch (Exception ex) {
            objSqlTrans.Rollback();
            throw ex;
        }
    }
}

1voto

Joshua Points 13231

Ce fragment devrait se lire comme suit :

using (SqlConnection objSqlConn = new SqlConnection(connStr)) {
 objSqlConn.Open();

 using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction()) {
   try {
     // code
     // more code
     // and more code
   }
   catch (Exception ex) {
     // What happens if RollBack() has an exception?
     try {
        objSqlTrans.Rollback();
     } catch (Exception ex2) {
        /* can't roll back -- db gone? db will do it for us since we didn't commit. */
     }
     throw;
   }
 }
}

EDIT : En y réfléchissant, il n'y a pas besoin de try/catch dans ce cas particulier puisque la fermeture d'une connexion avec une transaction non engagée annule la transaction, donc le bloc peut ressembler à ceci :

using (SqlConnection objSqlConn = new SqlConnection(connStr)) {
 objSqlConn.Open();

 using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction()) {
  // code
  // more code
  // and more code
 }
}

1voto

Conrad Frix Points 34272

Vous avez déjà

using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction())

La transaction sera annulée à la fin du bloc d'utilisation si elle n'a pas été validée.

Je supprimerais donc entièrement le bloc de capture.

Quant à ce qui se passe lorsque le retour en arrière échoue, je commencerais par reconnaître qu'il s'agit d'une très mauvaise situation et je suivrais les conseils d'Eric Lippert sur un problème similaire. aquí

0voto

Wyatt Barnett Points 12541

Cela devrait aussi probablement être un jet ; plutôt qu'un jet ex ;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X