MyBatis中可以使用#{}
或 ${}
两种语法填充 sql 参数。两种方法有不同的适用场景
使用 #{}
语法时,Mybatis 会使用预编译语句处理 sql,将参数以占位符的形式填充
select * from t_user where id = #{id}
等价于
PreparedStatement s = conn.prepareStatement("select * from t_user where id = ?");
填充参数时,对于字符串类型会自动包含引号
能够防止 sql 注入,无论内容是什么,都以普通字符串参数去解析
不适用于group by
、order by
等这些需要列名的场景
因为字段以占位符形式填充,列名会包含引号,sql 会解析错误
<select id="listOrderBy" resultType="top.originyy.interviewjava.case11.mybatis.entity.User"> select * from t_user order by #{sortField} #{sortType} </select>
List<User> listOrderBy(@Param("sortField") String sortField, @Param("sortType") String sortType);
sql 等价于
select * from t_user order by 'username' 'desc'
结果来看排序是无效的
${}
语法会在 sql 语句中插入未转义的字符串,将参数内容原封不动的替换占位符。
不会包含引号,所以使用这种方法时,需要在参数外自行添加一对引号。
<select id="listByName2" resultType="top.originyy.interviewjava.case11.mybatis.entity.User"> select * from t_user where username='${name}' </select>
会引起 sql 注入问题,示例:
@Test public void listByName2() { List<User> users = userMapper.listByName2("zhangsan' or 1=1 -- "); System.out.println(JSONUtil.toJsonStr(users)); }
sql 执行结果
${}
适用于根据参数插入列名、表名的场景
如:
<select id="listOrderBy2" resultType="top.originyy.interviewjava.case11.mybatis.entity.User"> select * from t_user order by ${sortField} ${sortType} </select>
List<User> listOrderBy2(@Param("sortField") String sortField, @Param("sortType") String sortType);
但是使用${}
有 sql注入风险,可以考虑使用动态 sql 根据参数判断实现
@Param 注解指定占位符中使用的参数名
不指定只能使用 #{param1}、#{param2}...
或者 #{arg0}、#{arg1}...