猫が綴る雑多なブログ

MyBatisでストアドプロシージャを使う

MyBatisを用いたJavaプロジェクトにて、MySQLのストアドプロシージャ(Stored Procedure)を呼び出そうとして戦った記録

呼び出しと戻り値の受け取り方が分からなかった

MyBatisを用いたJavaプロジェクトにて、MySQLサーバに設定したストアド・プロシージャを呼び出して、戻り値を得たかったのですが、 これ、といった模範例に巡り合えず、1日溶かしたので、備忘録を兼ねて、記事にします。

なるほど、完全に理解した

map_p_my_proc.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="pro.eng.yui.samples.p_my_procedure">
    <update id="run" statementType="CALLABLE"
            parameterType="P_My_Procedure">
        call p_register_payment(
        <!-- inputs -->
        #{workerId}, #{paymentDate}, #{boost},
        <!-- outputs -->
        #{success, mode=OUT, javaType=Boolean, jdbcType=NUMERIC},
        #{paymentId, mode=OUT, javaType=Long, jdbcType=NUMERIC},
        #{errMsg, mode=OUT, javaType=pro.eng.yui.samples.callProcWithMybatis.dto.colType.ErrMsg, jdbcType=VARCHAR}
        );
    </update>
</mapper>
DbIoTest.java
@Test
public void test(){
    P_My_Procedure paramAndResult = new P_My_Procedure();
    paramAndResult.workerId = 1234;
    paramAndResult.paymentDate = new Date();
    paramAndResult.boost = 100;
    session.update(QueryId.run, paramAndResult);

    assertAll(
            () -> {assertTrue(paramAndResult.success);},
            () -> {assertNull(paramAndResult.errMsg);},
            () -> {assertNotNull(paramAndResult.paymentId);}
    );
    System.out.println("paymentId is "+ paramAndResult.paymentId);
}

この2つのソースファイルが、解決した状態の集大成です。

解説

まずは、XMLのmapperファイルから。プロシージャ自体は通常通りの定義をしておきます。 それに合わせて、DTO(Data-Transfar-Object)クラスを定義して、これの1インスタンスを、 パラメータの引き渡しにも、出力の受け取りにも共用します。

mapperでは、通常のパラメータマッピングに加えて、出力を受け取るパラメータに対してmode=OUT, javaType=String, jdbcType=CHARの要素が増えているのがポイントです。 また、SQLに対応するタグは<update>で、見慣れない属性statementType="CALLABLE"を付与します。

javaTypeはjava.langパッケージ系の標準要素なら特段気にせず書けますが、サンプルソースの最後の要素のように、 独自定義のデータクラスを定義することもできます。 この場合、mybatis-config.xmlでtypeHandlerの指定と、Javaでのハンドリング実装が必要になります。 実装例はGitHubで公開しているconfig.xmlと、対応するJavaハンドラクラスの実装を参照してください。

続けて、呼び出すJavaプログラムの方。MyBatis利用時の通常の方法にて、SqlSessionを取得してください。 取得したSqlSessionに対して、.update("mapperNameSpace.queryId", DtoInstance)の様式でクエリ実行を指示します。

この時プロシージャへのIN,すなわち引き渡しパラメータの値を持ったDTOクラスのインスタンスに対して、 プロシージャからのOUT,すなわち戻り値が格納されます。 上記サンプルjavaコードの10~12行目の通り、インスタンスのフィールドで戻り値が取得できます。

参照資料

上記xmlおよびjavaを含む、実行可能なJavaプロジェクトおよびMySQL構築用クエリは、北村由衣のGitHubのリポジトリ『CallProcWithMybatis』を参照ください。

この課題事項の解決に大いに寄与したウェブ情報は、英語版StackOverflowの記事『Java MyBatis stored procedure call with OUT parameters』です。こちらではJavaのDAOクラスでSQL文を実装していますが、記法が大いに参考になりました。

つれづれ

結局Google検索する時、ニッチな情報は英語ソースから得られるなぁ、という所感。 Qiitaといったまとめ記事系や、日本語版StackOverflowといったQ&A形式のサイトもありますが、 日本語で発信するという行為に価値があるのではないか、と感じます。


ブログランキング・にほんブログ村へに参加しています。 PVアクセスランキング にほんブログ村 猫が綴る雑多なブログ - にほんブログ村 にほんブログ村 IT技術ブログへ にほんブログ村 IT技術ブログ IT技術メモへ



コメントはこちらからお寄せください