Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Já existe um DataReader aberto... mesmo que não seja


Eu suspeito que este é o problema, no final do método:
this.connectionPool.Putback(sqlConnection);

Você está apenas tomando dois elementos do iterador - para que você nunca complete o while loop, a menos que haja apenas um valor retornado do leitor. Agora você está usando o LINQ, que chamará automaticamente Dispose() no iterador, então seu using ainda estará descartando o leitor - mas você não está colocando a conexão de volta no pool. Se você fizer isso em um finally bloco, eu acho que você vai ficar bem:
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);
}

Ou, idealmente, se seu pool de conexões for sua própria implementação, faça Take retorna algo que implementa IDisposable e retorna a conexão de volta ao pool quando terminar.

Aqui está um programa curto, mas completo, para demonstrar o que está acontecendo, sem nenhum banco de dados real envolvido:
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));
    }
}

Conforme escrito - modelando a situação com o leitor encontrando apenas dois valores - a saída é:
Take from the pool
DummyReader.Dispose()
0,1

Observe que o leitor está disposto, mas nunca chegamos a devolver nada do pool. Se você alterar Main para modelar a situação onde o leitor tem apenas um valor, assim:
var data = FindValues(1).Take(2).ToArray();

Em seguida, percorremos todo o caminho while loop, então a saída muda:
Take from the pool
DummyReader.Dispose()
Put back in the pool
0

Eu sugiro que você copie meu programa e experimente com ele. Certifique-se de entender tudo sobre o que está acontecendo... então você pode aplicá-lo ao seu próprio código. Você pode querer ler meu artigo sobre detalhes da implementação do bloco do iterador também.