深入浅出Mybatis(七)动态sql

时间:2022-11-16 16:17:55

针对前面的用户信息综合查询这条sql

<!-- 用户信息综合查询 -->
    <select id="findUserList" parameterType="userQueryVo" resultType="userCustom">
        select * from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
    </select>

如果我们传入的参数为空,那么就会有问题。

这时就需要用到我们的if条件判断。

<!-- 用户信息综合查询 -->
    <select id="findUserList" parameterType="userQueryVo" resultType="userCustom">
        select * from user
         <where>
             <if test="userCustom != null">
                 <if test="userCustom.sex != null">
                     <!-- 第一个条件的and可以不写,写了也没关系,where标签会自动去掉第一个and -->
                    and user.sex = #{userCustom.sex}
                 </if>
                 <if test="userCustom.username != null">
                     and user.username like '%${userCustom.username}%'
                 </if>
             </if>
         </where>

    </select>

测试一下:

结果跟原来一样

[User{id=10, username='张三', birthday=Wed Mar 07 08:00:00 CST 2018, sex='1', addr='成都'}, User{id=39, username='张四', birthday=Wed Mar 21 08:00:00 CST 2018, sex='1', addr='北京'}]

sql片段:

当我们的一个查询条件被多个sql公用时,这时就需要将条件进行抽取,形成单独的sql片段,方便多个sql语句来共用。

首先需要定义sql片段:

<!-- 定义sql片段
            id: sql片段唯一标识
            经验:是基于单标定义sql片段,这样的话sql片段可重用性才高
     -->
    <sql id="query_user_where">
        <if test="userCustom != null">
            <if test="userCustom.sex != null">
                and user.sex = #{userCustom.sex}
            </if>
            <if test="userCustom.username != null">
                and user.username like '%${userCustom.username}%'
            </if>
        </if>
    </sql>

然后在需要的地方直接进行引用即可

<!-- 用户信息综合查询 -->
    <select id="findUserList" parameterType="userQueryVo" resultType="userCustom">
        select * from user
         <where>
             <!-- 引用定义的sql片段,如果不在本mapper中,需要加上namespace -->
             <include refid="query_user_where"/>
         </where>

    </select>



foreach:

假设我们需要查询id为 1或10或16的用户信息。

在UserQueryVo中新添加一个属性,并生成get和set方法

深入浅出Mybatis(七)动态sql

在mapper.xml中添加一个foreach

<sql id="query_user_where">
        <if test="userCustom != null">
            <if test="userCustom.sex != null">
                and user.sex = #{userCustom.sex}
            </if>
            <if test="userCustom.username != null">
                and user.username like '%${userCustom.username}%'
            </if>
            <!-- 使用foreach遍历传入ids
                collection:指定输入对象中集合属性
                item:每个遍历生成对象
                open:开始遍历时拼接的串
                close:结束遍历时拼接的串
                separator:遍历的两个对象中需要拼接的串
                使用实现下边的sql拼接:
                and (id=1 or id=10 or id=16)
             -->
            <foreach collection="ids" item="user_id" open="and (" close=")" separator="or">
                  id=#{user_id}
            </foreach>
        </if>
    </sql>

对它进行测试

@Test
    public void testfindUserList() throws Exception{
        SqlSession sqlSession = factory.openSession();
        //通过反射拿到UserMapper的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        UserQueryVo userQueryVo = new UserQueryVo();
        UserCustom userCustom = new UserCustom();
        //查询所有性别为1并且性张的用户
        userCustom.setSex("1");
        userCustom.setUsername("张");
        userQueryVo.setUserCustom(userCustom);
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(10);
        ids.add(16);
        userQueryVo.setIds(ids);
       List user = userMapper.findUserList(userQueryVo);
        System.out.println(user);

    }
}
成功的输出了   性别为1,性张, 并且id 在(1,10,16)这三个数字中的用户信息

[User{id=10, username='张三', birthday=Wed Mar 07 08:00:00 CST 2018, sex='1', addr='成都'}]

上面的foreach的另外一种实现

            <!-- 实现  and id in (1,10,16) 拼接 -->
            <foreach collection="ids" item="user_id" open="and id in (" close=")" separator=",">
                <!-- 每个遍历需要拼接的串 -->
                #{user_id}
            </foreach>
结果跟上面一样