Mybatis-动态SQL

340 阅读3分钟

动态SQL是mybatis的强大特性之一,主要包括以下几点

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

前置条件
  1. 项目是springboot搭建
  2. 开启mybatis的驼峰等配置
mybatis:
  mapper-locations: classpath:mapper/*Mapper.xml
  type-aliases-package: top.kooper.demo.model
  configuration:
    map-underscore-to-camel-case: true
  1. demo中的实体类。我这边为了简略代码,使用了lombok插件,可自行谷歌学习
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private Long id;
    private Long viewId;
    private String phone;
    private String nickname;
    
    public User(Long viewId, String phone, String nickname) {
        this.viewId = viewId;
        this.phone = phone;
        this.nickname = nickname;
    }
}

1. if
	//dao
	List<User> select_viewId(@Param("viewId")Long viewId);
	
	//xml
    <select id="select_viewId" resultType="User">
        select
        *
        from user
        where 1=1
        <if test="viewId != null">
            view_id = #{viewId}
        </if>
    </select>

如果viewId不为空,那么查询将会包含这个条件


2. choose(when,otherwise)

当SQL中判断条件较多时,可以采用这种方式

//dao
User selectByNicknameAndPhone(@Param("nickname") String nickname, @Param("phone") String phone);

//xml
<select id="selectByNicknameAndPhone" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List"/>
    from user
    where 1=1
    <choose>
        <when test="nickname != null and phone != null">
            and phone = #{phone} and nickname like #{nickname}
        </when>
        <when test="phone != null">
            and phone = #{phone}
        </when>
        <otherwise>
        
        </otherwise>
    </choose>
</select>

3. trim(where,set)
  • 在前面的示例中已经解决了动态SQL的问题,但是为了防止条件不匹配,出现多余的连接符and/or等,我们在where条件后面加了一个硬性条件1=1。
  • where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入“WHERE”子句。而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除
//dao
User selectByWhere(@Param("nickname")String nickname, @Param("phone") String phone);

//xml
<select id="selectByWhere" resultType="User">
    select
    *
    from user
    <where>
        <if test="nickname != null and phone != null">
            phone = #{phone} and nickname like #{nickname}
        </if>
        <if test="phone != null">
            and phone = #{phone}
        </if>
    </where>
</select>

与where标签等价的为自定义trim标签:

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

prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。

  • 在动态更新语句中,可能会出现最后一个条件多一个“,”。
  • set元素会删掉无关的逗号
//dao
int update(User user);

//xml
<update id="update">
    update user
    <set>
        <if test="viewId != null">
            view_id = #{viewId},
        </if>
        <if test="nickname != null">
            nickname = #{nickname},
        </if>
        <if test="phone != null">
            phone = #{phone}
        </if>
    </set>
    where id = #{id}
</update>

与set标签等价的为自定义trim标签:

<trim prefix="WHERE" prefixOverrides="AND|OR">
  ... 
</trim>
  • set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号

4. foreach

对集合进行遍历

//dao
List<User> selectByList(List<Long> list);

//xml
<select id="selectByList" resultType="User">
    select
    *
    from user
    where id in
    <foreach collection="list" index="index" item="item" open="(" close=")" separator=",">
        #{item}
    </foreach>
</select>
  • 注意:foreach可以遍历任何可迭代对象。当对象是数组或者列表,index是当前对象下标,item是本息迭代获取的元素。当对象是map时,index是键,item是值。
5. bind

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

//dao
List<User> selectByBind(User user);

//xml
<select id="selectByBind" resultMap="BaseResultMap" parameterType="User">
    <bind name="nicknamebind" value="'%'+nickname+'%'"></bind>
    select
    <include refid="Base_Column_List"/>
    from user
    where  phone = #{phone} and nickname like #{nicknamebind}
</select>