Mybatis - #{} 和 ${} 的区别是什么?
一则或许对你有用的小广告
最近,小哈正在带小伙伴们做前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.2 + Vite 4
,手把手,前端 + 后端,全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已进入第七章 《文章分类模块开发》中,截止到目前,已更新 105150 字,69 篇内容,讲解图:521 张,还在持续爆肝中,后续还会上新更多项目,已有 200+ 小伙伴加入,欢迎点击围观。
简单介绍一下
首先,两者都是占位符,它们区别如下:
#{}
是参数占位符,可以预编译处理,能够防止 SQL 注入,提高系统安全性;${}
是变量占位符,直接用于字符串替换,一般在使用 Sharding-JDBC 中间件进行分库分表时,动态指定表名时可能会用到。
深入解释
关于 #{}
#{}
是 SQL 的参数占位符,Mybatis 会将 SQL 中的 #{}
替换为 ?
号,在 SQL 执行前会使用 PreparedStatement 的参数设置方法,按序给 SQL 的 ?
号占位符设置参数值,如 ps.setInt(0, parameterValue)
。
所以,#{}
是预编译处理,它可以有效防止 SQL 注入,提高系统安全性,推荐使用。
关于 ${}
${}
常见于相关配置文件中,常被用于 XML 标签属性值以及 SQL 内部,用来做字符串替换。例如将 ${driver}
会被静态替换为 com.mysql.jdbc.Driver
:
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${driver}"/>
<!-- 基本属性 url、user、password -->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="1"/>
<property name="minIdle" value="1"/>
<property name="maxActive" value="20"/>
另外,${}
也可以对传递进来的参数原样拼接在 SQL 中。代码如下:
<select id="findUser" parameterType="Integer" resultType="User">
SELECT * FROM t_user
WHERE user_id = ${userId}
</select>
注意:生产环境下,不推荐这么做。会带来 SQL 注入的风险。
什么时候会用到 ${} 呢?应用场景?
在使用类似 Sharding-JDBC 等分库分表中间件时会用到,比如说,有张用户表 t_user
, 考虑到未来用户数据的增长,以及查询的效率(使每张表数据量保持在 500w 之内),设计时根据 user_id 分了 8 张表, 如下所示:
这时,在代码逻辑层就需要根据 user_id 动态指定表名,也就是说,对表名路由时,需要对 user_id % 8
处理后,才能得到记录具体落到哪张表:
String tableName = "t_user_" + (userId % 8);
算出表名后,再动态设置表名:
<select id="findUser" resultType="User">
SELECT * FROM ${tableName}
</select>
补充
#{}
和 ${}
的取值方式都异常方便。例如:#{item.name}
,框架在进行解析时,根据规则,使用反射可以很方便地从参数对象中,获取 item
对象的 name
属性值,相当于 param.getItem().getName()
。