Mybatis对JDBC进行了进一步封装,使得我们可以更加便捷的使用Java操作数据库。Mybatis获取参数值有两种方式:#{}${}

在大部分情况下,#{}${}都能相互替代,使用两者之一即可,更加推荐使用#{},因为可以防止SQL注入问题,但是由于#{}${}本质上的不同,部分SQL语句使用#{}${}需要格外注意

#{}和${}本质区别

  1. #{}本质上是占位符赋值,为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号
  2. ${}本质上是字符串拼接,为字符串类型或日期类型的字段进行赋值时,需要手动加单引号

模糊查询

这个场景下,使用#{}${}都能达到目的,但是用法稍有不同

Mapper接口

1
List<User> selectLike(@Param("likeString") String likeString);

直接使用#{}

1
2
3
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like '%#{likeString}%'
</select>

结果报错,?占位符被当做字符串处理了

image-20221005224430441

将#{}换成${}

1
2
3
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like '%${likeString}%'
</select>

成功执行

image-20221005224831546如果非要使用#{},也不是没有解决办法

使用""拼接

1
2
3
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like "%"#{likeString}"%"
</select>

结果

image-20221005225116146

使用concat函数

1
2
3
<select id="selectLike" resultType="pojo.User">
select * from user where user_name like concat('%',#{likeString},'%')
</select>

结果

image-20221005225520256

动态表名

在某些场景下,我们需要来回操作各种表,但SQL语句功能一致,这时我们可以使用动态表名,即传参为表名类型,这时就要从#{}${}中进行选择了

Mapper接口

1
List<User> selectAllFromTable(@Param("tableName") String tableName);

直接使用#{}

1
2
3
<select id="selectAllFromTable" resultType="pojo.User">
select * from #{tableName}
</select>

结果报错,原因在于#{}为占位符赋值,传参为String的话就会自动补上单引号'',而表名不允许添加单引号,所以导致出错

image-20221006085148136

使用${}

1
2
3
<select id="selectAllFromTable" resultType="pojo.User">
select * from ${tableName}
</select>

结果成功了,所以在动态表名的情况下,我们只能使用${}

image-20221006085828225

分页

分页是一个实际开发中用的很广泛的一个功能,但是使用MyBatis传参进行手动分页时,坑可不小

首先我们来看一下分页公式

1
select * from <表名> limit <每页大小> * (<页码> - 1), <每页大小>; 

写出公式,分页就变得很简单了,但是这时候使用#{}进行传参就有一些问题

1
2
3
4
5
6
/**
* @param pageSize 每页大小
* @param currentPage 当前页码
* @return 结果集List
*/
List<User> selectAllByPage(@Param("pageSize") Integer pageSize, @Param("currentPage") Integer currentPage);

使用#{}

1
2
3
<select id="selectAllByPage" resultType="pojo.User">
select * from #{pageSize} * (#{currentPage} - 1), #{pageSize}
</select>

结果报错,原因在于limit后面不能运算,而我们传入的正是运算表达式

image-20221006092530920

既然不能运算,那我们将运算结果传进去不就好了?

1
2
3
<select id="selectAllByPage" resultType="pojo.User">
select * from #{pageSize * (currentPage - 1)}, #{pageSize}
</select>

结果还是报错,原因在于#{}会将大括号内的表达式整体当成一个参数给占位符赋值,这显然是不可以的

image-20221006092428195

使用${}

1
2
3
<select id="selectAllByPage" resultType="pojo.User">
select * from user limit ${pageSize * (currentPage - 1)}, #{pageSize}
</select>

结果成功了,${}会先把大括号内的表达式计算出来,再来进行字符串拼接

image-20221006092133750

注:不光分页场景需要注意${}和#{},其他需要传入计算表达式的场景也需要注意

批量删除

有些场景,需要我们根据id数组批量删除记录,这个时候也有一些坑

由于id数组的长度是不确定的,所以我们不能确定参数的个数,但是我们可以使用in关键字,这个时候我们将id数组转为字符串进行传参就好了

1
[1,2,3] => 1,2,3

Mapper接口

1
Integer deleteByIds(String Ids);

使用#{}

1
2
3
<delete id="deleteByIds">
delete from user where id in (#{ids})
</delete>

结果报错,原因在于in后面的小括号里面的'1,2,3'为字符串类型且为一个整体,与整数类型不符,因此不能使用#{}

image-20221006093512825

使用${}

1
2
3
<delete id="deleteByIds">
delete from user where id in (${ids})
</delete>

结果成功了,看来有些场景不得不使用${}

image-20221006093835757