動態(tài)SQL

在mybatis3之前,需要學(xué)習(xí)和了解非常多標(biāo)簽,現(xiàn)在采用OGNL表達(dá)式語言,消除了許多其他標(biāo)簽
剩下
if
choose
trim
foreach
bind

if用法:

if通常用于WHERE語句中,判斷參數(shù)是否使用某個(gè)查詢條件,UPDATE語句中判斷是否更新某個(gè)字段,INSERT語句中判斷是否插入某個(gè)字段。

在WHERE語句中使用if

需求:
實(shí)現(xiàn)一個(gè)用戶管理高級查詢功能,根據(jù)輸入的條件去檢索用戶信息。當(dāng)只輸入用戶時(shí),需要根據(jù)用戶名進(jìn)行模糊查詢,當(dāng)只輸入郵箱時(shí),根據(jù)郵箱進(jìn)行完全匹配;當(dāng)同時(shí)輸入用戶名和郵箱時(shí),用這兩個(gè)條件去匹配用戶。

<select id="selectByUser" resultType="pers.congcong.myBatis2.pojos.SysUser">
    SELECT id,
        user_name userName,
        user_password userPassward,
        user_email userEmail,
        user_info userInfo,
        head_img headImg,
        create_time createTime
    FROM sys_user
    WHERE 1=1
    <if test="userName != null and userEmail != ''">
        AND user_name LIKE concat('%', #{userName}, '%')
    </if>
    <if test="userEmail != null and userEmail != ''">
        AND user_email = #{userEmail}
    </if>
</select>

if標(biāo)簽有一個(gè)必填的屬性 test, test的屬性是一個(gè)符合OGNL要求的判斷表達(dá)式,表達(dá)式的結(jié)果為TRUE或FALSE,除此之外非0都為true,0為false。

@Test
    public void testSelectByUser() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser sysUser = new SysUser();
            sysUser.setUserName("ad");
            List<SysUser> sysUserList = userMapper.selectByUser(sysUser);

            Assert.assertTrue(sysUserList.size()>0);

//            根據(jù)郵箱查
            sysUser.setUserEmail("test@mybatis.tk");
            sysUser.setUserName(null);
            sysUserList = userMapper.selectByUser(sysUser);


//            根據(jù)用戶和郵箱查
            sysUser.setUserName("ad");
            Assert.assertTrue(sysUserList.size()==0);

        } finally {
            sqlSession.close();
        }
    }

if 用法,加一個(gè)<if test ="property != ' ' and property == null">標(biāo)簽
中間加 and 條件。
if中符合條件才會有and條件。

在update中使用if

需求:
只更新變化的字段。需要注意,更新的時(shí)候不能將原來有值但沒發(fā)生變化的字段更新為空或者NULL。
通過IF就可以實(shí)現(xiàn)這種動態(tài)更新

示例:

   <update id="updateByIdSelective">
        UPDATE sys_user
        SET
        <if test="userName != null and userName !='' ">
            user_name = #{userName},
        </if>
        <if test="userPassword != null and userPassword != '' ">
            user_password = #{userPassword},
        </if>
        <if test="userEmail != null and userEmail != '' ">
            user_email = #{userEmail},
        </if>
        <if test="userInfo != null and userInfo != '' ">
            user_info = #{userInfo},
        </if>
        <if test="headImg != null">
            head_img = #{headImg, jdbcType=BLOB},
        </if>
        <if test="createTime != null">
            create_time = #{createTime, jdbcType=TIMESTAMP},
        </if>
        id = #{id}
        WHERE id = #{id}
    </update>

測試:

    @Test
    public void testUpdateByIdSelective() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectById(1l);
            sysUser.setUserName("cccc");


            userMapper.updateByIdSelective(sysUser);

        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }
在insert中使用if

應(yīng)用場景:
在數(shù)據(jù)表中插入?yún)?shù)是,如果參數(shù)值不為空,就傳入,如果傳入值為空,就使用數(shù)據(jù)庫中默認(rèn)的值,而不使用空值。

示例:

 <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
        insert INTO sys_user(
            user_name, user_password,
            <if test="userEmail != null and userEmail != ''">
                user_email,
            </if>  user_info, head_img, create_time
        )
        VALUES (
            #{userName}, #{userPassword},
        <if test="userEmail != null and userEmail != ''">
        #{userEmail},
        </if>
         #{userInfo}, #{headImg, jdbcType= BLOB}, #{createTime, jdbcType= DATE}
        )
    </insert>

choose用法
可以實(shí)現(xiàn)if ...else...的邏輯

案例需求:
當(dāng)參數(shù)id有值的時(shí)候,優(yōu)先使用id查詢,當(dāng)id沒有值的時(shí)候,便去判斷用戶名是否有值,如果有值就用用戶名查詢,如果沒有值,就使SQL查詢無結(jié)果。

方案:

 <select id="selectByIdOrUserName" resultType="pers.congcong.myBatis2.pojos.SysUser">
        SELECT id,
            user_name userName,
            user_password userPassword,
            user_email userEmail,
            user_info userInfo,
            head_img headImg,
            create_time createTime
        from sys_user
        WHERE 1=1
        <choose>
            <when test="id != null">
                AND id = #{id}
            </when>
            <when test="userName != null and userName != ''">
                AND user_name = #{userName}
            </when>
            <otherwise>
                and 1 = 2
            </otherwise>
        </choose>
    </select>

測試代碼:

@Test
    public void testselectByIdOrUserName() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            SysUser sysUser = userMapper.selectById(1l);
            sysUser.setId(null);

            SysUser sysUser1 = userMapper.selectByIdOrUserName(sysUser);

            sysUser.setUserName(null);
            sysUser1 = userMapper.selectByIdOrUserName(sysUser);
        } finally {
            sqlSession.close();
        }
    }

where/set/trim用法:

where標(biāo)簽的用法:如果標(biāo)簽包含的元素中有返回值,就插入一個(gè)where,如果where后面的字符串是以and和or開頭的,就將它們剔除。

where會自動剔除 and 或 or 開頭的 and 和 or

<select id="selectByUser" resultType="pers.congcong.myBatis2.pojos.SysUser">
        SELECT id,
            user_name userName,
            user_password userPassward,
            user_email userEmail,
            user_info userInfo,
            head_img headImg,
            create_time createTime
        FROM sys_user
        <where>
        <if test="userName != null and userEmail != ''">
            AND user_name LIKE concat('%', #{userName}, '%')
        </if>
        <if test="userEmail != null and userEmail != ''">
            AND user_email = #{userEmail}
        </if>
        </where>
  </select>
set的用法:

如果標(biāo)簽包含元素中的返回值,就插入一個(gè)set,如果set后面中的元素是以逗號結(jié)尾的,就將這個(gè)逗號剔除。
但是如果set元素中沒有內(nèi)容,照樣會出現(xiàn)SQL錯(cuò)誤,所以,類似id = #{id}這樣必然存在的賦值任然需要保留。

例子:

<update id="updateByIdSelective">
        UPDATE sys_user
        <set>
            <if test="userName != null and userName !='' ">
                user_name = #{userName},
            </if>
            <if test="userPassword != null and userPassword != '' ">
                user_password = #{userPassword},
            </if>
            <if test="userEmail != null and userEmail != '' ">
                user_email = #{userEmail},
            </if>
            <if test="userInfo != null and userInfo != '' ">
                user_info = #{userInfo},
            </if>
            <if test="headImg != null">
                head_img = #{headImg, jdbcType=BLOB},
            </if>
            <if test="createTime != null">
                create_time = #{createTime, jdbcType=TIMESTAMP},
            </if>
            id = #{id},
        </set>
        WHERE id = #{id}
    </update>
trim用法:

where和set都是通過trim實(shí)現(xiàn),并且底層都是通過TrimSqlNode實(shí)現(xiàn)的。

<trim prefix = "SET" suffixOverrides = ",">
...
</trim>

<trim prefix = "WHERE" prefixOverrides = "AND | OR">
...
</trim>

foreach用法

SQL語句中有時(shí)會使用IN關(guān)鍵字,例如 id in (1, 2, 3),可以使用$(ids)方式直接獲取值,但是不能放置SQL注入,避免SQL注入就需要使用#{}的方式,這是就要配合使用foreach標(biāo)簽來滿足需求。

foreach可以對數(shù)組、Map或?qū)崿F(xiàn)Iterable接口的對象進(jìn)行遍歷

foreach實(shí)現(xiàn)in集合

案例需求:
根據(jù)用戶ID集合查詢出所有符合條件的用戶

實(shí)現(xiàn):

 <select id="selectByIdList" resultType="pers.congcong.myBatis2.pojos.SysUser">
        SELECT id,
            user_name userName,
            user_password userPassword,
            user_email userEmail,
            user_info userInfo,
            head_img headImg,
            create_time createTime
        FROM sys_user
        WHERE id IN 
        <foreach collection="list" open="(" close=")" separator="," item="id" index="i">
            #{id}
        </foreach>
    </select>

foreach包含以下屬性:
collection:必填,值為要迭代循環(huán)的屬性名。這個(gè)屬性值的情況很多。
item:變量名,值為從迭代對象中取出的每一個(gè)值。
index:索引的屬性名,在集合數(shù)組情況下值為當(dāng)前索引值,當(dāng)?shù)鷮ο笫荕ap類型是,這個(gè)值為KEY。
open、close、separator。

foreach實(shí)現(xiàn)批量插入:
如果數(shù)據(jù)庫支持批量插入,就可以通過foreach來實(shí)現(xiàn)。批量插入是SQL-92新增的特性,目前支持的數(shù)據(jù)庫有DB2、SQL Server8.2及其以上版本、Mysql、Sqlite3.7.11以上、H2。
 批量插入語法如下:

INSERT INTO tablename (colum-a, [colum-b, ....])
VALUES('value-1a', ['value-1b', ...]),
('value-2a', ['value-2b', ...]),
....

例子:

    <insert id="insertList" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO sys_user(
            user_name, user_password, user_email, user_info, head_img, create_time
        )
        VALUES
       <foreach collection="list" item="user" separator=",">
           (
           #{user.userName}, #{user.userPassword}, #{user.userEmail}, #{user.userInfo}, #{user.headImg, jdbcType= BLOB},
           #{user.createTime, jdbcType= DATE}
           )
       </foreach>
    </insert>

測試代碼:

 @Test
    public void testInsertList() {
        SqlSession sqlSession = getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

            List<SysUser> sysUserList = new ArrayList<SysUser>();

            for (int i = 0; i < 2; i++) {
                SysUser sysUser = new SysUser();
                sysUser.setUserName("cc");
                sysUser.setUserPassword("111111");
                sysUser.setUserEmail("testck@qq.com");
                sysUserList.add(sysUser);
            }

            int result = userMapper.insertList(sysUserList);

            for (SysUser s :
                    sysUserList) {
                System.out.println(s.getId());
            }

            Assert.assertEquals(2, result);
        } finally {
            //為了不影響其他測試,這里選擇回滾
            sqlSession.rollback();
            sqlSession.close();
        }
    }

這里使用了useGeneratedKeys 和 keyProperty 兩個(gè)屬性,可以實(shí)現(xiàn)批量插入后返回主鍵。

foreach實(shí)現(xiàn)動態(tài)update
這個(gè)主要介紹參數(shù)是Map時(shí),foreach怎么實(shí)現(xiàn)動態(tài)update。

bind標(biāo)簽,創(chuàng)建一個(gè)變量并將其綁定到上下文中。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容