文章目录
- 关于 #{} 和 ${}
- 1. Integer类型的参数
- 2.String 类型的参数
- 3. #{} 和 ${} 的区别
- 3.1 性能问题:
- 3.2 安全问题
关于 #{} 和 ${}
MyBatis参数赋值有两种方式:#{} 和 ${}
1. Integer类型的参数
(1)${}
<update id="updateUser">
update userinfo set phone = ${phone} where id = ${id}
</update>
测试结果:
此时得到的参数ID是直接拼接在sql语句里面了,这种是"即时SQL"
(2)#{}
<update id="updateUser">
update userinfo set phone = ${phone} where id = #{id}
</update>
与前一种方式不一致的是,输入的参数不是在后面直接拼接,而是使用?
进行占位,这种是"预编译SQL"
2.String 类型的参数
(1) ${}
<select id="queryUserByUsername" resultMap="XMLBaseMap">
select * from userinfo where username = #{username}
</select>
测试:
@Test
void queryUserByUsername() {
System.out.println(userInfoMapper.queryUserByUsername("zhangsan"));
}
执行结果:
(2) #{}
<select id="queryUserByUsername" resultMap="XMLBaseMap">
select * from userinfo where username = ${username}
</select>
测试结果:
此时的SQL语句是:
可以看到,这次的参数也是直接拼接在sql语句后面了,但是字符串作为参数的时候,需要加上''
使用${}
不会自动拼接引号
因此需要我们自己添加引号
3. #{} 和 ${} 的区别
3.1 性能问题:
绝大部分情况下,一条SQL语句是会被重复执行的,或者每次执行的参数不一样(如where后面的条件参数)
如果每次都需要经过上面的语法解析,SQL优化,SQL编译等,则会影响效率
而预编译SQL,编译一次之后会将编译后的SQL语句缓存起来,后面再执行的时候,只是参数不同就不会再次编译,提高了效率
3.2 安全问题
使用预编译SQL可以防止SQL注入的问题
SQL注入:是通过输入操作的数据来修改事先定义好的sql语句,以达到执行代码对服务器进行攻击的方法
比如:' or 1 = '1
如果执行以下代码:
select * from userinfo where username = ‘${username}’
将' or 1 = '1
作为字符串参数传进去,就会得到下面的SQL语句:
那么如果此时是delete,后果不堪设想
那么是不是说由于SQL注入的问题,就必须无脑使用#{}
??
实际上,在一些需求里面,我们不得不使用${}
如排序功能
如果使用#{}
:
<select id="queryUserInfoByOrder" resultMap="XMLBaseMap">
select * from userinfo order by id #{order}
</select>
此时需要将order作为字符串传入
但是由于使用#{}
会自动加上引号,就会出现问题
<select id="queryUserInfoByOrder" resultMap="XMLBaseMap">
select * from userinfo order by id #{order}
</select>
执行结果:
这种情况就不得不使用${}
了,但是怎么解决SQL注入问题呢??
– 通过枚举,页面或者判断的方式控制参数,只能为desc 或 asc
like查询
like使用#{}
会报错
还是由于#{}
自动加引号导致的
此时还是不得不使用${}
还是得解决SQL注入的问题:
在sql里面,CONCAT
函数用于将两个或多个字符串值连接成一个字符串,可以用于解决这个问题
<select id="queryUserInfoLike" resultMap="XMLBaseMap">
select * from userinfo where username like concat('%',#{key},'%');
</select>