2Way-SQLとは
2Way-SQLは普通のSQL文をファイルに保存したものです。
特別なSQLコメントを使用してパラメータと条件を指定できます。
また、そのままテンプレートはSQLクライアントツールで実行できますし、本ライブラリで読み込んで PreparedStatement や JdbcTemplate などで実行することもでいます。 (2つの実行方法があることから2WaySQLと呼ばれます)
この機能は、O/Rマッピングフレームワークの S2JDBC に基づいています。
1. バインドパラメータ
SQLにバインドするパラメータを /*パラメータ名*/ のSQLコメントの形式で指定することができます。
- このSQLコメントには空白を含めることができません。
以下にもっとの簡単な例を示します。
SELECT * FROM EMPLOYEE WHERE FULL_NAME = /*fullName*/'Taro Yamada' ORDER BY EMP_ID
上の例では、/*fullName*/ がバインドパラメータで、SQLテンプレートを評価する際には、この部分がプレースホルダー(?)に置き換わります。 さらに、後ろの 'Taro Yamada' が削除されます。
SELECT * FROM EMPLOYEE WHERE FULL_NAME = ? ORDER BY EMP_ID
1.2. IN句の利用方法
Collection型や配列の値をIN句のパラメータとして指定することもできます。
- IN句にバインドパラメータを指定する場合、バインドパラメータの後に
(...)を記述する必要があります。
SELECT * FROM EMPLOYEE
WHERE JOB_TYPE IN /*jobTypeList*/('ADMIN')
ORDER BY EMP_ID
上の例に jobTypeList として {"ADMIN", "STAFF"} 指定すると、以下のようにCollectionや配列のサイズによってプレースホルダ―の個数が動的に変わります。
SELECT * FROM EMPLOYEE WHERE JOB_TYPE IN (?, ?) ORDER BY EMP_ID
1.3. LIKE句の利用方法
LIKE句に対してバインドパラメータを使用する場合は、 ’(シングルクオート)で囲まれている部分を置き換えます。
SELECT * FROM EMPLOYEE WHERE FULL_NAME LIKE /*fullName*/'%Yamada' ORDER BY EMP_ID
ワイルドカードを使いたい場合は、パラメータの値に埋め込んでください。
MapSqlTemplateContext templateContext = new MapSqlTemplateContext();
templateContext.setVariable("fullName", "%Yamada");
SQLテンプレートを評価した場合は、次のようになります。
SELECT * FROM EMPLOYEE WHERE FULL_NAME LIKE ? ORDER BY EMP_ID
1.4. プレースホルダーの利用方法
プレースホルダー(?)を指定した場合は、インデックス付きのバインドパラメータ(例. $1) に自動的に置き換えられます。
- インデックスは1から始まります。
SELECT * FROM EMPLOYEE WHERE BETWEEN AGE ? AND ? ORDER BY EMP_ID
パラメータの指定は、マップによるパラメータを設定する MapSqlTemplateContext を使用してください。
MapSqlTemplateContext templateContext = new MapSqlTemplateContext();
templateContext.setVariable("$1", 20);
templateContext.setVariable("$2", 50);
2. 文字列置換
LIMIT句やORDER BY句など、PreparedStatement にてプレースホルダ―が利用できない部分は、/*$パラメータ名*/ のSQLコメントの形式で指定し、単純な文字列置換を行います。
- 置換する値として、SQLインジェクションの脆弱性の原因となる
;(セミコロン) を含めることはできません。セミコロンが含まれている場合は、例外TwoWaySqlExceptionがスローされます。
SELECT * FROM EMPLOYEE ORDER BY /*$orderByColumn*/ LIMIT /*$limit*/ OFFSET /*$offset*/
SQLテンプレートを評価した結果として、次のように文字列置換されます。
SELECT * FROM EMPLOYEE ORDER BY BIRTHDAY,FULLNAME LIMIT 10 OFFSET 5
注意
文字列置換は、SQLインジェクションなど脆弱性の原因となる可能性があります。 十分に注意を払ったうえで利用してください
3. IF, ELSE, END
/*IF*/ / --ELSE / /*END*/ を使用し、動的にSQLを変更することができます。
IF コメントでは、次のように条件式を EL式の1種である SpEL で記述します。
SELECT * FROM EMPLOYEE /*IF fullName != null*/ WHERE FULL_NAME = /*fullName*/'Taro Yamada' /*END*/ ORDER BY EMP_ID
ELSE コメントは、IFコメントとENDコメントの間に行コメントとして埋め込みます。
理由として、SQLクライアントから直接実行した場合、ELSE文は無効となり正しいSQLとして解釈できるためです。
SELECT * FROM EMPLOYEE /*IF fullName != null*/ WHERE FULL_NAME = /*fullName*/'Taro Yamada' --ELSE FULL_NAME IS NULL /*END*/ ORDER BY EMP_ID
4. BEGIN, END
まず初めに、以下のSQLについて見ていきます。
SELECT * FROM EMPLOYEE
WHERE
/*IF minSalary != null*/
SALARY >= /*minSalary*/1000
/*END*/
/*IF maxSalary != null*/
AND SALARY <= /*maxSalary*/2000
/*END*/
バインドパラメータ minSalary が null、 maxSlary がnullでないとき、次のように不正なSQLとなります。
SELECT * FROM EMPLOYEE WHERE AND SALARY <= ?
また、minSalary と maxSalary の両方の値が null のときも同様に不正なSQLとなります。
SELECT * FROM EMPLOYEE WHERE
このようなときは、/*BEGIN*/, /*END*/ を使用して、次のように囲みます。
SELECT * FROM EMPLOYEE
/*BEGIN*/
WHERE
/*IF minSalary != null*/
SALARY >= /*minSalary*/1000
/*END*/
/*IF maxSalary != null*/
AND SALARY <= /*maxSalary*/2000
/*END*/
/*END*/
このようにすると、salaryMinがnullでsalaryMaxがnullではないときは、salaryMaxの条件は、BEGINコメントとENDコメントで囲まれた最初の条件なので、 AND の部分が自動的に削除されて次のようになります。
SELECT * FROM EMPLOYEE WHERE SALARY <= ?
また、salaryMinとsalaryMaxがnullの場合は、 BEGINコメントとENDコメントで囲まれた部分に有効なIFコメントが一つもないため、 BEGINコメントとENDコメントで囲まれた全体がカットされて次のようになります。
SELECT * FROM EMPLOYEE

