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
表示结束部分的字符串。