Mybatis(四)之动态SQL

在实际场景中,我们需要根据业务使用sql语句,这时动态sql语句就能很大程度上提高代码重用性,使编程更加灵活

  • if
  • where
  • trim
  • set
  • foreach
  • bind
  • choose
  • when
  • otherwise

if和where

我们先来看看示例

// mapper接口
public interface UserMapper {
    public List<User> findUserListByUserInfo(User user);
}

//mapper映射文件
<select id="findUserListByUserInfo" parameterType="com.zyj.mybatis.po.User" resultType="com.zyj.mybatis.po.User">
        select * from user where username like '%${username}%' and sex = #{sex}
</select>

//测试代码
@Test
public void testFindUserListByUserInfo() throws IOException {
    //......
    // 调用mapper方法
    User userCondition = new User();
    userCondition.setUsername("小明");
    userCondition.setSex("1");
    List<User> list = userMapper.findUserListByUserInfo(userCondition);
    //......
}
问题:以上代码可以正常运行,但是存在硬编码问题,灵活性差
比如只能固定使用username和sex两个字段作为条件来查询,如果增加或缺少字段,就会导致程序运行结果与预期不符
解决方法:使用Mybatis提供的标签,实现动态SQL语句
我们可以修改下mapper映射文件

<select id="findUserListByUserInfo" parameterType="com.zyj.mybatis.po.User" resultType="com.zyj.mybatis.po.User">
    select * from user 
    <!-- where标签:默认去掉后面第一个AND或OR,如果没有参数,则把自己干掉 -->
    <where>
        <!-- if标签:可以对输入的参数进行判断 -->
        <!-- test:指定判断表达式 -->
        <if test="username != null and username != ''">
            and username like '%${username}%'
        </if>
        <if test="sex != null and sex != ''">
            and sex = #{sex}
        </if>
    </where>
</select>

修改后,Mybatis可以自行根据条件创建sql语句

另外还支持将通用SQL抽取出来,提高代码重用性

<!-- 定义sql片段 -->
<!-- sql片段内,可以定义sql语句中任何部分 -->
<!-- sql片段内,最好不用将where和select关键字声明在内 -->
<sql id="whereClause">
    <if test="user != null">
        <if test="username != null and username != ''">
            AND username LIKE '%${username}%'
        </if>
        <if test="sex != null and sex != ''">
            AND sex = #{sex}
        </if>
    </if>
</sql>

<select id="findUserListByUserInfo" parameterType="com.zyj.mybatis.po.User" resultType="com.zyj.mybatis.po.User">
    select * from user 
    <where>
        <!-- 引入sql片段 -->
        <include refid="whereClause" />
    </where>
</select>

trim

上面的where标签,其实用trim可以表示如下:

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

它的意思就是: 当WHERE后紧随AND或则OR的时候,就去除AND或者OR。 除了WHERE以外, 其实还有一个比较经典的实现,那就是SET。

set

<update id="updateUser" parameterType="com.dy.entity.User">
    update user set 
    <if test="name != null">
        name = #{name},
    </if> 
    <if test="password != null">
        password = #{password},
    </if> 
    <if test="age != null">
        age = #{age}
    </if> 
    <where>
        <if test="id != null">
            id = #{id}
        </if>
        and deleteFlag = 0;
    </where>
</update>

问题来了: “如果只有name不为null时, 那么这SQL不就成了 update set name = #{name}, where ........? 那name后面那逗号会导致出错啊!”

是的,这时候,就可以用mybatis为我们提供的set标签了。下面是通过set标签改造后:

<update id="updateUser" parameterType="com.dy.entity.User">
       update user
    <set>
        <if test="name != null">name = #{name},</if> 
        <if test="password != null">password = #{password},</if> 
        <if test="age != null">age = #{age},</if> 
    </set>
    <where>
        <if test="id != null">
            id = #{id}
        </if>
        and deleteFlag = 0;
    </where>
</update>

这个用trim可表示为:

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

WHERE是使用的 prefixOverrides(前缀), SET是使用的 suffixOverrides (后缀), 看明白了吧!

foreach

需求:SELECT * FROM user WHERE id IN (1,10,16)
// mapper接口
public interface UserMapper {
    public List<User> findUserListByIdList(List<Integer> ids);
}

// mapper映射文件
<select id="findUserListByIdList" parameterType="list" resultType="com.zyj.mybatis.po.User">
    select * from user 
    <where>
        <if test="list != null">
            <!-- collection:表示List的属性名称 -->
            <!-- index: 当前所遍历到的元素下标 -->
            <!-- item: 为遍历出的结果声明一个变量名称 -->
            <!-- open:遍历开始时,需要拼接的字符串 -->
            <!-- close: 遍历结束时,需要拼接的字符串 -->
            <!-- separator:遍历中间需要拼接的连接符 -->
            and id in 
            <foreach collection="list" index="index" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
    // 拼出来的字符串:where id in (1, 10, 16)
</select>

// 测试代码
@Test
public void findUserListByIdList() throws IOException {
    //......
    // 调用mapper方法
    List<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(10);
    ids.add(16);
    List<User> list = mapper.findUserListByIdList(ids);
    //......
}

bind

bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:

<select id="selectBlogsLike" resultType="Blog">
    <bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
    SELECT * FROM BLOG
    WHERE title LIKE #{pattern}
</select>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值