一些特殊SQL使用Mybatis的#{}和${}注意点
Mybatis对JDBC进行了进一步封装,使得我们可以更加便捷的使用Java操作数据库。Mybatis获取参数值有两种方式:#{}
和${}
在大部分情况下,#{}
和${}
都能相互替代,使用两者之一即可,更加推荐使用#{}
,因为可以防止SQL注入问题,但是由于#{}
和${}
本质上的不同,部分SQL语句使用#{}
和${}
需要格外注意
#{}和${}本质区别
#{}
本质上是占位符赋值,为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号${}
本质上是字符串拼接,为字符串类型或日期类型的字段进行赋值时,需要手动加单引号
模糊查询
这个场景下,使用#{}
和${}
都能达到目的,但是用法稍有不同
Mapper接口
List<User> selectLike(@Param("likeString") String likeString);
直接使用#{}
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like '%#{likeString}%'
</select>
结果报错,?
占位符被当做字符串处理了
将#{}换成${}
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like '%${likeString}%'
</select>
成功执行
如果非要使用#{},也不是没有解决办法
使用""
拼接
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like "%"#{likeString}"%"
</select>
结果
使用concat函数
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like concat('%',#{likeString},'%')
</select>
结果
动态表名
在某些场景下,我们需要来回操作各种表,但SQL语句功能一致,这时我们可以使用动态表名,即传参为表名类型,这时就要从#{}
和${}
中进行选择了
Mapper接口
List<User> selectAllFromTable(@Param("tableName") String tableName);
直接使用#{}
<select id="selectAllFromTable" resultType="pojo.User">
select * from #{tableName}
</select>
结果报错,原因在于#{}
为占位符赋值,传参为String的话就会自动补上单引号''
,而表名不允许添加单引号,所以导致出错
使用${}
<select id="selectAllFromTable" resultType="pojo.User">
select * from ${tableName}
</select>
结果成功了,所以在动态表名的情况下,我们只能使用${}
分页
分页是一个实际开发中用的很广泛的一个功能,但是使用MyBatis传参进行手动分页时,坑可不小
首先我们来看一下分页公式
select * from <表名> limit <每页大小> * (<页码> - 1), <每页大小>;
写出公式,分页就变得很简单了,但是这时候使用#{}进行传参就有一些问题
/**
* @param pageSize 每页大小
* @param currentPage 当前页码
* @return 结果集List
*/
List<User> selectAllByPage(@Param("pageSize") Integer pageSize, @Param("currentPage") Integer currentPage);
使用#{}
<select id="selectAllByPage" resultType="pojo.User">
select * from #{pageSize} * (#{currentPage} - 1), #{pageSize}
</select>
结果报错,原因在于limit后面不能运算,而我们传入的正是运算表达式
既然不能运算,那我们将运算结果传进去不就好了?
<select id="selectAllByPage" resultType="pojo.User">
select * from #{pageSize * (currentPage - 1)}, #{pageSize}
</select>
结果还是报错,原因在于#{}会将大括号内的表达式整体当成一个参数给占位符赋值,这显然是不可以的
使用${}
<select id="selectAllByPage" resultType="pojo.User">
select * from user limit ${pageSize * (currentPage - 1)}, #{pageSize}
</select>
结果成功了,${}
会先把大括号内的表达式计算出来,再来进行字符串拼接
注:不光分页场景需要注意${}和#{},其他需要传入计算表达式的场景也需要注意
批量删除
有些场景,需要我们根据id数组批量删除记录,这个时候也有一些坑
由于id数组的长度是不确定的,所以我们不能确定参数的个数,但是我们可以使用in关键字,这个时候我们将id数组转为字符串进行传参就好了
[1,2,3] => 1,2,3
Mapper接口
Integer deleteByIds(String Ids);
使用#{}
<delete id="deleteByIds">
delete from user where id in (#{ids})
</delete>
结果报错,原因在于in后面的小括号里面的'1,2,3'
为字符串类型且为一个整体,与整数类型不符,因此不能使用#{}
使用${}
<delete id="deleteByIds">
delete from user where id in (${ids})
</delete>
结果成功了,看来有些场景不得不使用${}
使用${}
<delete id="deleteByIds">
delete from user where id in (${ids})
</delete>
结果成功了,看来有些场景不得不使用${}