1

私は次のクラスを持っています:

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 メンバーが null であることです。

初期化時にtry-catchブロックがあり、例外がキャッチされないため、これは奇妙です(ログメカニズムを使用してこれを確認します)。

この動作はまれですが、ほぼ発生します。週に 1 回 (1 日に何百万ものクエリを実行しています)

この謎を解こうとする人に感謝します!!

4

2 に答える 2

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がtrueになります。そしてこれまでのところ、これはサーバーの問題であることが判明しています。少なくとも私の場合、問題は一貫しておらず、サーバーコードのマルチスレッドの問題のように見えます。

于 2013-01-11T14:19:59.907 に答える
-1

コードを確認しましたが、NULLリーダーを使用する唯一の方法は、初期化コードに例外を設けることです。

SqlDataReader.ExecuteReaderはすべての場合にオブジェクトを返すため、nullを返すことはできません。Tatiana Rachevaは、この回答のSqlDataReaderクラスを反映して確認しました。

NULLリーダーを使用する2番目のシナリオは、ManagedDataReaderオブジェクトがガベージコレクターによって破棄された後にリーダーを使用しようとしている場合です。

于 2012-01-31T09:26:38.160 に答える