【MyBatis学習07】ダイナミックsql


1.ダイナミックsql
動態sqlはmybatisの中の一つの核心で、何が動態sqlですか?動的sqlはsql文を柔軟に操作し、表現で判断し、sqlを柔軟につなぎ合わせ、組み立てます。前の記事を持って、ユーザーの総合クエリの一例として:
select * from user where user.sex = #{user.sex} and user.username like '%${user.username}%'
もしこのuserがnullだったらどうしますか?またはuser.sexまたはuser.usernameはnullですか?ですから、より厳密なやり方はこの文を実行する前に判断しなければならないです。これはmybatisの動きに触れました。mybatisでは、動的sqlはラベルで表現できます。これはjstl表現に似ています。上のsql文を動的sqlに変えられます。
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User">
    select * from user
    <!-- where             and -->
    <where>
        <if test="user!=null">
            <if test="user.sex!=null and user.sex!=''">
                and user.sex = #{user.sex}
            </if>
            <if test="user.username!=null and user.username!=''">
                and user.username like '%${user.username}%'
            </if>
        </if>
    </where>
</select>
上のコードはよく分かります。主に判断を加えました。条件は空ではないので、検索条件のつなぎ合わせを行います。mybatisダイナミックに実行させます。テストコードでは、意図的にuser.sexを初期値にしないと、クエリの結果が違って見えます。
2.sqlセグメント
今はもう一つの問題があります。もしいくつかのstatementがこのようにしなければならないならば、動きのsql部分も同じで、コードの重複を招きます。だから、このような状況にあったら、私達は抽出すべきです。動きのsqlも抽出できます。この部分はsqlセグメントに抽出して、具体的なstatementに引用すればいいです。以下のとおりです
<sql id="query_user_where">
    <if test="user!=null">
        <if test="user.sex!=null and user.sex!=''">
            and user.sex = #{user.sex}
        </if>
        <if test="user.username!=null and user.username!=''">
            and user.username like '%${user.username}%'
        </if>
    </if>
</sql>
IDはこのsqlに名前を付けるだけです。内部は上のwhereダイナミックな部分です。そして上の元のダイナミックな部分をこのsqlセグメントの引用に変えます。
<select id="findUserList" parameterType="mybatis.po.UserQueryVo" resultType="mybatis.po.User">
    select * from user
    <where>
        <!--   sql   id,  refid   id   mapper   ,       namespace -->
        <include refid="query_user_where"></include>
        <!--        sql   -->
    </where>
</select>
3.foreach
もう一つの問題があります。sqlに配列やListを送るなら、どうすればいいですか?mybatisはforeach解析を使います。このシーンをシミュレートするために、上記のクエリを複数のidクエリに変更しました。二つの問い合わせ方法があります。
SELECT * FROM USER WHERE id=1 OR id=12 OR id=17 SELECT * FROM USER WHERE id IN(1,12,17)
まず一つ明確な点があります。複数のidを使って検索するなら、複数のidは必ずパラメータとして伝えられます。だから、複数のidを記憶するListはUserQueryVoの中に一つの属性として置く必要があります。これはよく分かります。だから、先にUserQueryVoにこの属性を追加します。
//    id
private List<Integer> ids;
その後、UserMapper.xmlのsqlセグメントを修正します。以下のようにします。
<sql id="query_user_where">
    <if test="user!=null">
        <if test="user.sex!=null and user.sex!=''">
            and user.sex = #{user.sex}
        </if>
        <if test="user.username!=null and user.username!=''">
            and user.username like '%${user.username}%'
        </if>
    </if>
    <if test="ids!=null">
        <!--      sql  :AND (id=1 OR id=12 OR id=17) -->
        <foreach collection="ids" item="user_id" open="AND (" close=")" separator="OR">
            id=#{user_id}
        </foreach>
    </if>
</sql>
このforeachに関する属性の役割を簡単に紹介します。
collection:入力対象の集合属性を指定します。ここがこのidsです。item:生成したオブジェクトを遍歴して、自分で名前をつけて、foreach体で使うことを表します。open:継ぎ接ぎのsqlを始めます。close:つなぎ合わせのsql串を全部終わらせます。separator:遍歴する二つの対象の中でつなぎ合わせが必要なsql串です。
私たちはテストして、コンソールから印刷されたsqlを見たら分かりやすいです。テストプログラム:
@Test
public void testFindUserList() throws Exception {

    SqlSession sqlSession = sqlSessionFactory.openSession();
    //  UserMapper  ,mybatis    mapper    
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

    //      ,      
    UserQueryVo userQueryVo = new UserQueryVo();
    User user = new User();
    //        sql,        ,       sql 
    user.setSex(" ");
    user.setUsername("   ");

    //    id
    List<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(12);
    ids.add(17);
    userQueryVo.setIds(ids);

    userQueryVo.setUser(user);  
    //  userMapper   
    List<User> list = userMapper.findUserList(userQueryVo);
    System.out.println(list);
}
コンソールから印刷されたsqlを見てください。
select * from user WHERE user.sex = ? and user.username like '%   %' AND ( id=? OR id=? OR id=? ) 
【詳細に注意してください。mybatisではIntegerまたはintタイプの0を入力すると、上記のif判定タグがfalseに戻ってきます。つまり、非空であっても、ラベル体のsqlには接続されません。もう一つのsqlの実現はもう詳しく説明しません。上記と同じで、唯一の違いはsqlセグメントの部分です。
<!--      sql  :AND id IN(1,12,17) -->
<foreach collection="ids" item="user_id" open="AND id IN(" close=")" separator=",">
    #{user_id}
</foreach>
mybatisのダイナミックsqlはこれだけまとめましょう。
関連記事:http://blog.csdn.net/column/details/smybatis.html 学習ノートのソースコードのダウンロード先:https://github.com/eson15/MyBatis_Study
—分かち合い、共に向上!—もっと多くの文章を読んでください。http://blog.csdn.net/eson_15