Mybatisの動的SQL文


場合によっては、sql文where条件では、ある条件でクエリを実行するときに入力されたパラメータが空である場合、クエリの結果が空になる可能性があります.パラメータが空である場合、すべての情報を検出する必要があるかもしれません.Oracleのシーケンス、mysqlの関数を使用してIdを生成します.この場合、ダイナミックsqlを使用できます.以下ではmysql構文と関数(文字列リンク関数CONCATなど)を使用します.
3.1 selectKeyラベル
Insert文では、Oracleでシーケンスを頻繁に使用し、MySQLで関数を使用して挿入テーブルのプライマリ・キーを自動的に生成し、この生成プライマリ・キーを返す方法が必要です.この効果はmyBatisのselectKeyラベルを使用して実現できます.
次の例では、mysqlデータベースのカスタム関数nextval('student')を使用してkeyを生成し、入力したエンティティクラスのstudentIdプロパティに設定します.したがって、このメソッドを実行した後、エッジは生成されたkeyをこのエンティティクラスで取得できます.
    <!--          -->  
    <insert id="createStudentAutoKey" parameterType="liming.student.manager.data.model.StudentEntity" keyProperty="studentId">  
        <selectKey keyProperty="studentId" resultType="String" order="BEFORE">  
            select nextval('student')  
        </selectKey>  
        INSERT INTO STUDENT_TBL(STUDENT_ID,  
                                STUDENT_NAME,  
                                STUDENT_SEX,  
                                STUDENT_BIRTHDAY,  
                                STUDENT_PHOTO,  
                                CLASS_ID,  
                                PLACE_ID)  
        VALUES (#{studentId},  
                #{studentName},  
                #{studentSex},  
                #{studentBirthday},  
                #{studentPhoto, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},  
                #{classId},  
                #{placeId})  
    </insert>  

インタフェースメソッドの呼び出しと自動生成keyの取得
StudentEntity entity = new StudentEntity();  
entity.setStudentName("    ");  
entity.setStudentSex(1);  
entity.setStudentBirthday(DateUtil.parse("1985-05-28"));  
entity.setClassId("20000001");  
entity.setPlaceId("70000001");  
this.dynamicSqlMapper.createStudentAutoKey(entity);  
System.out.println("    ID: " + entity.getStudentId());

selectKey文のプロパティ構成の詳細:
ツールバーの
説明
値をとる
keyProperty
selectKey文は、結果を生成するために設定するプロパティを生成します.
resultType
結果タイプを生成します.MyBatisでは、String、intタイプなどの基本的なデータ型を使用できます.
order
1:BEFOREは、プライマリ・キーを選択してkeyPropertyを設定し、insert文を実行します.2:AFTER、insert文を実行してからselectKey文を実行します.
BEFORE AFTER
statementType
MyBatisはSTATEMENT、PREPARED、CALLABLEの文形式をサポートし、Statement、PreparedStatement、CallableStatement応答に対応する
STATEMENT PREPARED CALLABLE
3.2 ifタグ
ifラベルは、多くのタイプのsql文で使用できます.クエリーを例に挙げます.まず、普通のクエリーを見てみましょう.
    <!--     list,like   -->  
    <select id="getStudentListLikeName" parameterType="StudentEntity" resultMap="studentResultMap">  
        SELECT * from STUDENT_TBL ST   
    WHERE ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName}),'%')  
    </select>  

ただし、studentNameまたはstudentSexがnullの場合、この文はエラーを報告したり、クエリの結果が空になったりする可能性があります.このときifダイナミックsql文を用いて先に判断し,nullまたは空の文字列に等しい値であれば,この条件の判断を行わず柔軟性を高める.
パラメータはエンティティークラスStudentEntityです.エンティティクラスのすべての属性を判断し、空でない場合は判断条件を実行します.
    <!-- 2 if(    ) -             where   -->  
    <select id="getStudentList_if" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">  
        SELECT ST.STUDENT_ID,  
               ST.STUDENT_NAME,  
               ST.STUDENT_SEX,  
               ST.STUDENT_BIRTHDAY,  
               ST.STUDENT_PHOTO,  
               ST.CLASS_ID,  
               ST.PLACE_ID  
          FROM STUDENT_TBL ST   
         WHERE  
        <if test="studentName !=null ">  
            ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')  
        </if>  
        <if test="studentSex != null and studentSex != '' ">  
            AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}  
        </if>  
        <if test="studentBirthday != null ">  
            AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}  
        </if>  
        <if test="classId != null and classId!= '' ">  
            AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}  
        </if>  
        <if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">  
            AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}  
        </if>  
        <if test="placeId != null and placeId != '' ">  
            AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}  
        </if>  
        <if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">  
            AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}  
        </if>  
        <if test="studentId != null and studentId != '' ">  
            AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}  
        </if>   
    </select>  

使用するときは柔軟ですが、newのようなエンティティクラスでは、その条件を制限する必要があります.対応する値を付けるだけでwhereという条件になります.逆に、値を付けなくてもwhereで判断できます.
    public void select_test_2_1() {  
        StudentEntity entity = new StudentEntity();  
        entity.setStudentName("");  
        entity.setStudentSex(1);  
        entity.setStudentBirthday(DateUtil.parse("1985-05-28"));  
        entity.setClassId("20000001");  
        //entity.setPlaceId("70000001");  
        List<StudentEntity> list = this.dynamicSqlMapper.getStudentList_if(entity);  
        for (StudentEntity e : list) {  
            System.out.println(e.toString());  
        }  
    }  

3.3 if+whereの条件判断
whereの条件で使用されるifラベルが多い場合、このような組み合わせはエラーを引き起こす可能性があります.3.1のクエリー文を例に挙げます.javaコードが次のように呼び出されると、
    @Test  
    public void select_test_2_1() {  
        StudentEntity entity = new StudentEntity();  
        entity.setStudentName(null);  
        entity.setStudentSex(1);  
        List<StudentEntity> list = this.dynamicSqlMapper.getStudentList_if(entity);  
        for (StudentEntity e : list) {  
            System.out.println(e.toString());  
        }  
    }  

上記の例では、パラメータstudentNameがnullの場合、STUDENT_は行われません.NAME列の判断は、「WHERE AND」キーワードの余計なエラーSQLを直接導きます.
この場合、where動的文を使用して解決できます.この「where」タブには、含まれるラベルに戻り値がある場合、「where」が挿入されることがわかります.また、ラベルがANDまたはORで始まる場合は削除されます.
次のように変更します.
    <!-- 3 select - where/if(    ) -             where   -->  
    <select id="getStudentList_whereIf" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">  
        SELECT ST.STUDENT_ID,  
               ST.STUDENT_NAME,  
               ST.STUDENT_SEX,  
               ST.STUDENT_BIRTHDAY,  
               ST.STUDENT_PHOTO,  
               ST.CLASS_ID,  
               ST.PLACE_ID  
          FROM STUDENT_TBL ST   
        <where>  
            <if test="studentName !=null ">  
                ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')  
            </if>  
            <if test="studentSex != null and studentSex != '' ">  
                AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}  
            </if>  
            <if test="studentBirthday != null ">  
                AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}  
            </if>  
            <if test="classId != null and classId!= '' ">  
                AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}  
            </if>  
            <if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">  
                AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}  
            </if>  
            <if test="placeId != null and placeId != '' ">  
                AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}  
            </if>  
            <if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">  
                AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}  
            </if>  
            <if test="studentId != null and studentId != '' ">  
                AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}  
            </if>  
        </where>    
    </select>  

3.4 if+setの更新文
update文でifラベルが使用されていない場合、nullのパラメータがある場合、エラーが発生します.
update文でifラベルを使用する場合、前のifが実行されていない場合、カンマに余分なエラーが発生する可能性があります.setラベルを使用して、SETキーワードを動的に構成し、条件の末尾に追加された関連のないカンマを削除します.
if+setラベルを使用して変更すると、nullの場合は更新せず、データベースの元の値を維持します.次の例を示します.
    <!-- 4 if/set(    ) -              -->  
    <update id="updateStudent_if_set" parameterType="liming.student.manager.data.model.StudentEntity">  
        UPDATE STUDENT_TBL  
        <set>  
            <if test="studentName != null and studentName != '' ">  
                STUDENT_TBL.STUDENT_NAME = #{studentName},  
            </if>  
            <if test="studentSex != null and studentSex != '' ">  
                STUDENT_TBL.STUDENT_SEX = #{studentSex},  
            </if>  
            <if test="studentBirthday != null ">  
                STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},  
            </if>  
            <if test="studentPhoto != null ">  
                STUDENT_TBL.STUDENT_PHOTO = #{studentPhoto, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},  
            </if>  
            <if test="classId != '' ">  
                STUDENT_TBL.CLASS_ID = #{classId}  
            </if>  
            <if test="placeId != '' ">  
                STUDENT_TBL.PLACE_ID = #{placeId}  
            </if>  
        </set>  
        WHERE STUDENT_TBL.STUDENT_ID = #{studentId};      
    </update>  

3.5 if+trimはwhere/setラベルtrimの代わりにより柔軟な余分なキーワードのラベルであり、whereとsetの効果を実践することができる.
3.5.1 trim代替where
<!-- 5.1 if/trim  where(    ) -             where   -->  
<select id="getStudentList_if_trim" resultMap="resultMap_studentEntity">  
    SELECT ST.STUDENT_ID,  
           ST.STUDENT_NAME,  
           ST.STUDENT_SEX,  
           ST.STUDENT_BIRTHDAY,  
           ST.STUDENT_PHOTO,  
           ST.CLASS_ID,  
           ST.PLACE_ID  
      FROM STUDENT_TBL ST   
    <trim prefix="WHERE" prefixOverrides="AND|OR">  
        <if test="studentName !=null ">  
            ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')  
        </if>  
        <if test="studentSex != null and studentSex != '' ">  
            AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}  
        </if>  
        <if test="studentBirthday != null ">  
            AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}  
        </if>  
        <if test="classId != null and classId!= '' ">  
            AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}  
        </if>  
        <if test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">  
            AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}  
        </if>  
        <if test="placeId != null and placeId != '' ">  
            AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}  
        </if>  
        <if test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">  
            AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}  
        </if>  
        <if test="studentId != null and studentId != '' ">  
            AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}  
        </if>  
    </trim>     
</select>

3.5.2 trim代替set
    <!-- 5.2 if/trim  set(    ) -              -->  
    <update id="updateStudent_if_trim" parameterType="liming.student.manager.data.model.StudentEntity">  
        UPDATE STUDENT_TBL  
        <trim prefix="SET" suffixOverrides=",">  
            <if test="studentName != null and studentName != '' ">  
                STUDENT_TBL.STUDENT_NAME = #{studentName},  
            </if>  
            <if test="studentSex != null and studentSex != '' ">  
                STUDENT_TBL.STUDENT_SEX = #{studentSex},  
            </if>  
            <if test="studentBirthday != null ">  
                STUDENT_TBL.STUDENT_BIRTHDAY = #{studentBirthday},  
            </if>  
            <if test="studentPhoto != null ">  
                STUDENT_TBL.STUDENT_PHOTO = #{studentPhoto, javaType=byte[], jdbcType=BLOB, typeHandler=org.apache.ibatis.type.BlobTypeHandler},  
            </if>  
            <if test="classId != '' ">  
                STUDENT_TBL.CLASS_ID = #{classId},  
            </if>  
            <if test="placeId != '' ">  
                STUDENT_TBL.PLACE_ID = #{placeId}  
            </if>  
        </trim>  
        WHERE STUDENT_TBL.STUDENT_ID = #{studentId}  
    </update>  

3.6 choose (when, otherwise)
 
すべての条件を適用するのではなく、複数のオプションから1つを選択したい場合があります.ifラベルを使用する場合、testの式がtrueである限りifラベルの条件が実行されます.MyBatisはchoose要素を提供しています.ifラベルは(and)との関係であり、chooseは天よりも(or)の関係である.
chooseタグは、その内部whenタグのtest条件が成立するか否かを順番に判断し、成立があればchooseは終了する.chooseのすべてのwhenの条件が満たされない場合、otherwiseのsqlが実行されます.Javaのswitch文と同様にchooseはswitch、whenはcase、otherwiseはdefaultです.
例えば以下の例では,同様にすべての制限可能な条件を記入し,使用する.chooseは、whenラベルのtestをtrueとするsqlを上から下に選択して実行します.セキュリティ上の考慮では、whereを使用してchooseをパッケージし、エラーよりもキーワードを配置します.
    <!-- 6 choose(    ) -                   where   -->  
    <select id="getStudentList_choose" resultMap="resultMap_studentEntity" parameterType="liming.student.manager.data.model.StudentEntity">  
        SELECT ST.STUDENT_ID,  
               ST.STUDENT_NAME,  
               ST.STUDENT_SEX,  
               ST.STUDENT_BIRTHDAY,  
               ST.STUDENT_PHOTO,  
               ST.CLASS_ID,  
               ST.PLACE_ID  
          FROM STUDENT_TBL ST   
        <where>  
            <choose>  
                <when test="studentName !=null ">  
                    ST.STUDENT_NAME LIKE CONCAT(CONCAT('%', #{studentName, jdbcType=VARCHAR}),'%')  
                </when >  
                <when test="studentSex != null and studentSex != '' ">  
                    AND ST.STUDENT_SEX = #{studentSex, jdbcType=INTEGER}  
                </when >  
                <when test="studentBirthday != null ">  
                    AND ST.STUDENT_BIRTHDAY = #{studentBirthday, jdbcType=DATE}  
                </when >  
                <when test="classId != null and classId!= '' ">  
                    AND ST.CLASS_ID = #{classId, jdbcType=VARCHAR}  
                </when >  
                <when test="classEntity != null and classEntity.classId !=null and classEntity.classId !=' ' ">  
                    AND ST.CLASS_ID = #{classEntity.classId, jdbcType=VARCHAR}  
                </when >  
                <when test="placeId != null and placeId != '' ">  
                    AND ST.PLACE_ID = #{placeId, jdbcType=VARCHAR}  
                </when >  
                <when test="placeEntity != null and placeEntity.placeId != null and placeEntity.placeId != '' ">  
                    AND ST.PLACE_ID = #{placeEntity.placeId, jdbcType=VARCHAR}  
                </when >  
                <when test="studentId != null and studentId != '' ">  
                    AND ST.STUDENT_ID = #{studentId, jdbcType=VARCHAR}  
                </when >  
                <otherwise>  
                </otherwise>  
            </choose>  
        </where>    
    </select>  

3.7 foreach
動的SQLでは、主に1つのセットを反復する必要があります.通常はIN条件で使用されます.Listインスタンスは「list」をキーとし,配列インスタンスは「array」をキーとする.
foreach要素は非常に強力で、要素内で使用できる集合を指定し、集合項目とインデックス変数を宣言することができます.また、開いた文字列と閉じた文字列を指定し、反復間に区切り記号を配置することもできます.この要素はインテリジェントで、偶然に余分な区切り文字を付加しません.
注意:リストインスタンスまたは配列をパラメータオブジェクトとしてMyBatisに渡すことができます.そうすると、MyBatisは自動的にMapにパッケージされ、キーとして名前が付けられます.Listインスタンスは「list」をキーとし、配列インスタンスは「array」をキーとする.
このセクションでは、XMLプロファイルとXMLマッピングファイルについて説明します.次のセクションでは、Java APIについて詳しく説明するので、作成した最も効果的なマッピングを得ることができます.
3.7.1パラメータがarrayの例の書き方
インタフェースのメソッド宣言:
    public List<StudentEntity> getStudentListByClassIds_foreach_array(String[] classIds);  

動的SQL文:
    <!— 7.1 foreach(  array  ) -   where in    -->  
    <select id="getStudentListByClassIds_foreach_array" resultMap="resultMap_studentEntity">  
        SELECT ST.STUDENT_ID,  
               ST.STUDENT_NAME,  
               ST.STUDENT_SEX,  
               ST.STUDENT_BIRTHDAY,  
               ST.STUDENT_PHOTO,  
               ST.CLASS_ID,  
               ST.PLACE_ID  
          FROM STUDENT_TBL ST  
          WHERE ST.CLASS_ID IN   
         <foreach collection="array" item="classIds"  open="(" separator="," close=")">  
            #{classIds}  
         </foreach>  
    </select>  

コードをテストし、学生のうち20000001、20000002の2つのクラスの学生を検索します.
@Test  
public void test7_foreach() {  
    String[] classIds = { "20000001", "20000002" };  
    List<StudentEntity> list = this.dynamicSqlMapper.getStudentListByClassIds_foreach_array(classIds);  
    for (StudentEntity e : list) {  
        System.out.println(e.toString());  
    }  
<p>}<span style="font-size:14px;font-weight: bold; white-space: normal;">  </span></p> 

3.7.2パラメータがlist例の書き方
インタフェースのメソッド宣言:
    public List<StudentEntity> getStudentListByClassIds_foreach_list(List<String> classIdList);  

動的SQL文:
    <!-- 7.2 foreach(  List<String>  ) -   where in    -->  
    <select id="getStudentListByClassIds_foreach_list" resultMap="resultMap_studentEntity">  
        SELECT ST.STUDENT_ID,  
               ST.STUDENT_NAME,  
               ST.STUDENT_SEX,  
               ST.STUDENT_BIRTHDAY,  
               ST.STUDENT_PHOTO,  
               ST.CLASS_ID,  
               ST.PLACE_ID  
          FROM STUDENT_TBL ST  
          WHERE ST.CLASS_ID IN   
         <foreach collection="list" item="classIdList"  open="(" separator="," close=")">  
            #{classIdList}  
         </foreach>  
    </select>  

コードをテストし、学生のうち20000001、20000002の2つのクラスの学生を検索します.
    @Test  
    public void test7_2_foreach() {  
        ArrayList<String> classIdList = new ArrayList<String>();  
        classIdList.add("20000001");  
        classIdList.add("20000002");  
        List<StudentEntity> list = this.dynamicSqlMapper.getStudentListByClassIds_foreach_list(classIdList);  
        for (StudentEntity e : list) {  
            System.out.println(e.toString());  
        }  
    }