2017-10-16 6 views
0

Vous rencontrez des problèmes avec un morceau de code supposé s'exécuter sur un ensemble de données SQL Server. L'idée est qu'il lit dans redimensionne un fichier jpeg et l'écrit à nouveau. Il fonctionne bien sur une seule ligne. Toutefois, lors de l'exécution sur un grand ensemble de données, les lignes suivantes la commande de mise à jour échoue en raison d'un délai d'expiration. Pas sur toutes les lignes, mais ça passe sur la majorité.SqlConnection et SqlCommand expirent

using System.Drawing.Imaging; 
using System.IO; 

namespace MesResizer 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var con = ConfigurationManager.ConnectionStrings["SQLconnString"].ToString(); 
      SqlConnection myConnection = new SqlConnection(con); 
      GetRows(myConnection); 
      myConnection.Close(); 
     } 

     private static void GetRows(SqlConnection connection) 
     { 
      Boolean changed = false; 

      using (connection) 
      { 
       SqlCommand command = new SqlCommand("SELECT TOP(16000) strIIImage, intIIID FROM InspectionItem;", connection); 

       try 
       { 
        Writeout("Setting up Database connection.."); 
        connection.Open(); 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine(e.Message); 
        Console.ReadLine(); 
        return; 
       } 

       Writeout("DONE"); 
       SqlDataReader reader = command.ExecuteReader(); 

       if (reader.HasRows) 
       { 
        while (reader.Read()) 
        { 
         using (MemoryStream ms = new MemoryStream()) 
         { 
          int RowId = (int)reader.GetValue(reader.GetOrdinal("intIIID")); 
          Stream str; 
          changed = false; 

          try 
          { 
           str = reader.GetStream(reader.GetOrdinal("strIIImage")); 

           Image imgstr = Image.FromStream(str); 
           imgstr.Save("before.jpg", ImageFormat.Jpeg); 

           if (str.Length > 0) 
            changed = ScaleImage(Image.FromStream(str), ms); 
          } 
          catch (ArgumentException e) 
          { 
           Writeout("Stream does not have a valid image format or is Null... Unable to process image... " + RowId); 
           Writeout("Exception: " + e.Message); 
          } 

          if (changed) 
           WriteImage(ms, RowId); 
          else 
           Writeout("Image already resized: " + RowId); 
         } 
        } 
       } 
       else 
       { 
        Writeout("No rows found."); 
        Console.ReadLine(); 
       } 

       reader.Close(); 
       Console.ReadLine(); 
      } 
     } 

     private static void WriteImage(MemoryStream ms, int RowId) 
     { 
      var conf = ConfigurationManager.ConnectionStrings["SQLconnString"].ToString(); 
      SqlConnection writecon = new SqlConnection(conf); 

      writecon.Open(); 

      using (FileStream file = new FileStream("after.jpg", FileMode.Create, System.IO.FileAccess.Write)) 
      { 
       file.Write(ms.ToArray(), 0, (int)ms.Length); 
      } 

      using (SqlCommand cmd = new SqlCommand("UPDATE InspectionItem SET strIIImage = @Image WHERE intIIID = @Id", writecon)) 
      { 
       cmd.Parameters.Add("@Image", SqlDbType.VarBinary, (int)ms.Length).Value = ms.ToArray(); 
       cmd.Parameters.Add("@Id", SqlDbType.Int).Value = RowId; 
       cmd.CommandTimeout = 5; 

       try 
       { //This is where it breaks. :) 
        cmd.ExecuteNonQuery(); 
       } 
       catch (SqlException e) 
       { 
        Writeout(e.Message + "Error occured on row: " + RowId); 
        return; 
       } 
      } 

      Writeout("Succesfully Resized File: " + RowId); 
      writecon.Close(); 
     } 
    } 
} 

Il y a un peu de choses supplémentaires qui se passe ici parce que je suis en train de vérifier l'image stockée est réellement redimensionnée et d'autres choses comme les lignes particulières qui éprouvaient la question.

J'ai commenté le code où le timeout arrive. :)

Toute information ou direction sera appréciée.

TIA.

EDIT Ran sur un certain nombre de formats d'image et un certain nombre de lignes sur 5000+ une base de données de test et n'a pas eu un problème du tout. Je peux voir que les données sont celles d'une image car j'écris chacune d'elles sur le disque mais il ne semble pas vouloir réécrire dans la base de données tout le temps. Très étrange

Modifier Juste au cas où quelqu'un voudrait connaître la résolution à ceci. Terminé par conclure que le SQLdatareader bloquait les lignes sur la base de données.

Je suis en train de sélectionner des blocs de lignes de la base de données en les déplaçant dans un datatable fermant le lecteur de données et en le redimensionnant et en le réécrivant si nécessaire. Je crois que la clé était de fermer le SqlDatareader et de libérer tous les verrous.

+0

C'est beaucoup de code.S'il vous plaît ne coller que la partie pertinente – Alex

+0

Sure ill mettre à jour il .. ne voulait pas laisser quelque chose hors de propos. –

Répondre

0

Modifié:

Je viens aussi remarqué dans votre appel de mise à jour que vous avez cmd.CommandTimeout = 5; ensemble. C'est un délai d'attente assez court, à seulement 5 secondes. La valeur par défaut pour cela est 30 secondes, vous pourriez facilement avoir besoin de beaucoup de temps pour diffuser un fichier.

Message initial ci-dessous

:

Il y a quelques choses qui pourraient se produire ici. Puisque vous utilisez un lecteur et que vous passez ligne par ligne, vous gardez la connexion initiale ouverte, il est possible qu'elle finisse par expirer aussi. En ce qui concerne votre autre problème de connexion, je ne serais pas surpris si vous obtenez une exception timeout while getting a connection from pool plutôt qu'un délai d'expiration traditionnel en raison d'un nombre maximal de connexions étant atteint. Comme vous êtes à l'intérieur d'une boucle serrée et en constante ouverture/fermeture des connexions.

J'envelopperais également la connexion sur votre mise à jour à l'intérieur d'une utilisation, en raison de votre gestion des exceptions, la connexion pourrait ne pas se fermer, entraînant un épuisement des ressources du pool.

Ce n'est pas parfait, mais changer pour ressembler à ceci pourrait aider.

private static void WriteImage(MemoryStream ms, int RowId) 
     { 
      var conf = ConfigurationManager.ConnectionStrings["SQLconnString"].ToString(); 
      //Added using 
      using(SqlConnection writecon = new SqlConnection(conf)) 
{ 

      writecon.Open(); 

      using (FileStream file = new FileStream("after.jpg", FileMode.Create, System.IO.FileAccess.Write)) 
      { 
       file.Write(ms.ToArray(), 0, (int)ms.Length); 
      } 

      using (SqlCommand cmd = new SqlCommand("UPDATE InspectionItem SET strIIImage = @Image WHERE intIIID = @Id", writecon)) 
      { 
       cmd.Parameters.Add("@Image", SqlDbType.VarBinary, (int)ms.Length).Value = ms.ToArray(); 
       cmd.Parameters.Add("@Id", SqlDbType.Int).Value = RowId; 
       cmd.CommandTimeout = 5; 
       try 
       { //This is where it breaks. :) 
        cmd.ExecuteNonQuery(); 
       } 
       catch (SqlException e) 
       { 
        Writeout(e.Message + "Error occured on row: " + RowId); 
        return; 
       } 
      } 
      Writeout("Succesfully Resized File: " + RowId); 
      } 
     } 
+0

Obtient-il la connexion à partir du pool lorsqu'il exécute la requête ou lorsque j'appelle open()? Délai d'exécution expiré. Le délai d'expiration s'est écoulé avant la fin de l'opération ou le serveur ne répond pas. La déclaration a été terminée. Est le message d'exception. :) Merci de votre aide. –

+0

La connexion est établie lorsque vous ouvrez. Si vous obtenez un délai d'attente réel, vous pouvez regarder la charge sur le serveur, pour vous assurer que vous ne maximisez pas sur IO, ou CPU, car cela pourrait retarder, ou si les images que vous écrivez sont très grandes . –

+0

@ T-rent Je viens de revoir votre code et édité ma réponse. Vous définissez un délai d'attente explicite de 5 secondes. Avec les opérations d'écriture de fichiers, il est fort probable que cela soit trop court. –