MyBatis中#和$的区别小结

 更新时间:2023年09月20日 09:40:10   作者:不会敲代码的程序猿!  
${} 和 #{} 都是 MyBatis 中用来替换参数的,它们都可以将用户传递过来的参数,替换到 MyBatis 最终生成的 SQL 中,但它们区别却是很大的,接下来我们一起来看

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 #和$的区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot Admin集成与自定义监控告警示例详解

    Spring Boot Admin集成与自定义监控告警示例详解

    SpringBootAdmin是一个管理和监控SpringBoot应用程序的工具,可通过集成和配置实现应用监控与告警功能,本文给大家介绍Spring Boot Admin集成与自定义监控告警示例详解,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • Java 容器类源码详解 Set

    Java 容器类源码详解 Set

    这篇文章主要介绍了Java 容器类源码详解 Set,Set 表示由无重复对象组成的集合,也是集合框架中重要的一种集合类型,直接扩展自 Collection 接口。,需要的朋友可以参考下
    2019-06-06
  • Java中的this和super实例浅析

    Java中的this和super实例浅析

    要说this和super就不得不说Java的封装和继承了。这篇文章主要介绍了Java中的this和super实例浅析,需要的朋友可以参考下
    2017-03-03
  • MyEclipse 2016 CI 4新增BootStrap模板

    MyEclipse 2016 CI 4新增BootStrap模板

    MyEclipse2016是一款全球使用最为广泛的企业级开发环境程序,这篇文章主要介绍了MyEclipse 2016 CI 4新增BootStrap模板的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • 一文搞懂java中的栈和括号匹配

    一文搞懂java中的栈和括号匹配

    栈在我们日常编码中遇到的非常多,很多人对栈的接触可能仅仅局限在 递归使用的栈 和 StackOverflowException,栈是一种后进先出的数据结构(可以想象生化金字塔的牢房和生化角斗场的狗洞)
    2023-11-11
  • IDEA编写JavaWeb出现乱码问题解决方案

    IDEA编写JavaWeb出现乱码问题解决方案

    这篇文章主要介绍了IDEA编写JavaWeb出现乱码问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • knife4j3.0.3整合gateway和注册中心的详细过程

    knife4j3.0.3整合gateway和注册中心的详细过程

    这篇文章主要介绍了knife4j3.0.3整合gateway和注册中心的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • 详解jeefast和Mybatis实现二级联动的问题

    详解jeefast和Mybatis实现二级联动的问题

    这篇文章主要介绍了详解jeefast和Mybatis实现二级联动的问题,本文通过图文实例相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java中的FilterOutputStream 简介_动力节点Java学院整理

    Java中的FilterOutputStream 简介_动力节点Java学院整理

    FilterOutputStream 的作用是用来“封装其它的输出流,并为它们提供额外的功能”。它主要包括BufferedOutputStream, DataOutputStream和PrintStream。接下来通过本文给大家简单介绍下FilterOutputStream知识,需要的朋友参考下吧
    2017-05-05
  • SpringBoot部署到Linux读取resources下的文件及遇到的坑

    SpringBoot部署到Linux读取resources下的文件及遇到的坑

    本文主要给大家介绍SpringBoot部署到Linux读取resources下的文件,在平时业务开发过程中,很多朋友在获取到文件内容乱码或者文件读取不到的问题,今天给大家分享小编遇到的坑及处理方案,感兴趣的朋友跟随小编一起看看吧
    2021-06-06

最新评论