Mybatis中 #{}和${}的区别
2019.11.01 杭州的一个面试,有问道这个问题:
讲一下Mybatis中 #{}和${}的区别?
部分内容涉及到 MySQL的预编译
情况一:只用 #{}
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=#{userName} and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select * from USER where userName=? and userPassword =?; ==> Parameters: mww(String), 123(String) <== Total: 1
结论:
#{}会在预编译期,生成两个 ?,作为占位符。
情况二:一个用 ${} 一个用 #{}
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=${userName} and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select * from USER where userName=mww and userPassword =?; ==> Parameters: 123(String)
结论:很显然 ${} 是直接拼成字符串的 ,#{} 是生成 ?占位符的。
而且 因为 userName:mww 是字符串,所以 这种写法显然也是错误的。
会报出如下错误:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column 'mww' in 'where clause'
所以正确的写法是这样的:为字符串字段加上单引号 ' '
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName='${userName}' and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select * from USER where userName='mww' and userPassword =?; ==> Parameters: 123(String) <== Total: 1
结论:显然这种写法是正确的,从这里可以看出,预编译期 ${} 是直接把参数拼结到SQL中,
运行时,就只传入了一个 #{} 修饰的参数。
${}的这种写法还有一个安全隐患,那就是 SQL注入。
情况三: ${} SQL注入:
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName='${userName}' and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select * from USER where userName='' OR 1=1 OR '' and userPassword =?; ==> Parameters: 65787682342367(String) <== Total: 2
结论:只要我们在 ${} 输入 ' OR 1=1 OR ' 无论后面的密码输入什么都可以,查询到数据,这种情况就是SQL注入。
情况四:#{} 防止SQL注入
<select id="getUserByNameAndPsw" parameterType="map" resultType="com.hotel3.model.User"> select * from USER where userName=#{userName} and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select * from USER where userName=? and userPassword =?; ==> Parameters: ' OR 1=1 OR '(String), 123(String) <== Total: 0
结论:上面预编译SQL的参数已经由占位符 { ?} 代替,所以传入的 ' OR 1=1 OR ' 只会作为 userName字段的值,
而不会拼入执行的SQL。这样就达到了防止SQL注入的目的。
在这种用法中, #{} 显然比 ${} 用法更好。
那 ${} 为什么经常在 Mybatis 使用那?
${}正确用法(个人见解):
1、同时传入一个字段名和字段值:
User u=userService.getUserByNameAndPsw("userName,userType,userPassword",userName,userPassword);
SQL: select ${arg0} from USER
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select ${arg0} from USER where userName=#{userName} and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?; ==> Parameters: mww(String), 123(String) <== Total: 1
结论:
生成了我们想要SQL语句 :select userName,userType,userPassword from USER。。。。
2、传入两个字段名和字段值:
User u=userService.getUserByNameAndPsw("userName,userType,userPassword",userName,userName,userPassword);
SQL: select ${arg0} from USER where ${arg1}=#{userName}
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select ${arg0} from USER where ${arg1}=#{userName} and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?; ==> Parameters: mww(String), 123(String) <== Total: 1
结论:
按照传参的顺序匹配 SQL 中的 ${arg0},${arg1}。。。
生成我们想要的代码,但这个方式会使Mybatis 的 Mapper 文件可读性变差,
如果不看其他的代码,很难辨别 ${arg0} ,${arg1} 代表的含义。
3、使用Map传值,提高 Mapper 文件的可读性
Map map =new HashMap(); map.put("selectValues","userName,userType,userPassword"); map.put("userNamefieId","userName"); map.put("userName",userName); map.put("userPassword",userPassword); User u=userService.getUserByNameAndPsw(map);
Mapper 文件的 xml
<select id="getUserByNameAndPsw" parameterType="map" resultType="com.hotel3.model.User"> select ${selectValues} from USER where ${userNamefieId}=#{userName} and userPassword =#{userPassword}; </select>
结果:
==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?; ==> Parameters: mww(String), 123(String) <== Total: 1
结论:
结果和arg0、arg1的传值方式相同,但 Mapper 文件的 xml 中的SQL语句可以
通过对 map 中 key 值命名提高可读性。
注:以上SQL,均为预编期生成的SQL。
注2:${} 每次传值不同 SQL 语句不同,可以灵活生成 SQL,
但每次都需要进行预编译,对效率会有影响,至于要不要使用 ${}还要具体情况具体分析。
肯定还有 ${} 其他的用法,欢迎留言评论,共同探讨,待续。。。。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律