c# – 已经有一个开放的DataReader ……即使它没有

c# – 已经有一个开放的DataReader ……即使它没有,第1张

概述注意:当问题没有正确处理读取器/连接时,或者错误是由于处理不当的延迟加载时,我已经经历了数百万个问题.我相信这个问题是另一个问题,可能与MySQL的.NET连接器有关.我通过其.NET连接器(6.8.3)广泛使用MySQL服务器(5.6)数据库.出于性能原因,所有表都是使用MyISAM引擎创建的.我只有一个进程有一个线程(更新:事实上,它不是真的,见下文)顺

注意:当问题没有正确处理读取器/连接时,或者错误是由于处理不当的延迟加载时,我已经经历了数百万个问题.我相信这个问题是另一个问题,可能与MySQL的.NET连接器有关.

我通过其.NET连接器(6.8.3)广泛使用MysqL服务器(5.6)数据库.出于性能原因,所有表都是使用MyISAM引擎创建的.我只有一个进程有一个线程(更新:事实上,它不是真的,见下文)顺序访问数据库,因此不需要事务和并发.

今天,经过几个小时的处理,下面这段代码:

public IEnumerable

抛出以下异常:

MysqLException: There is already an open DataReader associated with this Connection which must be closed first.

这是堆栈跟踪的相关部分:

at mysql.data.MysqLClIEnt.ExceptionInterceptor.Throw(Exception exception)
at mysql.data.MysqLClIEnt.MysqLConnection.Throw(Exception ex)
at mysql.data.MysqLClIEnt.MysqLCommand.CheckState()
at mysql.data.MysqLClIEnt.MysqLCommand.ExecuteReader(CommandBehavior behavior)
at mysql.data.MysqLClIEnt.MysqLCommand.ExecuteReader()
at implementation.VectorTransitionsMysqLtable.d__27.MoveNext() in C:\Users\bartoszp…\implementation\VectorTransitionsMysqLtable.cs:line 201

at System.linq.Enumerable.d__3a1.MoveNext()
at System.linq.Buffer
1..ctor(IEnumerable1 source)
at System.linq.Enumerable.ToArray[TSource](IEnumerable
1 source)
at implementation.VectorTransitionService.Add(VectorTransition vectorTransition) in C:\Users\bartoszp…\implementation\VectorTransitionService.cs:line 38

at Program.Go[T](Environment`2 p,Space parentSpace,Epsilonestimator epsilonestimator,ThresholdEstimator thresholdEstimator,Transitiontransformer Transitiontransformer,AmbiguityCalculator ac,VectorTransitionstableFactory vttf,AxestableFactory atf,NeighbourhoodstableFactory ntf,AmbiguitySamplestableFactory astf,AmbiguitySampleMatchestableFactory asmtf,MysqLConnectionPool connectionPool,Boolean rejectDuplicates,Boolean addNew) in C:\Users\bartoszp…\Program.cs:line 323

connectionPool.Take返回满足以下谓词的第一个连接:

private bool IsAvailable(MysqLConnection connection){    var result = false;    try    {        if (connection != null            && connection.State == System.Data.ConnectionState.Open)        {            result = connection.Ping();        }    }    catch (Exception e)    {        Console.Writeline("Ping exception: " + e.Message);    }    return result && connection.State == System.Data.ConnectionState.Open;}

(这与我之前的问题有关,当我解决了一个不同但相似的问题时:MySQL fatal error during information_schema query (software caused connection abort))

FinDWithSourceVector方法由以下代码调用:

var existing    = this.vectorTransitionstable        .FinDWithSourceVector(vectorTransition.sourceVector)        .Take(2)        .ToArray();

(我需要找到最多两个重复的向量) – 这是堆栈跟踪的VectorTransitionService.cs:第38行的一部分.

现在最有趣的部分:当调试器在异常发生后停止执行时,我已经调查了sqlConnection对象来查找,它没有与之关联的阅读器(如下图所示)!

为什么会发生这种情况(显然是“随机” – 这种方法几乎每隔一分钟被调用一次,直到最后~20h)?我可以避免这种情况(以其他方式猜测 – 当Ping抛出异常并祈祷它会帮助时添加一些睡眠)?

有关连接池实现的其他信息:

Get适用于仅调用简单查询且不使用读取器的方法,因此返回的连接可以以可重入的方式使用.它不直接在此示例中使用(因为涉及读者):

public MysqLConnection Get(){    var result = this.connections.FirstOrDefault(IsAvailable);    if (result == null)    {        Reconnect();        result = this.connections.FirstOrDefault(IsAvailable);    }    return result;}

重新连接方法只是迭代整个数组并重新创建并打开连接.

使用Get但也从可用连接列表中删除返回的连接,因此,如果某些方法在使用读取器期间调用其他需要连接的方法,则不会共享它.这也不是这种情况,因为FindSourceVector方法很简单(不调用使用DB的其他方法).但是,Take用于约定 – 如果有读者,请使用Take:

public MysqLConnection Take(){    var result = this.Get();    var index = Array.IndexOf(this.connections,result);    this.connections[index] = null;    return result;}

Putback只是将连接放到第一个空位,或者只是在连接池已满时忘记它:

public voID Putback(MysqLConnection MysqLConnection){    int index = Array.IndexOf(this.connections,null);    if (index >= 0)    {        this.connections[index] = MysqLConnection;    }    else if (MysqLConnection != null)    {        MysqLConnection.Close();        MysqLConnection.dispose();    }}
最佳答案我怀疑这是问题,在方法结束时:

this.connectionPool.Putback(sqlConnection);

你只从迭代器中取两个元素 – 所以你永远不会完成while循环,除非读者只返回一个值.现在您正在使用liNQ,它将自动在迭代器上调用dispose(),因此您的using语句仍将处理读取器 – 但您不会将连接放回池中.如果你在finally块中这样做,我想你会没事的:

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

或者理想情况下,如果您的连接池是您自己的实现,请使Take返回实现Idisposable的内容,并在完成后将连接返回池中.

这是一个简短但完整的程序,用于演示正在发生的事情,而不涉及任何实际的数据库:

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

正如所写 – 对读者仅仅找到两个值的情况进行建模 – 输出是:

Take from the poolDummyReader.dispose()0,1

请注意,阅读器处理完毕,但我们从来没有从池中返回任何内容.如果您更改Main以模拟读者只有一个值的情况,如下所示:

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

然后我们一直通过while循环,所以输出改变:

Take from the poolDummyReader.dispose()Put back in the pool0

我建议你复制我的程序并进行实验.确保您了解正在发生的事情……然后您可以将其应用于您自己的代码.您可能也想阅读我在iterator block implementation details上的文章. 总结

以上是内存溢出为你收集整理的c# – 已经有一个开放的DataReader ……即使它没有全部内容,希望文章能够帮你解决c# – 已经有一个开放的DataReader ……即使它没有所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1168953.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-02
下一篇 2022-06-02

发表评论

登录后才能评论

评论列表(0条)