Mysql
 sql >> Database >  >> RDS >> Mysql

C'è già un DataReader aperto... anche se non lo è

Sospetto che questo sia il problema, alla fine del metodo:

this.connectionPool.Putback(sqlConnection);

Stai solo prendendo due elementi dall'iteratore, quindi non completi mai il while ciclo a meno che non sia effettivamente un solo valore restituito dal lettore. Ora stai usando LINQ, che chiamerà automaticamente Dispose() sull'iteratore, quindi il tuo using l'istruzione eliminerà comunque il lettore, ma non rimetterai la connessione nel pool. Se lo fai in un finally blocco, penso che andrà tutto bene:

var sqlConnection = this.connectionPool.Take();
try
{
    // Other stuff here...

    using (var reader = this.selectWithSourceVectorCommand.ExecuteReader())
    {
        while (reader.Read())
        {
            yield return ReaderToVectorTransition(reader);
        }
    }
}
finally
{
    this.connectionPool.Putback(sqlConnection);
}

O idealmente, se il tuo pool di connessioni è la tua implementazione, fai Take restituire qualcosa che implementa IDisposable e restituisce la connessione al pool al termine.

Ecco un programma breve ma completo per dimostrare cosa sta succedendo, senza alcun reale database coinvolto:

using System;
using System.Collections.Generic;
using System.Linq;

class DummyReader : IDisposable
{
    private readonly int limit;
    private int count = -1;
    public int Count { get { return count; } }

    public DummyReader(int limit)
    {
        this.limit = limit;
    }

    public bool Read()
    {
        count++;
        return count < limit;
    }

    public void Dispose()
    {
        Console.WriteLine("DummyReader.Dispose()");
    }
}

class Test
{    
    static IEnumerable<int> FindValues(int valuesInReader)
    {
        Console.WriteLine("Take from the pool");

        using (var reader = new DummyReader(valuesInReader))
        {
            while (reader.Read())
            {
                yield return reader.Count;
            }
        }
        Console.WriteLine("Put back in the pool");
    }

    static void Main()
    {
        var data = FindValues(2).Take(2).ToArray();
        Console.WriteLine(string.Join(",", data));
    }
}

Come scritto, modellando la situazione con il lettore che trova solo due valori, l'output è:

Take from the pool
DummyReader.Dispose()
0,1

Nota che il lettore è disposto, ma non arriviamo mai al punto di restituire qualcosa dalla piscina. Se modifichi Main per modellare la situazione in cui il lettore ha un solo valore, come questo:

var data = FindValues(1).Take(2).ToArray();

Quindi andiamo fino in fondo attraverso il while loop, quindi l'output cambia:

Take from the pool
DummyReader.Dispose()
Put back in the pool
0

Ti suggerisco di copiare il mio programma e di sperimentarlo. Assicurati di capire tutto su cosa sta succedendo... quindi puoi applicarlo al tuo codice. Potresti voler leggere il mio articolo sui dettagli sull'implementazione del blocco iteratore anche.