プロシージャコール
プロシージャコールとは?
DBFluteでは、ストアドプロシージャ、および、ストアドファンクションなどのDBに組み込まれた処理のことをひっくるめて プロシージャ と呼びます。そして、アプリなどからのプロシージャ呼び出しをプロシージャコールと呼びます。 また、DBFluteのプロシージャコール機能を ProcedureCall と表現します。
プロシージャコールの悩み
プロシージャ内部の実装については、DBFluteでは何も関与しません(できません)。 ここでは、アプリからのプロシージャコールの際の実装上の悩みに着目します。以下のような悩みが考えられます。
- プロシージャの名前
- 呼び出すプロシージャの名前の指定でスペルミスでの呼び出しミス
- パラメータ
- プロシージャのパラメータ(引数)の名前の指定でスペルミスでの設定ミス
- 結果セット(ResultSet)
- プロシージャの結果セットの受け取り用 Entity を作成(スペルミスでのマッピングミス)
- プロシージャ変更
- 結果、全てタイプセーフではないため、プロシージャの変更(DB変更とも言える)に弱い
およそ、DBFluteを使わずにSQLをJDBCダイレクトに発行させたときに発生する悩みとほぼ同じです。 結局、何も対策していなければ、"呼び出し" というレイヤにおける悩みに変わりはありません。特に "プロシージャ変更" に関しては、アプリのプログラムとプロシージャのプログラムは遠い関係にありがちで(作成者も違えば、管理組織も違うかも)、 同期漏れのデバッグコストが発生する可能性を秘めています。
タイプセーフなプロシージャコール
対応クラスの自動生成
DBFluteでは、プロシージャコールはタイプセーフ、そして、プロシージャ変更にも強い をポリシーとしています。具体的には、以下の通りです。
- プロシージャのメタデータからプロシージャ対応のクラス(ParameterBean)を自動生成
- プロシージャ実行のメタデータから結果セット対応のクラス(CustomizeEntity)を自動生成
やっていることは、実は通常の外だしSQL(OutsideSql)と同じことです。どちらかというと、プロシージャも "外に出しているSQL" というニュアンスで、広い意味で外だしSQLと捉えることができます。実際に DBFlute のプロシージャコールの実装方法は、ほぼ外だしSQLと同じやり方で呼び出します。
プロシージャ変更に強い
これにより、プロシージャコールの悩みは吹き飛びます。
- プロシージャの名前
- プロシージャの名前に対応した ParameterBean を利用することで呼び出しミスは発生しない
- パラメータ
- パラメータ(の名前)に対応したプロパティを利用することで設定ミスは発生しない
- 結果セット
- 結果セット(select句)に対応した Entity を利用することでマッピングミスは発生しない
- プロシージャ変更
- プロシージャの名前変更、パラメータ変更(パラメータの増減、パラメータ名や型の変更)、結果セットの変更(select句の構成変更)は、 プログラムのコンパイルエラーとなって検知でき、同期漏れは発生しない。
利用方法の概要
プロシージャ対応の ParameterBean や CustomizeEntity は、外だしSQLのと同じく Sql2Entity タスクにて自動生成できます。プロシージャ対応の ParameterBean を ProcedurePmb と呼びます。 ProcedurePmb の仕様がそのまま、DBFluteにおけるプロシージャへのアプローチ(サポート状況も含めて)を表現していると言えます。
クラスができ上がったら、あとはそのクラスを使ってアプリから呼び出すだけです。
IN, OUTパラメータ
対応するプロパティ経由で、INパラメータは call() 前に設定し、OUTパラメータは call() 後に取得します。 また、INOUTパラメータは、INパラメータとOUTパラメータの両方の特性を持ちます。
e.g. IN, OUT, INOUT パラメータ (SP_IN_OUT_PARAMETER) {MySQL} @Procedure
create procedure SP_IN_OUT_PARAMETER(
in v_in_varchar varchar(32)
, out v_out_varchar varchar(32)
, inout v_inout_varchar varchar(32)
)
begin
set v_out_varchar = 'qux';
set v_inout_varchar = 'quux';
end;
e.g. IN, OUT, INOUT パラメータの利用 (SP_IN_OUT_PARAMETER) @Java
SpInOutParameterPmb pmb = new SpInOutParameterPmb();
pmb.setVInVarchar("foo"); // INパラメータの設定
//pmb.setVOutVarchar("bar"); // OUTパラメータなので設定なし
pmb.setVInOutVarchar("baz"); // INOUTパラメータの設定
xxxBhv.outsideSql().call(pmb);
String outParam = pmb.getVOutVarchar(); // OUTパラメータの受け取り (qux)
String inOutParam = pmb.getVInOutVarchar(); // INOUTパラメータの受け取り (quux)
プロシージャリターン
プロシージャリターン値(戻り値)も受け取れます。OUTパラメータと同じ扱いとなります。
e.g. プロシージャリターンのあるプロシージャ (SP_RETURN_PARAMETER) {PostgreSQL} @Procedure
create or replace function SP_RETURN_PARAMETER()
returns integer as
$BODY$
begin
return 1;
end;
$BODY$ LANGUAGE 'plpgsql';
e.g. プロシージャリターンの利用 (SP_RETURN_PARAMETER) @Java
SpReturnParameterPmb pmb = new SpReturnParameterPmb();
xxxBhv.outsideSql().call(pmb); // 実行
Integer returnValue = pmb.getReturnValue(); // プロシージャリターンの受け取り (1)
結果セット (ResultSet)
結果セット(ResultSet)は、コール後に対応するプロパティから Entity (のリスト)を取得します。
e.g. OUTパラメータの結果セットの受け取り {PostgreSQL} @Java
create or replace function SP_FOO_PROC(cur_member out refcursor)
as
$BODY$
begin
open cur_member for
select MEMBER_ID, MEMBER_NAME, BIRTHDATE
from MEMBER;
end;
$BODY$ LANGUAGE 'plpgsql';
e.g. OUTパラメータの結果セットの受け取り {PostgreSQL} @Java
SpFooProcPmb pmb = new SpFooProcPmb();
memberBhv.outsideSql().call(pmb);
List<SpFooProcCurMember> memberList = pmb.getCurMember();
for (SpFooProcCurMember member : memberList) {
... = member.getMemberId();
... = member.getMemberName();
... = member.getBirthdate();
}
プロシージャ呼び出しフレームワーク
DB変更に強いをポリシーとする DBFlute は、そのDB変更という言葉にプロシージャ実装の変更も含みます。基本的には ConditionBean や外だしSQLなどを使ってDBアクセスをすることが前提のポリシー ですが、いざというときのパフォーマンスを発揮するプロシージャ、そして、 組織文化によってプロシージャでのDBアクセスをメインすることもあるため、様々な場面でプロシージャが活躍することがあります。
DBMSごとの方言も(かなり)激しく、Java や C# などとは全く違った世界が展開されているため全ての機能をサポートするのは難しいですが、プロシージャを目の前にした途端に DBFlute の良さが完全には消えてしまう、ということがないように プロシージャ呼び出しフレームワーク としても有用であるようにと作られています。
プロシージャ一覧の生成
プロシージャの一覧を SchemaHTML で参照することができます。どんなプロシージャがあるのか、ディベロッパーがすぐに把握できます。 アーキテクトもプロシージャを管理する上で役に立つでしょう。
DBMSごとのプロシージャの取扱い
プロシージャは DBMS ごとの方言がとても激しいものです。複雑な構造のものはサポートされない場合もあります。 DBMSごとの取扱いを参考に、利用する DBMS でのプロシージャの取扱いの特徴をよく押さえて利用すると良いでしょう。
フィードバックの重要性
プロシージャの世界は広く、(DBFluteとして)未到達の部分も多いです。いざ呼び出せないプロシージャなどに直面したときには フィードバック を頂ければ、実現可能性次第で対応される可能性もあるでしょう。 特にプロシージャに関しては、トップダウンで全ての機能・事象を把握することが困難なため、 要望ベースのボトムアップで対応していくというスタンスをとっています。