我有以下课程:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using MySql.Data.MySqlClient;
namespace DataBaseModule.General
{
public class ManagedDataReader : IDisposable
{
private bool _disposed = false;
private MySqlCommand _command;
private MySqlDataReader _dataReader;
// The class constructor.
public ManagedDataReader(string StrSQL)
: this(new MySqlCommand(StrSQL))
{
}
public ManagedDataReader(MySqlCommand SQL_Cmd)
{
try
{
_command = SQL_Cmd;
_command.Connection = new MySqlConnection(DbAccessProvider._connectionString);
DbAccessProvider.SqlCommandsPerformed++;
_command.Connection.Open();
_dataReader = _command.ExecuteReader();
}
catch (Exception ex)
{
DataBaseModule.Log.CommonLogger.Log_Database_Error(new Exception("Sql command Was: " + _command.CommandText, ex));
throw ex;
}
}
public int VisibleFieldCount()
{
return _dataReader.VisibleFieldCount;
}
public bool Read()
{
return _dataReader.Read();
}
public object this[int i]
{
get
{
if (_dataReader[i].Equals(DBNull.Value))
{
return null;
}
else
{
return _dataReader[i];
}
}
}
public object this[string FieldName]
{
get
{
if (_dataReader[FieldName].Equals(DBNull.Value))
{
return null;
}
else
{
return _dataReader[FieldName];
}
}
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this._disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
if (_dataReader != null)
{
_dataReader.Close();
}
if (_command != null)
{
if (_command.Connection != null)
{
_command.Connection.Dispose();
_command.Connection = null;
//Free the reference.
}
_command.Dispose();
}
}
// Call the appropriate methods to clean up
// unmanaged resources here.
// If disposing is false,
// only the following code is executed.
// Note disposing has been done.
_disposed = true;
}
}
// This finalizer will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide finalize methods in types derived from this class.
~ManagedDataReader()
{
// Do not re-create Dispose clean-up code here.
// Calling Dispose(false) is optimal in terms of
// readability and maintainability.
Dispose(false);
}
}
}
我的问题是,由于某些原因,有时我在调用Read()时遇到异常: 例外是我的_dataReader成员为空。
这很奇怪,因为我在初始化时有try-catch块,没有捕获异常(我使用我的登录机制来检查)。
此行为很少见,但会出现aprox。每周一次(我每天运行数百万次查询)
非常感谢那些试图解决这个问题的人!
答案 0 :(得分:2)
我想出了同样的问题。事实证明,在某些情况下,ExecuteReader()实际上可以返回null。
我查了连接器的代码,这就是我找到的:
catch (MySqlException ex)
{
...
// if we caught an exception because of a cancel, then just return null
if (ex.IsQueryAborted)
return null;
当服务器返回 MySqlErrorCode.QueryInterrupted 或 MySqlErrorCode.FileSortAborted 时,深入挖掘 IsQueryAborted 是正确的。到目前为止,事实证明这是一些服务器问题,至少在我的情况下,问题不一致,看起来像服务器代码中的多线程问题。
答案 1 :(得分:-1)
我查看了代码,我发现使用NULL读取器的唯一方法是在初始化代码中有一个例外。
由于SqlDataReader.ExecuteReader在所有情况下都返回一个对象,并且不能返回null。 Tatiana Racheva通过this answer中的反射SqlDataReader类确认了这一点。
拥有NULL读取器的第二种情况是,如果您在垃圾收集器处理ManagedDataReader对象后尝试使用读取器。