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个参数时,取值为list或array,取决于集合对象的数据类型,当抽象方法 有多个参数时,使用@Param注解中的名称,item表示遍历过程中的变量名,separator表示分隔符。
以上配置还可以调整为:
id in
<foreach collection="array"
item="id" separator=","
open="(" close=")">
#{id}
</foreach>即:open表示由<foreach>处理的SQL语句的起始部分的字符串,而close表示结束部分的字符串。