いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

iBatis奮闘記-0013 ($を使用した動的パラメータ)

ibatisには、SQLマッピング設定ファイルにて、以下の2つの値指定ができます。

  • #を使用した値指定
  • $を使用した値指定

上記の2つの違いは、#は実行時にエスケープや文字列の場合は' 'で囲んでくれるなどの処理をおこなってくれますが
$の方は、指定された値をそのまま出力します。

たとえば、java.lang.String型の値value1があったとして、

hoge_column = #value1#

と指定した場合、実行時には、

hoge_column = 'value1の値'

のように、展開してくれますが、

hoge_column = $value1$

と指定した場合は、

hoge_column = value1の値

とそのまま展開されます。

$指定は、主にテーブルを動的に与えたり、order byを動的に変えたりするのに
使用したります。取得カラム名を動的に変更したりする場合にも使えたりします。

今回は、order by を動的に変更するサンプルを作成してみます。

[ddl]

 --vim:set ts=4 sw=4 et ws is nowrap ft=sql:

 --
 -- SAMPLE010_TEST_TABLEのDDL
 --
create table sample010_test_table(
     id int auto_increment
    ,value1 varchar(100)
    ,value2 varchar(100)
    ,value3 varchar(100)
    ,primary key(id)
);

 --
 -- サンプルデータ
 --
insert into SAMPLE010_TEST_TABLE (value1, value2, value3) values ('value1-001', 'value2-011', 'value3-348');
insert into SAMPLE010_TEST_TABLE (value1, value2, value3) values ('value1-002', 'value2-032', 'value3-489');
insert into SAMPLE010_TEST_TABLE (value1, value2, value3) values ('value1-003', 'value2-034', 'value3-098');
insert into SAMPLE010_TEST_TABLE (value1, value2, value3) values ('value1-004', 'value2-048', 'value3-934');
insert into SAMPLE010_TEST_TABLE (value1, value2, value3) values ('value1-005', 'value2-002', 'value3-485');

[データクラス]

// vim:set ts=4 sw=4 et ws is nowrap ft=java:
package gsf.samples.ibatis.sample010;

import java.io.*;

import org.apache.commons.lang.builder.*;

public class Sample010TestTable implements Serializable{

    /** ID */
    private Integer id;

    /** VALUE1 */
    private String  value1;

    /** VALUE2 */
    private String  value2;

    /** VALUE3 */
    private String  value3;

    /**
     * コンストラクタ.<br/>
     *
     */
    public Sample010TestTable(){
        // nop;
    }
    
    /**
     * Get id.
     *
     * @return id as Integer.
     */
    public Integer getId(){
        return this.id;
    }
    
    /**
     * Set id.
     *
     * @param id the value to set.
     */
    protected void setId(Integer id){
        this.id = id;
    }
    
    /**
     * Get value1.
     *
     * @return value1 as String.
     */
    public String getValue1(){
        return this.value1;
    }
    
    /**
     * Set value1.
     *
     * @param value1 the value to set.
     */
    public void setValue1(String value1){
        this.value1 = value1;
    }
    
    /**
     * Get value2.
     *
     * @return value2 as String.
     */
    public String getValue2(){
        return this.value2;
    }
    
    /**
     * Set value2.
     *
     * @param value2 the value to set.
     */
    public void setValue2(String value2){
        this.value2 = value2;
    }
    
    /**
     * Get value3.
     *
     * @return value3 as String.
     */
    public String getValue3(){
        return this.value3;
    }
    
    /**
     * Set value3.
     *
     * @param value3 the value to set.
     */
    public void setValue3(String value3){
        this.value3 = value3;
    }

    @Override
    public String toString(){
        return new ReflectionToStringBuilder(this).toString();
    }
}

[SQLマッピングファイル]

<?xml version="1.0" encoding="Windows-31J"?>
<!-- vim:set ts=4 sw=4 et ws is nowrap ft=xml: -->
<!DOCTYPE sqlMap 
          PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" 
          "http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Dollar">

    <typeAlias alias="Sample010TestTable" type="gsf.samples.ibatis.sample010.Sample010TestTable"/>

    <select id="findSample010TestTableOrderBy" parameterClass="java.lang.String" resultClass="Sample010TestTable">
        select
             id
            ,value1
            ,value2
            ,value3
        from
            SAMPLE010_TEST_TABLE
        order by
            $value$
    </select>

</sqlMap>

[動作確認クラス]

// vim:set ts=4 sw=4 et ws is nowrap ft=java:
package gsf.samples.ibatis.sample010;

import java.util.*;
import java.sql.*;

import gsf.interfaces.sqlmap.*;
import gsf.utils.sqlmap.*;

import com.ibatis.sqlmap.client.*;

public class IBatisSample010{

    private static class DollarSampleExecutor implements SqlMapClientExecutor{

        private String orderByTarget;

        public DollarSampleExecutor(String orderByTarget){
            this.orderByTarget = orderByTarget;
        }

        public Object execute(SqlMapClient sqlMap) throws SQLException{
            return sqlMap.queryForList("findSample010TestTableOrderBy", this.orderByTarget);
        }
    }

    public static void main(String[] args){

        List&lt;Sample010TestTable> result1 
            = (List&lt;Sample010TestTable>) SqlMapUtils.executeNoTransaction(new DollarSampleExecutor("value1"));
        List&lt;Sample010TestTable> result2 
            = (List&lt;Sample010TestTable>) SqlMapUtils.executeNoTransaction(new DollarSampleExecutor("value2"));
        List&lt;Sample010TestTable> result3 
            = (List&lt;Sample010TestTable>) SqlMapUtils.executeNoTransaction(new DollarSampleExecutor("value3"));

        System.out.println("======== value1でorder by ========");
        printResult(result1);
        System.out.println("\n======== value2でorder by ========");
        printResult(result2);
        System.out.println("\n======== value3でorder by ========");
        printResult(result3);
    }
    
    private static void printResult(List&lt;Sample010TestTable> result){

        for(Sample010TestTable aRow : result){
            System.out.println(aRow);
        }

    }

}

実行すると、指定した値でOrder Byが行われている事が確認できます。
このサンプルの場合、$指定ではなく、#指定をすると展開された場合に、

order by 'value1'

とかなってしまい、うまくいきません。

データのパラメータではなく、実行するSQLの一部を動的に変更したい場合は、
$指定をします。

ちなみに、iBatisのドキュメントやwikiにも記述がありますが、
$指定の場合は、そのままデータが展開されますので、SQLインジェクションなどの
アタックを許さないように、処理元でしっかりとコントロールする必要があります。

ちなみに、サンプルの動作結果は、以下のとおりです。

exec:
     [java] ======== value1でorder by ========
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@1006d75[id=1,value1=value1-001,value2=value2-011,value3=value3-348]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@18dfef8[id=2,value1=value1-002,value2=value2-032,value3=value3-489]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@15e83f9[id=3,value1=value1-003,value2=value2-034,value3=value3-098]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@bb7465[id=4,value1=value1-004,value2=value2-048,value3=value3-934]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@d6c16c[id=5,value1=value1-005,value2=value2-002,value3=value3-485]

     [java] ======== value2でorder by ========
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@134bed0[id=5,value1=value1-005,value2=value2-002,value3=value3-485]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@1db4f6f[id=1,value1=value1-001,value2=value2-011,value3=value3-348]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@13c1b02[id=2,value1=value1-002,value2=value2-032,value3=value3-489]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@11121f6[id=3,value1=value1-003,value2=value2-034,value3=value3-098]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@1ccce3c[id=4,value1=value1-004,value2=value2-048,value3=value3-934]

     [java] ======== value3でorder by ========
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@f7f540[id=3,value1=value1-003,value2=value2-034,value3=value3-098]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@10655dd[id=1,value1=value1-001,value2=value2-011,value3=value3-348]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@ef5502[id=5,value1=value1-005,value2=value2-002,value3=value3-485]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@b61fd1[id=2,value1=value1-002,value2=value2-032,value3=value3-489]
     [java] gsf.samples.ibatis.sample010.Sample010TestTable@e2dae9[id=4,value1=value1-004,value2=value2-048,value3=value3-934]