2010-01-28 2 views
18

Per anni, ho riscontrato problemi molto strani su tutte le mie applicazioni Web che si collegano a un server SQL.Il pool di connessioni SQL Server non rileva connessioni chiuse?

Il problema è che se qualcosa accade al server del database (riavvio del server o altro problema), l'app web smette di funzionare da quel punto in poi, anche se il server del database è vivo e anche dopo.

Cosa accade è che ogni operazione ADO.NET (ExecuteNonQuery, CreateReader, BeginTransaction, ...) non riesce con un InvalidOperationException: "Operazione non valida La connessione è chiusa". Sembra che una chiamata a SqlConnection.Open() recupera una connessione dal pool di applicazioni che è ... chiuso!

Secondo la documentazione, il pool di connessioni dovrebbe rimuovere automaticamente le connessioni dal pool di connessioni reciso, ma pare una connessione chiusa non è considerata come "mozzata", così la chiamata a SqlConnection.Open() restituisce felicemente un connessione chiusa, supponendo che sia aperta, senza verificare questo.

mia soluzione attuale è quella di verificare lo stato della connessione subito dopo l'apertura è:

using (SqlConnection connection = new SqlConnection(connectionString)) 
{ 
    connection.Open(); 

    if (connection.State != ConnectionState.Open) 
    { 
     SqlConnection.ClearAllPools(); 

     connection.Open(); 
    } 

    // ... 
} 

Questa soluzione sembra funzionare per ora, ma non mi sento comodo fare questo.

Quindi le mie domande sono:

  1. Perché SqlConnection.Open() ritorno connessioni dal pool di connessioni chiusa?
  2. La mia soluzione alternativa è valida?
  3. C'è un modo migliore per gestire questo?

risposta

12

Ho fatto qualche ricerca simile sul pool di connessioni qualche tempo fa, per un motivo leggermente diverso, ma spero che sarà di qualche utilità. Quello che ho trovato è:

  1. anche quando si chiude una connessione in codice, viene restituito al pool senza che la connessione sia effettivamente chiusa, pronta per un ulteriore utilizzo.
  2. se tale connessione viene interrotta (ad esempio, il riavvio di SQL Server), quando la connessione viene restituita dal pool per un altro chiamante da utilizzare e tale chiamante esegue una .Open su di esso, non errore in quel punto quando il database il server è ancora inattivo. Questo fa parte del vantaggio in termini di prestazioni del pool di connessioni poiché in realtà non sta tornando al server del database per connettersi.
  3. quando si tenta effettivamente di eseguire un comando contro la connessione (ad es.ExecuteNonQuery) è a quel punto in realtà genera un'eccezione

Le connessioni vengono automaticamente rimosse dal pool, i miei risultati sono stati che ciò si è verificato in genere pochi minuti dopo l'ultimo utilizzo. Quindi, potrebbe trattarsi di un problema di temporizzazione - e vengono chiariti, ma non prima che le connessioni siano tentate di essere riutilizzate di nuovo.

Questi erano alcuni articoli ho guardato, al momento:
Sql Server Google Group
Using Connection Pooling in ASP.NET

Edit:
Suona strano che la cattiva connessione rimane nel pool per sempre - Sei sicuro che sicuramente lo fa, e non si tratta solo di più cattive connessioni? Se sei sicuro, sembra che quelle connessioni non vengano rilasciate correttamente all'interno del tuo codice. This è un altro ottimo articolo che ho letto qualche tempo fa, che dice (cito):

Connessioni automaticamente Flushing

Se una connessione in pool rimane nello stato “chiuso ma riutilizzabili” per tra il 4 e il 8 minuti (un intervallo scelto a caso) la connessione meccanismo di raggruppamento chiude la connessione fisica e scarta la connessione raggruppata. Questo a meno che il numero delle connessioni rimanenti sia maggiore rispetto alle connessioni minime configurate per il pool (il valore predefinito è 0). Si noti che una connessione deve essere chiusa dall'applicazione (e rilasciata nuovamente al pool) prima dello può essere soggetta alla versione automatica . Se non si chiude la connessione nel codice o orfano l'oggetto di connessione , il meccanismo di pool non farà nulla. No, ci sono non argomenti ConnectionString a modificare il valore di timeout.

+0

Potrei vivere con "pochi minuti", ma quando viene utilizzata la connessione, ovviamente genera un'eccezione, ma quella connessione "cattiva" rimane disponibile nel pool di connessioni per sempre. Non viene mai rimosso, sebbene ADO.NET abbia generato un'eccezione perché la connessione non era buona. –

2

Abbiamo visto lo stesso problema dal C++ usando ADO. Alcuni anni fa, dopo aver lavorato con il supporto Microsoft, abbiamo anche implementato una logica retry simile nel codice e ripristinato il pool di connessioni che risolveva il problema.

Se c'è una soluzione migliore, la gente del Supporto Microsoft non lo sapeva, o non lo condivideva (a quel tempo comunque).