Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Es gibt bereits einen offenen DataReader ... obwohl es keiner ist

Ich vermute, das ist das Problem am Ende der Methode:

this.connectionPool.Putback(sqlConnection);

Du nimmst nur zwei Elemente aus dem Iterator - Sie vervollständigen also nie das while Schleife, es sei denn, es gibt tatsächlich nur einen Wert, der vom Reader zurückgegeben wird. Jetzt verwenden Sie LINQ, das automatisch Dispose() aufruft auf dem Iterator, also Ihr using -Anweisung wird den Leser immer noch entsorgen - aber Sie stellen die Verbindung nicht wieder in den Pool. Wenn Sie das in einem finally tun Block, ich denke, Sie werden in Ordnung sein:

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);
}

Oder idealerweise, wenn Ihr Verbindungspool Ihre eigene Implementierung ist, machen Sie Take etwas zurückgeben, das IDisposable implementiert und gibt die Verbindung an den Pool zurück, wenn sie fertig ist.

Hier ist ein kurzes, aber vollständiges Programm, um zu demonstrieren, was vor sich geht, ohne dass tatsächliche Datenbanken involviert sind:

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));
    }
}

Wie geschrieben - die Situation modellierend, wobei der Leser nur zwei Werte findet - ist die Ausgabe:

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

Beachten Sie, dass der Leser entsorgt wird, aber wir kommen nie so weit, etwas aus dem Pool zurückzugeben. Wenn Sie Main ändern um die Situation zu modellieren, in der der Leser nur einen Wert hat, wie folgt:

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

Dann kommen wir ganz durch while loop, also ändert sich die Ausgabe:

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

Ich schlage vor, Sie kopieren mein Programm und experimentieren damit. Stellen Sie sicher, dass Sie alles darüber verstehen, was vor sich geht ... dann können Sie es auf Ihren eigenen Code anwenden. Vielleicht möchten Sie meinen Artikel über Details zur Implementierung von Iteratorblöcken lesen auch.