2012-04-04 17 views
9

Ho notato che i miei errori di codice su sqlWrite.ExecuteNonQuery(); dopo l'esecuzione di 200 inseriscono query in un paio di secondi. Ho sempre pensato che lo using assicurasse che le risorse vengano riutilizzate correttamente e non ci sarà bisogno di fare nulla. Questa è la prima volta che ottengo questo errore e ho avuto a che fare con sql/C# per quasi 3 anni facendo cose diverse.Quando utilizzare SqlConnection.ClearAllPools() in C#

using (SqlConnection varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails)) 
{ 
    using (var sqlWrite = new SqlCommand(preparedCommand, varConnection)) 
    { 
     sqlWrite.Parameters.AddWithValue("@var_agr_fname", var_agr_fname == "" ? (object) DBNull.Value : var_agr_fname); 
     sqlWrite.ExecuteNonQuery(); 
    } 
} 


public static SqlConnection sqlConnectOneTime(string varSqlConnectionDetails) 
{ 
    var sqlConnection = new SqlConnection(varSqlConnectionDetails); 
    try 
    { 
     sqlConnection.Open(); 
    } 
    catch 
    { 
     DialogResult result = MessageBox.Show(new Form {TopMost = true}, 
               "Błąd połączenia z bazą danych. Czy chcesz spróbować nawiązac połączenie ponownie?", 
               "Błąd połączenia (000001)", 
               MessageBoxButtons.YesNo, 
               MessageBoxIcon.Stop); 
     if (result == DialogResult.No) 
     { 
      if (Application.MessageLoop) 
      { 
       Application.Exit(); // Use this since we are a WinForms app 
      } 
      else 
      { 
       Environment.Exit(1); // Use this since we are a console app 
      } 
     } 
     else 
     { 
      sqlConnection = sqlConnectOneTime(varSqlConnectionDetails); 
     } 
    } 
    return sqlConnection; 
} 

Messaggio di errore: A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

Considerando consiglio per this error dovrei usare SqlConnection.ClearAllPools(); per assicurarsi che i collegamenti siano reset o scartati in modo corretto. Quindi posso usarlo ma la domanda è dove usarlo e quando? Come sapere se il limite si sta rompendo? Dov'è il limite? a 50/150/200? o dovrei usarlo ogni volta in un ciclo?

+3

Perché non attivare solo un 'SqlConnection' e usarlo esclusivamente? Sembra che tu stia usando qualsiasi thread, quindi questo dovrebbe funzionare senza alcun * hacky * 'SqlConnection.ClearAllPools()'. –

+0

Ho un metodo che riuso usandolo una o più volte. Fa tutto da stabilire una connessione (o usare quella che è già collegata) a restituire la connessione al pool. Questi sono i consigli che ho ricevuto. In questo modo riutilizza sempre la connessione se è aperta e se è chiusa la apro sempre. Non ho mai avuto un problema fino ad ora. Ho pensato/mi è stato detto che il pool di connessione si prenderà cura di esso per me quando uso 'using' :-) Sembra non :-) – MadBoy

+2

@Madboy: Sembra che tu abbia reinventato il Connection-Pool. Riutilizza sempre le connessioni se sono chiuse e non può riutilizzarle se sono aperte. Hai visto anche i link nelle altre domande (non accettato)? http://social.msdn.microsoft.com/Forums/en-US/sqldataaccess/thread/9609559d-f7ce-4bd8-97d0-0003ff7c9c98/ e http://blogs.msdn.com/b/spike/archive/2009/04/16/un-trasporto-level-error-è-accaduto-quando-invio-the-request-to-the-server-provider-tcp-fornitore-error-0-an-esistente-connection-stato-forza -closed-by-the-remote-host.aspx –

risposta

0

Quei 2 errori:

A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)

A transport-level error has occurred when sending the request to the server. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

hanno riguardato valore DateTime essere inseriti in SQL con la data prima del 1900 anno. La regola Microsoft qui è .. non memorizzare il valore DateTime meno di 1900 anni nel valore DateTime in SQL. Utilizzare invece una stringa ...

4

"Ho un metodo che riuso usandolo una o più volte. Fa tutto da stabilire una connessione (o usando quella già connessa) per restituire la connessione al pool. Ho avuto modo di riutilizzare sempre la connessione se è aperta e se è chiusa la apro sempre ".

Sembra che tu abbia reinventato il Connection-Pool. Riutilizza sempre le connessioni se sono chiuse e non può riutilizzarle se sono aperte.

Quindi chiudere la connessione nel blocco catch:

public static SqlConnection sqlConnectOneTime(string varSqlConnectionDetails) { 
    var sqlConnection = new SqlConnection(varSqlConnectionDetails); 
    try { 
     sqlConnection.Open(); 
    } catch { 
     //log and 
     sqlConnection.Close(); 
     throw 
    } 
    return sqlConnection; 
} 

Modifica: Per essere onesti non vorrei utilizzare tali metodi factory a tutti. Sono solo una fonte di errori non riproducibili. Quanto tempo richiede per creare e aprire la connessione in cui lo stai utilizzando?

using(SqlConnection varConnection = new SqlConnection(Locale.sqlDataConnectionDetails)) { 
    using (var sqlWrite = new SqlCommand(preparedCommand, varConnection)) { 
     sqlWrite.Parameters.AddWithValue("@varSecus_agr_fname", varSecus_agr_fname == "" ? (object) DBNull.Value : varSecus_agr_fname); 
     varConnection.Open(); 
     sqlWrite.ExecuteNonQuery(); 
    } 
} 

I primi due collegamenti sono dalla tua domanda legata (non la risposta accettata), potrebbero anche essere utili:

+0

Non chiudere la connessione se la prova riesce comunque? Restituendo comunque la stringa di connessione chiusa? Fondamentalmente ciò che fa il tuo codice è la connessione aperta e la chiude in un secondo. Mentre quello che doveva fare il mio codice è aprire la connessione in modo che possa essere usata e quando è fatto "usare" dovrebbe pulirlo/tornare al pool. – MadBoy

+0

@Madboy: hai ragione, corretto. Ad essere onesti non userei affatto questi metodi di fabbrica. Sono solo una fonte di errori non riproducibili. Quanto tempo richiede per creare e aprire la connessione in cui lo stai utilizzando? –

+0

Beh, posso cercarlo (è da qualche parte nelle mie domande sul profilo) quando stavo cercando l'uso corretto delle connessioni Apri/Chiudi è stato suggerito (e upvoted) che Se apro Connection e non lo chiudo esplicitamente verrà restituito al pool con 'using' e questa connessione' open' nel pool può essere ancora riutilizzata dalle query successive senza necessità di stabilire una connessione (quindi essere più veloce). Se lo dico esplicitamente a Apri e poi lo chiudo sempre, la prossima query durerà quanto il primo. – MadBoy

5

In primo luogo, lasciami sono sicuro che questo codice sia orribile. Stai mescolando l'interfaccia utente con la creazione della connessione dati. Inoltre, si mostra una finestra di dialogo all'interno di una sezione catch e si effettua una chiamata ricorsiva! Questo è molto caotico e di per sé può portare a errori e comportamenti imprevedibili. E la formattazione (originale) rende difficile la lettura. Ci scusiamo per l'aspro commento ma dovresti davvero ridisegnare questo codice.

A parte questo il tuo codice dovrebbe funzionare bene, ma se stai ricevendo l'errore No process is on the other end of the pipe. significa che c'è qualcosa di sbagliato nel tuo database e/o SQL Server. Sembra che si ostruisca e non accetta più connessioni. Se esegui batch di inserimenti in un breve periodo, eseguili su una connessione, se possibile. ClearAllPools è un modo per recuperare quando succede qualcosa di sbagliato e sarebbe meglio scoprire di cosa si tratta invece di coprirlo. È come prendere il paracetamolo quando il dente fa male e non va mai dal dentista.

Un'altra cosa è che l'utilizzo di più SqlConnections crea una transazione separata per ciascuna connessione. Ciò aggiunge carico su SQL Server anche se può sicuramente fare più di centinaia di transazioni al secondo.

Inoltre, è possibile modificare il trasporto su named pipe e TCP per vedere se cambia qualcosa.

+0

Sta accadendo generalmente su 3 computer diversi, quindi non è collegato al server o almeno non è qualcosa che posso vedere. Sulla pagina Microsoft http://msdn.microsoft.com/en-us/library/8xx3tyca.aspx#Y1790 suggeriscono che se la stringa di connessione è la stessa la connessione rimarrà aperta per le prossime connessioni in arrivo. Quindi se li sto facendo tutti in un ciclo foreach probabilmente è solo una connessione. Ovviamente il metodo è un esempio breve dato che ci sono circa 20 parametri anziché solo 1. Ma ciò non ha influito prima. E il problema inizia con 180 inserti. – MadBoy

+0

È vero che la vera connessione DB rimarrà aperta e verrà riutilizzata, ma la creazione di SqlConnection centinaia di volte per pochi secondi e quindi l'eliminazione per il garbage collector è un inutile sforzo sulle risorse (principalmente GC) –

+0

Fare qualche test - introdurre un ritardo tra Inserts e vedi cosa succede Vedi anche se cambia per rendere tutti gli inserti su una connessione. –