动态sql在xml中支持的几种标签:

  • if
  • choose(when、otherwise)
  • trim(where、set)
  • foreach
  • bind

    4.1 if用法

    4.1.1 在where条件中使用if

    1. /**
    2. * 根据动态条件查询用户信息
    3. * @param user
    4. * @return
    5. */
    6. List<SysUser> selectByUser(SysUser user);
    1. <select id="selectByUser" resultType="com.ql.simple.model.SysUser">
    2. select id,
    3. user_name,
    4. user_password,
    5. user_email,
    6. user_info,
    7. head_img,
    8. create_time
    9. from sys_user
    10. where 1 = 1
    11. <if test="userName != null and userName != ''">
    12. and user_name like concat('%', #{userName}, '%')
    13. </if>
    14. <if test="userEmail != null and userEmail != ''">
    15. and user_email = #{userEmail}
    16. </if>
    17. </select>

    if中必填的属性时test,test是一个符合OGNL要求的判断表达式

  • 注意sql中where关键字后面的条件

  • 注意条件中的and或or

测试:

  1. @Test
  2. public void testSelectByUser() {
  3. SqlSession sqlSession = getSqlSession();
  4. try {
  5. UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
  6. // 只查询用户名
  7. SysUser user = new SysUser();
  8. user.setUserName("ad");
  9. List<SysUser> userList = userMapper.selectByUser(user);
  10. Assert.assertTrue(userList.size() > 0);
  11. // 只查询邮箱
  12. SysUser user2 = new SysUser();
  13. user2.setUserEmail("test@mybatis.tk");
  14. List<SysUser> userList2 = userMapper.selectByUser(user2);
  15. Assert.assertTrue(userList2.size() > 0);
  16. // 同时查询用户名和邮箱
  17. SysUser user3 = new SysUser();
  18. user3.setUserName("ad");
  19. user3.setUserEmail("test@mybatis.tk");
  20. List<SysUser> userList3 = userMapper.selectByUser(user3);
  21. Assert.assertTrue(userList3.size() == 0);
  22. }finally {
  23. sqlSession.close();
  24. }
  25. }

4.1.2 在update更新列中使用if

  1. /**
  2. * 根据主键更新
  3. * @param sysUser
  4. * @return
  5. */
  6. int updateByIdSelective(SysUser sysUser);
  1. <update id="updateByIdSelective">
  2. update sys_user
  3. set
  4. <if test="userName != null and userName != ''">
  5. user_name = #{userName},
  6. </if>
  7. <if test="userPassword != null and userPassword != ''">
  8. user_password = #{userPassword},
  9. </if>
  10. <if test="userEmail != null and userEmail != ''">
  11. user_email = #{userEmail},
  12. </if>
  13. <if test="userInfo != null and userInfo != ''">
  14. user_info = #{userInfo},
  15. </if>
  16. <if test="headImg != null">
  17. head_img = #{headImg, jdbcType=BLOB},
  18. </if>
  19. <if test="createTime != null">
  20. create_time = #{createTime,jdbcType=TIMESTAMP},
  21. </if>
  22. id = #{id}
  23. where id = #{id}
  24. </update>
  • 注意 id = #{id}条件,防止if全部不成立时,sql语法错误
  • 每个if查询中都是有“,”的,所以最后id = #{id}省略的话,会导致sql语法错误

    4.1.3 在insert动态插入列中使用if

    1. /**
    2. * 添加用户,使用useGenerateKeys方式
    3. * @param user
    4. * @return
    5. */
    6. int insert2(SysUser user);
    1. <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
    2. insert into sys_user(id,
    3. user_name,
    4. user_password,
    5. <if test="userEmail != null and userEmail != ''">
    6. user_email,
    7. </if>
    8. user_info,
    9. head_img,
    10. create_time)
    11. values ( #{id}, #{userName}, #{userPassword},
    12. <if test="userEmail != null and userEmail != ''">
    13. #{userEmail},
    14. </if>
    15. #{userInfo}, #{headImg, jdbcType=BLOB}, #{createTime, jdbcType=TIMESTAMP} )
    16. </insert>

    4.2 choose用法

    1. /**
    2. * 根据用户id或用户名查询
    3. * @param sysUser
    4. * @return
    5. */
    6. SysUser selectByIdOrUserName(SysUser sysUser);
    1. <select id="selectByIdOrUserName" resultType="com.ql.simple.model.SysUser">
    2. select id,
    3. user_name,
    4. user_password,
    5. user_email,
    6. user_info,
    7. head_img,
    8. create_time
    9. from sys_user
    10. where 1 = 1
    11. <choose>
    12. <when test="id != null">
    13. and id = #{id}
    14. </when>
    15. <when test="userName != null and userName != ''">
    16. and user_name = #{userName}
    17. </when>
    18. <otherwise>
    19. and 1 = 2
    20. </otherwise>
    21. </choose>
    22. </select>

    4.3 wherre、set、trim用法

    4.3.1 where用法

    1. <select id="selectByUser" resultType="com.ql.simple.model.SysUser">
    2. select id,
    3. user_name,
    4. user_password,
    5. user_email,
    6. user_info,
    7. head_img,
    8. create_time
    9. from sys_user
    10. <where>
    11. <if test="userName != null and userName != ''">
    12. and user_name like concat('%', #{userName}, '%')
    13. </if>
    14. <if test="userEmail != null and userEmail != ''">
    15. and user_email = #{userEmail}
    16. </if>
    17. </where>
    18. </select>

    也就是sql中where语句的作用,但是这里的where标签会把语句后面and或or开头的单词去掉,这样就不会有sql异常。这样也不需要像之前那样添加1 = 1 这样的临时条件

    4.3.2 set用法

    1. <update id="updateByIdSelective">
    2. update sys_user
    3. <set>
    4. <if test="userName != null and userName != ''">
    5. user_name = #{userName},
    6. </if>
    7. <if test="userPassword != null and userPassword != ''">
    8. user_password = #{userPassword},
    9. </if>
    10. <if test="userEmail != null and userEmail != ''">
    11. user_email = #{userEmail},
    12. </if>
    13. <if test="userInfo != null and userInfo != ''">
    14. user_info = #{userInfo},
    15. </if>
    16. <if test="headImg != null">
    17. head_img = #{headImg, jdbcType=BLOB},
    18. </if>
    19. <if test="createTime != null">
    20. create_time = #{createTime,jdbcType=TIMESTAMP},
    21. </if>
    22. id = #{id},
    23. </set>
    24. where id = #{id}
    25. </update>

    set的作用和update语句中set语句的作用一致,只是如果该标签后面的字符串是以逗号结尾的,就将这个逗号剔除

    4.3.3 trim的用法

    where和set标签的功能都可以用trim标签来实现,底层就是通过TrimSqlNode来实现的
    where标签对应的trim的实现:

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

    set标签对应的trim实现:

    1. <trim prefix="SET" suffixOverrides=",">
    2. ...
    3. </trim>

    4.4 foreach用法

    4.4.1 foreach实现in集合

    1. /**
    2. * 根据用户id集合查询
    3. * @param idList
    4. * @return
    5. */
    6. List<SysUser> selectByIdList(List<Long> idList);
    1. <select id="selectByIdList" resultType="com.ql.simple.model.SysUser">
    2. select id,
    3. user_name,
    4. user_password,
    5. user_email,
    6. user_info,
    7. head_img,
    8. create_time
    9. from sys_user
    10. where id in
    11. <foreach collection="list" open="(" close=")" separator="," item="id" index="i">
    12. #{id}
    13. </foreach>
    14. </select>

    foreach包含的属性:

  • collection:必填,值为要迭代循环的属性名

  • item:变量名
  • index:索引的属性名
  • open:整个循环内容开头的字符串
  • close:整个循环内容结尾的字符串
  • separator

collection属性的设置:

  1. 只有一个数组或集合参数

collection=”list” or collection=”array”

  1. 有多个参数

用@Param指定参数,将collection设为param注解指定的名字

  1. 参数是Map类型

与param注解相似,将collection指定为对应Map中的key即可,默认为_parameter

  1. 参数是一个对象

指定为对象的属性名即可

4.4.2 foreach实现批量插入

  1. /**
  2. * 批量插入用户信息
  3. * @param userList
  4. * @return
  5. */
  6. int insertList(List<SysUser> userList);
  1. <insert id="insertList">
  2. insert into sys_user(user_name, user_password, user_email, user_info, head_img, create_time)
  3. values
  4. <foreach collection="list" item="user" separator=",">
  5. (#{user.userName}, #{user.userPassword}, #{user.userEmail}, #{user.userInfo}, #{user.headImg,jdbcType=BLOB},
  6. #{user.createTime,jdbcType=TIMESTAMP})
  7. </foreach>
  8. </insert>

如果要在MySQL中实现批量插入返回自增主键值:

  1. <insert id="insertList" useGeneratedKeys="true" keyProperty="id">

4.4.3 foreach实现动态update

  1. /**
  2. * 通过Map更新列
  3. * @param map
  4. * @return
  5. */
  6. int updateByMap(Map<String, Object> map);
  1. <update id="updateByMap">
  2. update sys_user
  3. set
  4. <foreach collection="_parameter" item="val" index="key" separator=",">
  5. ${key} = #{val}
  6. </foreach>
  7. where id = #{id}
  8. </update>

index对应的值为map的key

4.5 bind用法

bind标签主要是用来避免由于更换数据库带来的一些麻烦

  1. <if test="userName != null and userName != ''">
  2. and user_name like concat('%', #{userName}, '%')
  3. </if>

该语句在mysql中正常,但是换到oracle会报错

  1. <if test="userName != null and userName != ''">
  2. <bind name="userNameLike" value="'%' + userName + '%'"/>
  3. and user_name like #{userNameLike}
  4. </if>

4.6 多数据库支持

4.7 OGNL用法