1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ExecuteReaderを使用したらMaxPoolSize超過した失敗事例

Posted at

はじめに

ログに実行したSQLを出力するように修正した際に、ExecuteReaderの使用箇所を1メソッドに纏めるように修正をしたのですが、アプリケーションを使用しているうちに何も動作しなくなり、MaxPoolSizeが超過した例外メッセージが出力されました。

変更内容

変更前

省略して書いてます。
社内のDB操作ライブラリーを使用しているので、記述が一般と若干違います。

using DbProduct manager = new DbAdapter(DBInfo).Create()
{
   // DB接続
   manager.ConnectDB(false);

   string message = "メソッド名";
   Logger.DebugSQL(message, sql, sqlParameter);
   DbDataReader reader = manager.ExecuteReader(sql, sqlParameter);
}

変更後

Readerメソッド側に接続情報を移動させました。

string message = "メソッド名";
using (DbDataReader reader = Reader(messaage, sql, sqlParameter))

DbProductusingで囲んでしまうと、呼び出し先のreadercloseされているとのエラーになるので、 接続側のusingを外しました。
これにより値は取得できていたので、よしとしていた。

static DbDataReader Reader(string messaage, string sql, params object[] sqlParameter)
{
    DbProduct manager = new DbAdapter(DBInfo).Create();
    // DB接続
    manager.ConnectDB(false);

    Logger.DebugSQL(message, sql, sqlParameter);

    return DbDataReader reader = manager.ExecuteReader(sql, sqlParameter);
}

MaxPoolSize 超過エラー

ところが、アプリケーションを使用しているうちに何も動作しなくなり、MaxPoolSizeが超過した例外メッセージが出力されました。

そこでPostgreSQLのpsqlコマンドで、2秒単位で接続数を監視できるので実行してみました。
すると、アプリケーションを動かしていくたびに、どんどん接続数が増えていきました。

SELECT numbackends FROM pg_stat_database; \watch

改善内容

接続に関しては、DbProductusing で囲む必要がありましたね。
でも、出来るだけ使用箇所を纏めたい。

主な使用用途として、存在確認とデータ1個取得です。
それ以外は、これまで通り manager を引数に渡してデータ取得するようにしています。

値取得
static DbDataReader Reader(DbProduct manager, string messaage, string sql, params object[] sqlParameter)
{
    DbDataReader reader;
    if (sqlParameter.Length == 0)
    {
        Logger.DebugLogSQL(message, sql);
        reader = manager.ExecuteReader(sql);
    }
    else
    {
        Logger.DebugLogSQL(message, sql, sqlParameter);
        reader = manager.ExecuteReader(sql, sqlParameter);
    }

    return reader;
}
レコード存在確認用
public static bool HasReader(string message, string sql, params object[] sqlParameter)
{
    bool result = false;
    using (DbProduct manager = new DbAdapter(DBInfo).Create())
    {
        // DB接続
        manager.ConnectDB(false);

        using DbDataReader reader = Reader(manager, message, sql, sqlParameter);
        result = reader.HasRows;
    }

    return result;
}

// 使用例
bool result = HasReader("ExistsPass:合格有無確認", sql, sqlParameter);
データ1個取得用
public static T? Scalar<T>(string message, string sql, params object[] sqlParameter)
{
    using (DbProduct manager = new DbAdapter(DBInfo).Create())
    {
        // DB接続
        manager.ConnectDB(false);

        using DbDataReader reader = Reader(manager, message, sql, sqlParameter);
        if (reader.HasRows)
        {
            reader.Read();
            Object obj = reader.GetValue(0);

            switch (obj)
            {
                case int i:
                    return (T)(object)i;
                case long l:
                    return (T)(object)l;
                case double d:
                    return (T)(object)d;
                case decimal dc:
                    return (T)(object)dc;
                case float f:
                    return (T)(object)f;
                case bool b:
                    return (T)(object)b;
                case DateTime dt:
                    return (T)(object)dt;
                case string s:
                    return (T)(object)s;
                default:
                    return (T)(object)default!;
            }
        }
    }

    return default;
}

// 使用例
int result = (int)Scalar<decimal>("GetMaxRepeatCount:繰り返し最大回数取得", sql, sqlParameter);

そういえば、SQLで、nvl(MAX(pass_type), 0) で値を取得した際の型は、decimal型なんですよね。
ジェネリクスメソッドで、Scalar を指定すると、型変換エラーになってしまいました。

最後に

using (DbDataReader reader = Reader(・・・ として、usingで囲んだから、呼び出し先の接続も閉じると思ってしまったのは失敗でした。
接続は、接続で閉じないと駄目でしたね。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?