sql >> Databasteknik >  >> RDS >> Mysql

Det finns redan en öppen DataReader ... även om den inte är det

Jag misstänker att detta är problemet, i slutet av metoden:

this.connectionPool.Putback(sqlConnection);

Du tar bara två element från iteratorn - så att du aldrig slutför while loop såvida det faktiskt bara är ett värde som returneras från läsaren. Nu använder du LINQ, som automatiskt anropar Dispose() på iteratorn, så du using uttalandet kommer fortfarande att förfoga över läsaren - men du lägger inte tillbaka anslutningen i poolen. Om du gör det i en finally blockera, jag tror att du kommer att klara dig:

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

Eller helst, om din anslutningspool är din egen implementering, gör Take returnera något som implementerar IDisposable och återställer anslutningen till poolen när den är klar.

Här är ett kort men komplett program för att visa vad som händer, utan några egentliga databaser inblandade:

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

Som skrivet - modellering av situationen med att läsaren bara hittar två värden - resultatet är:

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

Observera att läsaren är disponerad, men vi kommer aldrig så långt som att lämna tillbaka något från poolen. Om du ändrar Main att modellera situationen där läsaren bara har ett värde, så här:

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

Sedan tar vi oss hela vägen genom while loop, så utgången ändras:

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

Jag föreslår att du kopierar mitt program och experimenterar med det. Se till att du förstår allt om vad som händer... sedan kan du applicera det på din egen kod. Du kanske vill läsa min artikel om detaljer för implementering av iteratorblock också.



  1. MySQL ERROR 1046 (3D000):Ingen databas vald vid uppdateringsfrågan

  2. Vad är skillnaden mellan schema och databas?

  3. En databasmodell för en onlineundersökning. Del 1

  4. Få exekveringstid för PostgreSQL-fråga