我通过其.NET连接器(6.8.3)广泛使用MySQL服务器(5.6)数据库。出于性能原因,所有表都使用MyISAM引擎创建。我只有一个进程(更新:实际上不是这样,请参见下文),顺序访问DB,因此不需要事务和并发。
今天,在处理多个小时后,以下代码片段:
public IEnumerable<VectorTransition> FindWithSourceVector(double[] sourceVector)
{
var sqlConnection = this.connectionPool.Take();
this.selectWithSourceVectorCommand.Connection = sqlConnection;
this.selectWithSourceVectorCommand.Parameters["@epsilon"].Value
= this.epsilonEstimator.Epsilon.Min() / 10;
for (int d = 0; d < this.dimensionality; ++d)
{
this.selectWithSourceVectorCommand.Parameters["@source_" + d.ToString()]
.Value = sourceVector[d];
}
// *** the following line (201) throws the exception presented below
using (var reader = this.selectWithSourceVectorCommand.ExecuteReader())
{
while (reader.Read())
{
yield return ReaderToVectorTransition(reader);
}
}
this.connectionPool.Putback(sqlConnection);
}
以下异常信息被抛出:
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__3a`1.MoveNext() at System.Linq.Buffer`1..ctor(IEnumerable`1 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:line 38部分。
现在最有趣的部分是:当调试器在异常发生后停止执行时,我调查了sqlConnection对象,发现它没有与之关联的读取器(如下图)!
这是为什么会发生(显然是“随机”的 - 这个方法在过去的大约20小时内被调用了几乎每分钟一次)?我能避免这种情况吗(除了猜测添加一些睡眠时间,当Ping引发异常时并祈祷它会有帮助)?
关于连接池的实现的其他信息:
Get适用于仅调用简单查询且不使用读取器的方法,因此返回的连接可以以可重入方式使用。 在此示例中,它不直接使用(由于涉及读取器)。
public MySqlConnection Get()
{
var result = this.connections.FirstOrDefault(IsAvailable);
if (result == null)
{
Reconnect();
result = this.connections.FirstOrDefault(IsAvailable);
}
return result;
}
Reconnect
方法只是遍历整个数组并重新创建和打开连接。
Take
使用Get
,但也从可用连接列表中删除返回的连接,以防在某些方法使用读取器期间调用其他需要连接的方法时进行共享。在这里也不是这种情况,因为FindSourceVector
方法很简单(不调用使用DB的其他方法)。然而,出于惯例,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();
}
}
MySqlConnection
对象周围使用using
语句,如果检测到以前使用过相同的连接字符串且超时关闭底层连接,ADO.NET 将自动重用连接。 - Scott Chamberlainpooling=False
部分)- 直到今天... 但如果其他方法都无法帮助,我也会尝试回到内置的连接池,谢谢。 - BartoszKP