一、前言
在 MyBatis 中,#{} 和 ${} 都用于在 SQL 语句中绑定参数,但它们在具体实现和安全性方面有所差异。明白它们的区别对于编写高效且安全的 MyBatis 映射文件非常告急。这篇文章重要讲一下他们的利用和区别。
数据库数据信息:
二、 #{} 和${} 的利用方法和区别
2.1 #{}利用方法
在 MyBatis 中,#{} 用于绑定参数值,将其直接插入到 SQL 语句中。它不举行任何范例转换,实用于简朴范例的参数绑定,如字符串、整数等。
示例:
UserInfoMapper.xml 文件
- <select id="selectById" resultType="java.lang.Integer">
- select * from user_info where id=#{id}
- </select>
复制代码 UserInfoMapperXML接口
- List<UserInfo> selectById(Integer id);
复制代码 测试类
- @Test
- void selectById() {
- userInfoMapperXML.selectById(3).stream().forEach(x-> System.out.println(x));
- }
复制代码 运行结果:
作用剖析:
- #{id} 会将参数值直接更换到 SQL 语句中。
- 我们输⼊的参数并没有在背面拼接,id的值是利用 ? 举行占位. 这种SQL 我们称之为"预编译SQL"。
- 实用于不须要范例转换的简朴参数。
2.2 ${}利用方法
我们把上面的UserInfoMapper.xml 文件改一下,把#{}改成${}再观察打印日记。
UserInfoMapper.xml 文件:
- <select id="selectById" resultType="com.sliqvers.model.UserInfo">
- select * from user_info where id=${id}
- </select>
复制代码 观察运行结果日记:
可以看到, 这次的参数是直接拼接在SQL语句中了.
2.3#{} 和 ${} 的重要区别
再举一个例子来对比一下#{}和${}的区别。
#{}
UserInfoMapperXML接口
- List<UserInfo> selectByusername(String username);
复制代码 UserInfoMapper.xml 文件
- <select id="selectByusername" resultType="com.sliqvers.model.UserInfo">
- select * from user_info where username=#{username}
- </select>
复制代码 测试类
- @Test
- void selectByusername() {
- userInfoMapperXML.selectByusername("Bob").stream().forEach(x-> System.out.println(x));
- }
复制代码 运行结果:
我们再来看:
${}
我们把UserInfoMapper.xml 文件轻微改一下,其他的稳定。
- <select id="selectByusername" resultType="com.sliqvers.model.UserInfo">
- select * from user_info where username=${username}
- </select>
复制代码 我们再来看运行结果:
可以看到这个报错了,由于username是字符串范例,这个Bob少了两个引号。
我们把这个引号加上去:
- <select id="selectByusername" resultType="com.sliqvers.model.UserInfo">
- select * from user_info where username='${username}'
- </select>
复制代码 运行结果:
可以看到标题得以办理。
综上可以得出他们的区别.
#{} 利用的是预编译SQL, 通过 ? 占位的方式, 提前对SQL举行编译, 然后把参数添补到SQL语句中. #{} 会根据参数范例, 自动拼接引号 ‘’ .
${} 会直接举行字符更换, ⼀起对SQL举行编译. 假如参数为字符串, 须要加上引号 ‘’ .
特性#{}${}参数处置惩罚将参数值直接更换为字符串,不举行范例转换对参数值举行 JDBC 范例转换安全性旧版本大概存在 SQL 注入风险,新版本默认安全旧版本大概存在 SQL 注入风险,新版本默认安全利用场景实用于简朴范例的参数绑定实用于须要范例转换的参数绑定或动态 SQL 场景示例select * from users where username = #{username};select * from users where birthday = ${birthday};提出标题:
从上面的例子中, 可以得出结论 {}会有SQL注入的风险, 以是我们只管利用#{}完成查询。
既然云云, 是不是 ${} 就没有存在的须要性了呢?
固然不是⼀些场景,#{}不能完成, 比如 排序功能, 表名, 字段名作为参数时, 这些情况须要利用${}。
${}的利用场景:
筹划一个排序查询:
UserInfoMapperXML.java 文件:
- List<UserInfo> selectBysort(String sort);
复制代码 UserInfoMapper.xml文件
- <select id="selectBysort" resultType="com.sliqvers.model.UserInfo">
- select * from user_info order by age #{sort}
- </select>
复制代码 测试类:
- @Test
- void selectBysort() {
- userInfoMapperXML.selectBysort("asc").stream().forEach(x-> System.out.println(x));
- }
复制代码 运行结果:
可以看到报错了。由于此处 sort 参数为String范例, 但是SQL语句中, 排序规则是不须要加引号 ‘’ 的。
我们把#{sort} 换成${}然后看一下运行结果:
- <select id="selectBysort" resultType="com.sliqvers.model.UserInfo">
- select * from user_info order by age ${sort}
- </select>
复制代码
运行乐成了。
含糊查询固然${}可以完成, 但由于存在SQL注入的标题,以是通常利用mysql内置函数concat来完成。
筹划一个like查询:
UserInfoMapperXML.java 文件:
- List<UserInfo> selectBylike(String like);
复制代码 UserInfoMapper.xml文件
- <select id="selectBylike" resultType="com.sliqvers.model.UserInfo">
- select * from user_info where username like `${like}%`
- </select>
复制代码 测试类:
- @Test
- void selectBysort() {
- userInfoMapperXML.selectBysort("asc").stream().forEach(x-> System.out.println(x));
- }
复制代码 利用#{}会报错,利用${}可以运行但是不安全,存在SQL注入的标题,以是利用MySQL的内置函数concat()来举行。
UserInfoMapper.xml文件
- <select id="selectBylike" resultType="com.sliqvers.model.UserInfo">
- select * from user_info where username like concat('${like}%')
- </select>
复制代码 运行结果:
2.4利用发起
何时利用 #{}:
- 当须要绑定的参数是简朴范例,如字符串、整数。
- 当不须要对参数举行范例转换时。
何时利用 ${}
- 当须要对参数举行范例转换时,如日期、Blob 范例。
- 当须要动态天生 SQL 语句时,比方根据条件添加 WHERE 子句。
安全留意事项:
- 无论利用 #{} 照旧 ${},都要确保参数值已颠末恰当的过滤和验证,以防止 SQL 注入。
- 依赖 MyBatis 的预编译语句和范例转换功能,增强安全性。
三、总结
- #{} 和 ${} 都用于 MyBatis 的参数绑定,但 #{} 不涉及范例转换,而 ${} 会举行范例转换。
- #{} 实用于简朴范例的参数绑定,${} 实用于复杂范例或须要范例转换的场景。
- 在利用时,重点关注参数的安全性,确保参数已颠末恰当的验证和过滤。
通过公道选择 #{} 和 ${},可以编写出高效、安全的 MyBatis 映射文件,提升开发服从。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |