MyBatis中#和$的区别小结
作者:不会敲代码的程序猿!
MyBatis中#和$的区别
说一下为什么要写这篇文章,最近面试有被问到,一下子想不出来有啥区别,想记录一下加深自己的理解,同时自己也经常用MyBatis-Plus忽略了XML文件的编写和使用,所以需要加深一下这块的知识
一、例子
1、#{}将传入的数据当作一个字符串,会对传入的数据加上一个双引号。
比如
select * from student where student_name = #{studentName}
如果传入的值为zhangxiangwei,那么经过Mybatis解析完成之后的语句是
select * from student where student_name="zhangxiangwei"
2.${}将传入的数据直接显示生成在sql中。
比如
select ${fieldName} from user where user_age = 22
此时,传入的参数作为要查询的字段,如果传入的值为user_name,则解析成的sql为:
select user_name from user where user_age = 22
二、区别
1.#{}方式能够很大程度上防止sql注入,${}无法防止sql注入。
2.${}方式一般用于传入数据库对象,例如列表和表名,#{}方式一般用来传递接口传输过来的具体数据。
3.由于#{}方式具有更高的安全行,所以能用#{}的地方尽量不要使用${}。
4.Mybatis排序时使用order by动态参数时需要注意,用${}而不是#{}。
5.#
符号(Pound Sign):
#
符号用于参数值的占位,会将参数值进行预编译,并在执行SQL语句时将参数值安全地传递给数据库,防止SQL注入攻击。适用于大多数情况,尤其是当参数值来自用户输入或不可信数据时,是更安全的选择。
参数值会被自动转义,不需要担心特殊字符的处理。
使用
#
符号会产生预编译的SQL语句,可以提高数据库的性能,因为数据库可以缓存相同的预编译语句。
<!-- 使用#符号进行参数占位 --> <select id="getUserById" parameterType="int" resultType="User"> SELECT * FROM users WHERE id = #{userId} </select>
6.$
符号(Dollar Sign):
$
符号用于简单的值替换,不进行预编译,直接将参数的值嵌入SQL语句中。适用于那些不需要参数值预编译,且参数值是确定且可信的情况,比如用于动态拼接SQL语句的情况。
使用
$
符号时,需要小心防止SQL注入攻击,需要手动处理参数值的安全性。不会产生预编译的SQL语句,可能会导致数据库性能较低,因为每次SQL语句都会重新解析和执行。
<!-- 使用$符号进行简单值替换 --> <select id="getUserByName" parameterType="string" resultType="User"> SELECT * FROM users WHERE username = '${username}' </select>
三、最后说一下 $ 动态 拼接SQL
下面是一个实例
<select id="getUsersWithDynamicSorting" parameterType="map" resultType="User"> SELECT * FROM users WHERE 1=1 <!-- 为了方便拼接,可以始终使用一个始终成立的条件 --> <!-- 根据参数动态拼接排序字段和排序顺序 --> <if test="sortField != null and sortOrder != null"> ORDER BY ${sortField} ${sortOrder} </if> </select>
补充:mybatis中的#{}和${}的区别
1. 取值范围不同
MyBatis既可以获取执行SQL时插入的请求参数,也可以从主配置文件加载的配置文件中获取配置参数。 #{}
只能获取请求参数的值,无法获取配置参数。 ${}
在MyBatis初始化时能获取配置参数,如果没有,执行时再获取请求参数。
2. 处理方式不同
#{}
如果SQL中只有 #{}
或者可以被配置参数替换的 ${}
,那么在初始化时 #{}
就被解析成了占位符 ?
。
如果SQL中有动态标签(例如 if
, where
),或者无法被配置参数替换的 ${}
,那么 #{}
在执行SQL时才会被替换成占位符 ?
。 #{}
的值是执行SQL时通过JDBC的Statement根据占位符进行设置。
${}
如果可以被配置参数替换,则在初始化时已被配置参数替换,否则在执行SQL时使用请求参数替换。
${}
的值使用参数值直接替换,不做任何特殊处理。
3. 安全性不同
#{}
能够很大程度防止SQL注入。 ${}
无法防止SQL注入。
所以,能用 #{}
的就别用 ${}
。 ${}
方式一般用于传入数据库对象,例如传入表名,排序字段等。
4. 测试验证
以下是自己做过的一些测试验证场景:
测试场景一: ${}
是否能够获取配置文件中的参数?如果能获取配置参数,那么是初始化时替换 ${}
还是执行时替换 ${}
。
测试结果一: ${}
在MyBatis初始化时,获取MyBatis主配置文件中加载的配置参数进行替换。
- SQL中只有
${}
,${}
被替换成配置参数,在所有${}
都被替换的情况下,生成的是静态SQL对象。 - SQL中只有
${}
和#{}
,${}
被替换成配置参数,在所有${}
都被替换的情况下,#{}
会被替换成?
,且生成静态SQL对象。 - SQL中存在
${}
和动态标签,${}
无论在动态标签内或者外,${}
都被替换成配置参数,生成动态SQL对象。 - SQL中存在
${}
、#{}
和动态标签,${}
被替换成配置参数,#{}
没有被替换成?
,生成动态SQL对象。
测试结论一:
在MyBatis初始化阶段,解析XML配置文件的过程中,会对 ${propertyName}
占位符做解析,如果能够在配置参数中获取到 key=propertyName
的值,那么就会使用配置参数值替换 ${propertyName}
,否则保留。所以在 xxxMapper.xml
中使用 ${propertyName}
获取参数时,需要考虑是获取配置文件中的值,还是获取SQL执行时传入的请求参数值。这可能会出现意想不到的结果。
测试场景二:
如果SQL中有动态标签或者 ${}
符号,且 ${}
不会被配置参数替换时,SQL中的 #{}
在初始化时替换成 ?
,还是在执行时被替换成 ?
。
测试结果二:
在MyBatis初始化过程中的测试结果:
- SQL中仅有
#{}
,#{}
被替换成?
。 - SQL中有
#{}
和${}
,#{}
没有被替换成?
。SQL中有#{}
和动态标签,#{}
无论在动态标签内还是外,都没有被替换成?
。 - SQL中有
#{}
和${}
、动态标签,#
{}没有被替换成?
。
在SQL执行过程中的测试结果:
- SQL中仅有
#{}
,#{}
在初始化阶段就已被替换成了?
。 - SQL中有
#{}
和${}
,#{}
被替换成?
,${}
被替换成参数值。 - SQL中有
#{}
和动态标签,#{}
被替换成?
,动态标签根据参数被解析。 - SQL中有
#{}
、${}
和动态标签,#{}
被替换成?
,${}
被替换成参数值,动态标签根据参数被解析。
到此这篇关于MyBatis中#和$的区别的文章就介绍到这了,更多相关MyBatis #和$的区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!