MyBatis 参数赋值:#{} 和 ${}及区别

一. #{} 和${} 使用

1 对Interger类型的参数

#{}:
@Select("select username, `password`, age, gender, phone from userinfo where 
id= #{id} ")
 UserInfo queryById(Integer id);

发现输出的SQL语句:
 select username, `password`, age, gender, phone from userinfo where id= ?
输入的参数并没有在后面拼接,id的值是使用  ? 进型占位。这种SQL 称之为"预编译SQL"。

${}

@Select("select username, `password`, age, gender, phone from userinfo where 
id= ${id} ")
 UserInfo queryById(Integer id);

这次的参数是直接拼接在SQL语句中。

2 对String类型的参数 

#{}:

@Select("select username, `password`, age, gender, phone from userinfo where 
username= #{name} ")
UserInfo queryByName(String name);

${}

@Select("select username, `password`, age, gender, phone from userinfo where 
username= '${name}' ")
 UserInfo queryByName(String name);

字符串作为参数时, 需要添加引号 ' ' , 使用 ${} 不会拼接引号 ' ' , 如果不加就会导致程序报错。
注意到:
#{} 使用的是预编译SQL, 通过 ? 占位的方式, 提前对SQL进行编译, 然后把参数填充到SQL语句中。 #{} 会根据参数类型, 自动拼接引号 ' ' 。
${} 会直接进行字符替换, 一起对SQL进行编译。如果参数为字符串, 需要手动加上引号 ' ' 。
参数为数字类型时,也可以加上,查询结果不变,但是可能会导致索引失效,性能下降。

二、#{} 和${} 区别

#{} 和 ${} 的区别就是预编译SQL和即时SQL 的区别。
当发送一条SQL语句给服务器后, 大致流程如下:
  1. 解析语法和语义, 校验SQL语句是否正确
  2. 优化SQL语句, 制定执行计划
  3. 执行并返回结果
一条 SQL如果走上述流程处理,称之为 Immediate Statements(即时 SQL)

1.性能更好

绝大多数情况下, 某一条 SQL 语句可能会被反复调用执行, 或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同, update 的 set 子句值不同, insert 的 values 值不同)。如果每次都需要经过上面的语法解析, SQL优化、SQL编译等,则效率就明显不行。
预编译SQL,编译一次之后会将编译后的SQL语句缓存起来,后面再次执行这条语句时,不会再次编译(只是输入的参数不同), 省去了解析优化等过程, 以此来提高效率。

2.SQL注入

SQL注入:是通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。sql 注入代码: ' or 1 = ' 1 

SQL注入举例:

@Select("select username, `password`, age, gender, phone from userinfo where 
username= '${name}' ")
 List<UserInfo> queryByName(String name);
@Test
void queryByName() {
 List<UserInfo> userInfos = userInfoMapper.queryByName(" ' or 1='1 ");
 System.out.println(userInfos);
}

可以看出,查询的数据并不是想要的数据。${} 可能会产生SQL注入的问题,所以用于查询的字段,尽量使用 #{} 预查询的方式。 

SQL注入是一种非常常见的数据库攻击手段, SQL注入漏洞也是网络世界中最普遍的漏洞之一。 如果发生在用户登录的场景中, 密码输入为 ' or 1='1 , 就可能完成登录。
${} 会有SQL注入的风险, 所以尽量使用#{}完成查询。那么, 是不是 ${} 就没有存在的必要性了呢?
下面来看一下 ${} 的使用场景:
 
1. 排序功能

Mapper实现: 

@Select("select id, username, age, gender, phone, delete_flag, create_time, 
update_time " +
 "from userinfo order by id ${sort} ")
List<UserInfo> queryAllUserBySort(String sort);
使用  ${sort} 可以实现排序查询。而使用  #{sort} 查询时会自动加引号, 会导致 sql 错误。
那么使用${}仍然存在SQL注入,需要控制参数,只设置为desc或者asc即可。
除此之外, 还有字段和表名作为参数时, 也只能使用  ${}。但也需要考虑SQL注入。
2. like 查询
${}存在SQL注入的问题,所以不能直接使用 ${}。解决办法:使用 mysql 的内置函数 concat() 来处理,实现代码如下:
@Select("select id, username, age, gender, phone, delete_flag, create_time, 
update_time " +
 "from userinfo where username like concat('%',#{key},'%')")
 List<UserInfo> queryAllUserByLike(String key);

总结

#{} 和${} 的区别:

1. $符号存在SQL注入问题;

2. $是即时SQL(参数直接拼接),#是预编译SQL(参数通过占位的方式);

3. 像排序功能,like查询等只能使用$,但是得解决SQL注入的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值