2

MyBatis を使用して呼び出す必要があるストアド プロシージャがあります。とにかく、このストアドプロシージャを呼び出すことができました。プロシージャには複数の出力パラメータがあります。out パラメータの 1 つは Oracle カーソルです。Oracle Cursor を反復処理する必要がありますが、fetchSize 属性を使用して jdbc ドライバーを微調整せずにこれを行うと、行ごとに処理され、このソリューションは非常に遅くなります。プロシージャ コールの fethcSize 属性を設定できます。

<select id="getEvents" statementType="CALLABLE" parameterMap="eventInputMap" fetchSize="1000">
    {call myProc(?, ?, ?, ?, ?)}
</select>

しかし、これはまったく役に立ちません。複数の out パラメータがあるため、これは機能しないと思います。そのため、プログラムは、このフェッチ サイズをどこに適用する必要があるか、どの out パラメータに適用するかわかりません。ResultSet(Oracleカーソル)にフェッチサイズを設定する方法はありますか? java.sql パッケージの CallableStatemen を使用する場合と同様に、ResultSet フェッチ サイズを設定できます。

以下は、プログラムからのマッピング ファイルとプロシージャ コールです。

  <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
          "http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">

<mapper namespace="mypackage.EventDao">

    <resultMap id="eventResult" type="Event">
        <result property="id" column="event_id" />
        <result property="name" column="event_name" />
    </resultMap>

    <parameterMap id="eventInputMap" type="map" >
        <parameter property="pnNetworkId" jdbcType="NUMERIC" javaType="java.lang.Integer" mode="IN"/>
        <parameter property="pvUserIdentityId" jdbcType="VARCHAR" javaType="java.lang.String" mode="IN"/>
        <parameter property="result" resultMap="eventResult" jdbcType="CURSOR" javaType="java.sql.ResultSet" mode="OUT" />
        <parameter property="success" jdbcType="INTEGER" javaType="java.lang.Integer" mode="OUT"/>
        <parameter property="message" jdbcType="VARCHAR" javaType="java.lang.String" mode="OUT"/>
    </parameterMap>



    <select id="getEvents" statementType="CALLABLE" parameterMap="eventInputMap" fetchSize="1000">
        {call myProc(?, ?, ?, ?, ?)}
    </select>
   </mapper>    

そしてプログラムから呼び出します:

SqlSession session = sqlSessionFactory.openSession();
    Map<String, Object> eventInputMap = new HashMap<String, Object>();
        try {       
            EventDao ed = session.getMapper(EventDao.class);            
            eventInputMap.put("pnNetworkId", networkId);
            eventInputMap.put("pvUserIdentityId", identityId);          
            eventInputMap.put("success", 0);
            eventInputMap.put("message", null);         
            ed.getEvents(eventInputMap);
            session.selectList("EventDao.getEvents", eventInputMap);    
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            session.close();
        }

前もって感謝します!

4

1 に答える 1

1

提供されたコードは機能します。ここでは、parameterMapを使用する方法、 parameterMapを使用しない方法(ステートメントで直接マッピングする方法)、および注釈を使用する方法の 3 つの方法を確認しました。

最近、実際にテストするまで、 fetchSize設定がメイン ステートメントから OUT パラメータ resultSet に伝播されないことに慣れていました。フェッチ サイズが使用されているかどうか、およびその影響がどの程度かを把握するには、結果に十分な数の行が含まれている必要があります。そしてもちろん、アプリから DB へのレイテンシーが最も低く、その効果がより顕著になります。私のテストでは、プロシージャで使用されるカーソルは 120 列の 5400 行を返しました (ただし、最も重要なのは行数です)。大きさを示すために、カーソルからフェッチされたデータで満たされた結果リストを使用して、ストアドプロシージャのリターンからステートメントのリターンまでのフェッチ時間を測定しました。次に、マップされた最初のオブジェクトのインスタンス化をログに記録します。これは、おそらく最初のフェッチの後、グローバル フェッチの開始近くで発生します。

public static boolean firstInstance = true;

public Item() {
    if (firstInstance) {
        LOGGER.debug("Item first instance");
        firstInstance=false;
    }
}

そして、 session.selectListが返された後、最後にもう一度ログに記録します。

これはテストのみを目的としています。それをあなたのコードにしないでください。それを行うためのクリーンな方法を見つけてください。

設定されたフェッチ サイズに応じたタイミングを次に示します。

- fetchSize=1    => 13000 ms
- fetchSize=10   =>  5300 ms
- fetchSize=100  =>  3800 ms
- fetchSize=300  =>  3700 ms
- fetchSize=500  =>  3650 ms
- fetchSize=1000 =>  3600 ms

Oracle JDBC ドライバーのデフォルトの fetchSize は 10 です。

fetchSize=1でテストすると、指定された設定が使用されていることを証明できます。

ここでは 100 で 30% 節約されます。それ以上は、ゲインは無視できます (このユースケースと環境で)

とにかく、いつプロシージャの実行が終了し、いつ結果のフェッチが開始されるかを知ることができれば興味深いでしょう。残念ながら、Mybatis はほとんどログを記録しません。カスタム結果ハンドラーが役立つと思いましたが、クラスorg.apache.ibatis.executor.resultset.DefaultResultSetHandlerのソースコードを見ると、カスタム結果ハンドラーを使用できるメソッドhandleResultSet (単純な選択ステートメントに使用)とは異なり、メソッドhandleRefCursorOutputParameter (ここではプロシージャの OUT カーソルに使用) はありません。カスタム結果ハンドラーを渡す必要はありません。無視されます。誰かが解決策を持っている場合、私は解決策に興味があります。ただし、進化リクエストが必要なようです。

于 2016-11-18T13:55:54.050 に答える