プロシジャーCALLでのタイムアウト設定方法について

41 views
Skip to first unread message

志水正幸

unread,
Dec 13, 2019, 12:39:32 AM12/13/19
to DBFluteユーザの集い
志水です。
こんにちは。

プロシジャー実行でタイムアウトとなってしまいます。
実行環境ですが
プロシジャー実行するのは
バック側アプリケーションなのですが
フロント側とDBFlute環境は共用していますので
できればバック側実行時のみタイムアウト設定を無制限としたいです。

下記のようにCbeanを使う場合はタイムアウト設定ができるようなのですが
cb.configure(new StatementConfig().queryTimeout(3000)); 

下記のようにプロシージャCALLする場合の
タイムアウト設定ってどうやればいいんでしょうか?
Bhv.OutsideSql().Call(pmb);

マニュアルみると
littleAdjustmentMap.dfprop の extendedDBFluteInitializerClass で 
DBFluteInitializer を継承した独自のクラスを設定することができます(@since 0.9.8.4)
とありますが、(@since 0.9.8.4)ということは.NET版は未対応ってことですよね?


以上、ご教示宜しくお願い致します。

kubo

unread,
Dec 13, 2019, 1:49:10 AM12/13/19
to DBFluteユーザの集い
jfluteです

志水さん、こんにちは

Java版だと、このように書けるのですが...
memberBhv.outsideSql().configure(conf -> conf.createSnapshot()).call(pmb);

// 外だしSQL(OutsideSql)
http://dbflute.seasar.org/ja/manual/function/ormapper/outsidesql/index.html
↑configure()ページがまだなく灰色になってはいますが...

.NET版でConfigure()メソッドいないでしょうか?

志水正幸

unread,
Dec 13, 2019, 3:14:12 AM12/13/19
to DBFluteユーザの集い
志水です。

jfluteさん、いつもお世話になっております。

configureありましたが実行しても効果ないようです。
※下記のように書きました。
           StatementConfig statementConfig = new StatementConfig();
            statementConfig.QueryTimeout(0);
            Bhv.OutsideSql().Configure(statementConfig).Call(pmb);

ちなみに
BasicCommandFactoryの
        private int commandTimeout = -1; ⇒ 0に書き換えて実行したら
  タイムアウト設定が効きました。

StatementConfig で設定した後に実行してもBasicCommandFactoryのcommandTimeout は
書き換わってくれてませんでした。

コードの書き方間違っているのでしょうか?

以上、宜しくお願い致します。












2019年12月13日金曜日 15時49分10秒 UTC+9 jflute:

uparrow

unread,
Dec 13, 2019, 3:36:17 AM12/13/19
to DBFluteユーザの集い
uparroと申します。

C# の OutsideSQLでタイムアウトは

string path = HogeBhv.PATH_selectSelHogeList;
SelHogeListPmb pmb = new SelHogeListPmb();
ListResultBean<SelHogeList> dbEntityList = flxOrderBhv.OutsideSql().
    Configure(new StatementConfig().QueryTimeout(80 * 1000)).
    SelectList<SelHogeList>(path, pmb);
 
のようなコードで書いていた部分はありました。

志水正幸

unread,
Dec 13, 2019, 3:55:38 AM12/13/19
to DBFluteユーザの集い
志水です。

uparroさん、こんばんは。

ありがとうございます。


StatementConfig の使い方としては私の書いたコードと同じようなので合ってそうですね。
提示いただいた書き方でタイムアウト設定はうまくいっていますか?





2019年12月13日金曜日 17時36分17秒 UTC+9 uparrow:

kubo

unread,
Dec 13, 2019, 6:09:57 AM12/13/19
to DBFluteユーザの集い
jfluteです

sourceをStatementConfigで単純に検索すると...
TnBasicCommandFactory@CreateCommand() で反映しているようですね。

まずは、そこで cmd.CommandTimeout に指定された値がちゃんと入っているか?
確認してみると良さそうです。

まあ、どこかで StatementConfig の値が、ADO.NET が渡ってないのだと思うのですが。
(例えば、ストアドプロシージャだけ処理が特殊で値が渡らないとか)

uparrow

unread,
Dec 15, 2019, 5:46:38 PM12/15/19
to DBFluteユーザの集い
志水さん

uparrowです。
最近はStatementConfig を利用していないのですが、以前SQLServer2014を利用していた際は、こちらの設定でOutsideSQLでSelectする際にタイムアウトは効いていたと思います。
プロシジャは利用していなかったので、Callではわかりません。

よろしくお願いいたします。

志水正幸

unread,
Dec 15, 2019, 9:13:20 PM12/15/19
to DBFluteユーザの集い
志水です。

uparrowさんありがとうございます。
やはりCALLとはタイムアウトの設定が違うんでしょうね。
jfluteさんのレスとおり調査してみます。。

志水正幸

unread,
Dec 15, 2019, 11:57:36 PM12/15/19
to DBFluteユーザの集い
志水です。

jfluteさん、こんにちは。

下記の箇所をデバッグで追ってみたのですが
結果的にcmd.CommandTimeout には①の場合でも正しく値がセットされていました。
しかし、不思議なことに①のStatementConfigで設定して動作させるとタイムアウトになってしまいます。
②のcommandTimeout を直接変更した場合はやはり問題なく正常終了します。
私には同じようにセットされていると思うのですが・・
ちょっと見当がつかないのですが、もっと根深い部分の話なのでしょうかねぇ・・・


        public override IDbCommand CreateCommand(IDbConnection conn, string sql) {
            IDbCommand cmd = conn.CreateCommand();
            cmd.CommandText = ChangeSignSql(cmd, sql);
            StatementConfig defaultStatementConfig = DBFluteConfig.GetInstance().DefaultStatementConfig;
            bool internalDebug = DBFluteConfig.GetInstance().IsInternalDebug;
            StatementConfig config = FindStatementConfigOnThread();

            if (config != null && config.HasQueryTimeout()) {
①StatementConfigで設定した場合はココをとおる
                if (internalDebug) {
                    _log.Debug("...Setting statement config as request: " + config);
                }
                cmd.CommandTimeout = config.GetQueryTimeout().Value;// DBFlute original logic.

            } else if (defaultStatementConfig != null && defaultStatementConfig.HasQueryTimeout()) {
                if (internalDebug) {
                    _log.Debug("...Setting statement config as default: " + config);
                }
                cmd.CommandTimeout = defaultStatementConfig.GetQueryTimeout().Value;// DBFlute original logic.
            } else {

②BasicCommandFactoryの  private int commandTimeout の値を0にした場合はココをとおる
                if (CommandTimeout > -1) {
                    cmd.CommandTimeout = CommandTimeout;// S2Dao original logic.
                }
            }
            return cmd;
        }
        
ExecuteNonQuery実行時のcmdのCommandTimeout は変更した内容が正しく入っていた
       
        public static int ExecuteNonQuery(IDataSource dataSource, IDbCommand cmd)
        {
            try
            {
                dataSource.SetTransaction(cmd);
                return cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                throw new SQLRuntimeException(ex, cmd.CommandText);
            }
        }           





kubo

unread,
Dec 16, 2019, 12:39:54 AM12/16/19
to DBFluteユーザの集い
jfluteです

志水さん、こんにちは、詳細デバッグありがとうございます。

なんと不思議ですね...
自分も少しコード読んでみましたが、プロシージャのときでも、
TnBasicCommandFactory@CreateCommand() が使われますものね。

セットするタイミングとか、セットする場所とか...

BasicCommandFactoryの中のソースコードが気になるのですが、
これのnamespaceわかります?

(C#はusingでクラス名がないので、コードだけだとどこのクラスかわからない...)

kubo

unread,
Dec 16, 2019, 1:52:46 AM12/16/19
to DBFluteユーザの集い
jfluteです

BasicCommandFactory.csは、Github上で発見しました。
(ブランチに隠れてて素直に見つからなかった...)
https://github.com/seasarorg/s2container.net/blob/s2container.net-v1.4-for.NET4.0/s2container.net/source/Seasar/Seasar.Extension.ADO/Impl/BasicCommandFactory.cs

// CommandTimeoutのプロパティ定義
public int CommandTimeout { get; set; } = -1;
...
// IDbCommandの生成: Tn側のクラスでオーバーライドされるのでこっちは動かないはず
public virtual IDbCommand CreateCommand(IDbConnection con, string sql)
{
var cmd = con.CreateCommand();
cmd.CommandText = ChangeSignSql(cmd, sql);
if (CommandTimeout > -1)
{
cmd.CommandTimeout = CommandTimeout;
}
return cmd;
}
...
// 実行するときに呼ばれる。インスタンス変数は何も使ってないので何を影響はなさそう
public virtual int ExecuteNonQuery(IDataSource dataSource, IDbCommand cmd)
{
return CommandUtil.ExecuteNonQuery(dataSource, cmd);
}

> ExecuteNonQuery実行時のcmdのCommandTimeout は変更した内容が正しく入っていた

ここがすべてを物語るはずで、セットする元データ次第で効く効かないが変わるとは思えませんもんね。
(どっちのやり方にしても、最終的に IDbCommand に CommandTimeout は入っていると)


ここまで来たら完全に論理的な矛盾を抱えていますから、
どこかしら前提と思ってしまっているロジックが実は違った、分析で間違ったところがあった、
ということがあるかもしれません。状況を変えて試し実行して要因を増やしていく方が良いですね。


例えば、TnBasicCommandFactory@CreateCommand() の中の、
「ここを通ったときは効いている」という S2Dao original logic. 側の else の方で、
if分岐を外して以下のように書き換えて実行してみると、どうなるでしょう?
(StatementConfigは利用せずに)

cmd.CommandTimeout = 0 ; // S2Dao original logic.

また、その else では完全に何もせず(CommandTimeout設定しない)、
デバッガーで private int commandTimeout の値を0にした場合、どうなるでしょう?


cmd.CommandTimeout のセット処理が影響しているのか?
BasicCommandFactoryのCommandTimeout が直接的にどこかで盛況しているのか?

その辺の切り分けができればと。

志水正幸

unread,
Dec 16, 2019, 4:29:50 AM12/16/19
to DBFluteユーザの集い
志水です。


添付の検証やってみましたが
すべて正常に実行できました。
私的には検証2のStatementConfig使ったら直接セットもダメなんじゃ
と思ったんですが。。





2019年12月16日月曜日 15時52分46秒 UTC+9 jflute:
プロシジャーのタイムアウト検証.txt
プロシジャーのタイムアウト検証2.txt
プロシジャーのタイムアウト検証3.txt

kubo

unread,
Dec 16, 2019, 5:06:47 AM12/16/19
to DBFluteユーザの集い
jfluteです

検証ありがとうございます。

検証3つがすべて効くとなれば、
「BasicCommandFactoryのCommandTimeoutプロパティの値を経由するかは関係ない」
ってことは言えて...

逆に、
「StatementConfigのGetQueryTimeout()の値を経由すると効かない」
って言えますかね。

要は、

cmd.CommandTimeout = config.GetQueryTimeout().Value;// DBFlute original logic.
(効かない)



cmd.CommandTimeout = 0;// S2Dao original logic.
(効く)

の違い。


検証1の続きで、StatementConfigをその場でnewして固定で0入れて、
StatementConfigからcmd.CommandTimeoutに直接セットするとどうでしょう?
(int と int? の違いが何か作用してたりするかなぁ...)

StatementConfig config = new StatementConfig().QueryTimeout(0);
Console.WriteLine(config.GetQueryTimeout().Value); // 0が入っていることの確認

cmd.CommandTimeout = config.GetQueryTimeout().Value;// DBFlute original logic.
Console.WriteLine(cmd.CommandTimeout); // 0が入っていることの確認

とまあ、どんどん狭めていくしか無いので、思い付いた検証たくさんやってみると良いです。
(StatementConfigのソースコードも書き換えたり)

志水正幸

unread,
Dec 20, 2019, 4:35:30 AM12/20/19
to DBFluteユーザの集い
志水です。

jfluteさん。ありがとうございます。

いままで担当者に指示してテストしてもらってたのですが
どうにも、ソースコードとテスト結果に合点がいかなかったので
自分でテストしたくて当該機能の完成を待っていたため
返信が遅くなりました。

今日、当該機能が完成したので自分で試しに実行したところ
StatementConfigにゼロをセットすることでタイムアウトせず正常に終了することができました。
おそらくですが、
共有しているDBFlute環境を持つ本体プロジェクト側のビルトもしくは
当該機能のリビルトが上手くできておらず、本体プロジェクト側のDLLを
うまく取り込めていなかったのかな?と思います。

jfluteさん、お忙しいところ対応していただいていたのに
まさかのこういう結果で申し訳ありません。

以上、お騒がせいたしました。。

kubo

unread,
Dec 20, 2019, 5:01:33 AM12/20/19
to DBFluteユーザの集い
jfluteです

いやいや、要件が満たせたということで良かった良かったです。
じっくり分析・検証することで「こう考えるしかないよね」ってのが納得できるわけなので、
それまでのやり取りや作業はぜんぜん無駄なことじゃないです。
(かなり勉強になったと思いますし^^)

志水正幸

unread,
Dec 20, 2019, 11:51:31 AM12/20/19
to DBFluteユーザの集い
志水です。

そうですね。
自分の合点のいく結果となりましたし
いい勉強になりました。
またよろしくお願いいたします。
Reply all
Reply to author
Forward
0 new messages