Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Jest już otwarty DataReader… mimo że tak nie jest

Podejrzewam, że to jest problem, na końcu metody:

this.connectionPool.Putback(sqlConnection);

Tylko zabierasz dwa elementy z iteratora - więc nigdy nie kończysz while pętla, chyba że w rzeczywistości zwrócona jest tylko jedna wartość z czytnika. Teraz używasz LINQ, który automatycznie wywoła Dispose() na iteratorze, więc Twoje using oświadczenie nadal będzie usuwać czytnik - ale nie przywracasz połączenia z powrotem do puli. Jeśli zrobisz to w finally blok, myślę, że wszystko będzie dobrze:

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

Lub najlepiej, jeśli twoja pula połączeń jest twoją własną implementacją, wykonaj Take zwrócić coś, co implementuje IDisposable i po zakończeniu zwraca połączenie z powrotem do puli.

Oto krótki, ale kompletny program pokazujący, co się dzieje, bez żadnych rzeczywistych baz danych:

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

Jak napisano - modelowanie sytuacji z czytnikiem znajdowania tylko dwóch wartości - wynik to:

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

Zwróć uwagę, że czytnik jest unieszkodliwiony, ale nigdy nie dochodzimy do zwrócenia czegokolwiek z puli. Jeśli zmienisz Main do modelowania sytuacji, w której czytnik ma tylko jedną wartość, na przykład:

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

Następnie przechodzimy przez cały while pętla, więc wyjście się zmienia:

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

Proponuję skopiować mój program i poeksperymentować z nim. Upewnij się, że rozumiesz wszystko o tym, co się dzieje... wtedy możesz zastosować to do własnego kodu. Możesz przeczytać mój artykuł o szczegółach implementacji bloku iteratorów też.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sprawdź, czy wiersz istnieje w bazie danych przed wstawieniem

  2. Znajdź kombinacje spełniające kryteria z zakresu

  3. MySql wybierz w polach zawierających wartości null

  4. Wybór ostatniego rzędu BEZ jakiegokolwiek klawisza

  5. Jak wyświetlić błędy dla mojego zapytania MySQLi?