Mybatis占位符的使用、动态SQL

1. MyBatis中的占位符

在MyBatis中,常见的占位符格式是#{参数},其中,也可能是参数对象中的属性,如果参数是Map类型,还可以是Map中的key。

使用#{}的占位符可用于替换,例如:

select * from t_user where username=?

即可替换以上语句中的问号(?),在实际运行时,MyBatis会将以上SQL语句进行预编译,并后续使用#{}替换问号(?)。

假设获取用户列表时,排序规则不确定,可能使用的抽象方法是:

List<User> findAllOrderedList(String orderBy);

配置的映射可能是:

<select id="xx" resultType="xx">
    select * from t_user
    order by #{orderBy}
</select>

调用时:

mapper.findAllOrderedList("id asc");
mapper.findAllOrderedList("id desc");

以上代码的执行效果是失败的!需要将#{}修改为${},且在抽象方法中,这样的参数必须添加@Param注解,即:

List<User> findAllOrderedList(
    @Param("orderBy") String orderBy);

<select id="xx" resultType="xx">
    select * from t_user
    order by ${orderBy}
</select>

然后,在调用时,就可以根据参数的不同,实现不同的排序效果!

使用${}格式的占位符并不具备预编译的效果!它是直接拼接形成的SQL语句,例如:"select * from t_user order by" + orderBy,如果一定使用${}格式的占位符来表示某个值,还需要考虑单引号类似的问题,例如:select * from t_user where username='${username}',由于只是拼接,所以,还存在SQL注入风险!

小结

使用#{}是预编译的(没有SQL注入风险,无需关注数据类型),使用${}不是预编译的;

使用#{}只能替换某个值,使用${}可以替换SQL语句中的任何部分;

关于SQL注入,不需要太过于紧张,预编译可以从根源上杜绝,或者,在执行SQL指令之前,判断参数中是否包含单引号也可以杜绝!

通过使用${},可以使得SQL更加灵活,更加通用!但是,却不推荐太过于通用的SQL!因为,即使查询条件可以自由更改,但是,不同的查询条件对应不同的需求,所需的字段列表很有可能是不一样的,查询时,获取不必要的字段,就会造成不必要的资源浪费,例如,显示列表时,可能需要用户名、密码、年龄、手机、邮箱,但是,登录的查询就只需要用户名、密码即可,年龄、手机、邮箱这几项数据在登录时是不需要的,如果也查询出来,就是浪费资源!如果变量太多,又会导致不可控因素太多,容易出错!

2. 动态SQL

在MyBatis的映射文件中,配置SQL语句时,可以添加例如<if>此类的标签,实现SQL语句的动态变化,即:参数不同,最终执行的SQL语句可能是不同的!

在使用动态SQL时,最常用的就是<if><foreach>这两种,<if>是用于判断的,例如:

select 
    * 
from 
    t_user

<if test="where != null">
where 
    ${where}
</if>

<if test="orderBy != null">
order by 
    ${orderBy}
</if>

关于<foreach>,主要用于循环处理SQL语句中的某个部分,例如:批量删除某些数据!它的SQL语句可能是:

delete from t_user where id in (?,?,?)

其中,in关键字右侧的括号中的内容是不确定的,应该是由用户操作时决定的!则需要<foreach>动态的生成这个部分!

针对这个问题,设计的抽象方法可能是:

Integer deleteByIds(Integer[] ids);

配置的映射为:

<delete id="deleteByIds">
    delete from 
        t_user
    where
        id in (
        <foreach collection="array"
            item="id" separator=",">
            #{id}
        </foreach>
        )
</delete>

以上配置的<foreach>中,collection表示被遍历的集合对象,当抽象方法只有1个参数时,取值为listarray,取决于集合对象的数据类型,当抽象方法 有多个参数时,使用@Param注解中的名称,item表示遍历过程中的变量名,separator表示分隔符。

以上配置还可以调整为:

id in
<foreach collection="array"
    item="id" separator=","
    open="(" close=")">
    #{id}
</foreach>

即:open表示由<foreach>处理的SQL语句的起始部分的字符串,而close表示结束部分的字符串。

QAQ感谢你的支持=w=