Mybatis中# 和 $ 的使用详解

简介: Mybatis中# 和 $ 的使用详解

【1】#和$使用对比

① #和$详解

在JDBC中,主要使用的是两种语句:

一种是支持参数化和预编译的PrepareStatement,能够支持原生的Sql,也支持设置占位符的方式,参数化输入的参数,防止Sql注入

一种是支持原生Sql的Statement,有Sql注入的风险。

#{key}:获取参数的值,预编译到SQL中。安全。

${key}:获取参数的值,拼接到SQL中。有SQL注入问题。ORDER BY ${name}

在使用Mybatis进行开发过程中,隐藏了底层具体使用哪一种语句的细节,我们通过使用#和$告诉Mybatis,我们实际上进行的是怎么样的操作,需要对语句进行参数化还是说直接保持原生状态就好。


在Mybatis的mapper.xml中经常看到这两个符号,其中 # 频率最高。


如下:

<insert id="insertUSer" parameterType="User" >
  insert into c_user (name,age)
  values(#{name},#{age})
</insert>

或者如下:

//...
<if test="SORTNAME !=null and SORTNAME !='' ">
  order by ${SORTNAME}
  <if test="SORTORDER !=null and SORTORDER !='' ">
    ${SORTORDER} 
  </if>
</if>
limit ${(page-1)*pagesize},${pagesize}

下面说明一下二者的用法与区别

默认情况下,使用 #{ } 格式的语法会导致 MyBatis 创建预处理语句属性并以它为背景设置安全的值(比如 )。

这样做很安全,很迅速,也是首选的做法 !

但有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像 ORDER BY , 你可以这样来使用:

ORDER BY ${columnName}

这里 MyBatis 不会修改或转义字符串。如果sql语句中使用动态的表或者列,请使用$符号

接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的,这会导致潜在的SQL注入攻击。因此你不应该允许用户输入这些字段,或者通常自行转义并检查。

② 使用#或者说PrepareStatement如何防止SQL攻击?

比如说根据学生姓名查学生信息,会传入一个name的参数,假设学生姓名是方方,那么Sql就是:

SELECT id,name,age FROM student WHERE name = '方方';

在没有做防Sql注入的时候,我们的Sql语句可能是这么写的

<select id="fetchStudentByName" parameterType="String" resultType="entity.StudentEntity"> 
SELECT id,name,age FROM student WHERE name = '${value}' 
</select>

但如果我们对传入的姓名参数做一些更改,比如改成anything' OR 'x'='x,那么拼接而成的Sql就变成了:

SELECT id,name,age FROM student WHERE name = 'anything' OR 'x'='x'

库里面所有的学生信息都被拉了出来,是不是很可怕。原因就是传入的anything’ OR ‘x’='x和原有的单引号,正好组成了 ‘anything’ OR ‘x’='x’,而OR后面恒等于1,所以等于对这个库执行了查所有的操作。

防范Sql注入的话,就是要把整个anything’ OR ‘x’='x中的单引号作为参数的一部分,而不是和Sql中的单引号进行拼接

使用了#即可在Mybatis中对参数进行转义:

<select id="fetchStudentByName" parameterType="String" resultType="entity.StudentEntity"> 
SELECT id,name,age FROM student WHERE name = #{name} 
</select>

我们看一下发送到数据库端的Sql语句长什么样子。

SELECT id,name,age FROM student WHERE name = 'anything\' OR \'x\'=\'x'

从上述代码中我们可以看到参数中的所有单引号统统被转义了,这都是JDBC中PrepareStatement的功劳。如果在数据库服务端开启了预编译,则是服务端来做了这件事情。

【2】使用动态表或列

有时候会不可避免使用动态表或者列进行业务处理。下面学习几种动态表/列的使用方式(其本质核心是使用$获取表名或列名):

① 使用预编译

即,默认值。

<select id="hisNumber" parameterType="hashmap" resultType="hashmap"  >
     select number from ${oldTableName} 
<!--这里使用"$"!!!-->
where name=#{name} and date = #{date}
<!--这里使用"#"-->
<select>

预编译,即首先会生成select number from ? where name=? and date=? 这样使用”?”作为占位符的语句,然后进行参数解析。

② 使用非预编译

<select id="hisNumber" parameterType="hashmap" resultType="hashmap" statementType="STATEMENT" >
     select number from ${oldTableName} 
<!--这里使用"$"!!!-->
where name='${name,jdbcType=VARCHAR}' and date = '${date,jdbcType=TIMESTAMP}'
<select>

注意后面name和date的取值,使用了'${name}' 格式,这样会对参数进行数据类型转换,有助于mysql查询时提升性能。

仍旧使用非预编译

<select id="hisNumber" parameterType="hashmap" resultType="hashmap" statementType="STATEMENT" >
     select number from ${oldTableName} 
<!--这里使用"$"!!!-->
where name=${name} and date = ${date}
<select>

注意后面name和date的取值,使用了${name} 格式,将会直接取参数值,不进行数据类型转换。当参数为数值类型且格式如“00124”时,将会出现数据错读(会将0124、124等都读出来)。


目录
相关文章
|
SQL 存储 监控
深入可观测底层:OpenTelemetry 链路传递核心原理
本文会系统讲解链路传递一些基本概念,同时结合案例讲解链路传递的过程。
3643 1
深入可观测底层:OpenTelemetry 链路传递核心原理
SpringBoot——SpringBoot中使用过滤器Filter的两种方式
SpringBoot——SpringBoot中使用过滤器Filter的两种方式
2871 0
SpringBoot——SpringBoot中使用过滤器Filter的两种方式
|
JSON 数据格式
【异常】com.alibaba.fastjson.JSONException: unclosed string : U
【异常】com.alibaba.fastjson.JSONException: unclosed string : U
3197 0
|
20天前
|
安全 Java API
Spring Boot 4 升级实战:从3.x到4.0的分步升级保姆级指南
Spring Boot 4.0于2025年11月发布,基于Spring Framework 7.0,实现模块化(47个轻量自动配置)、JSpecify空安全校验、原生API版本控制等重大升级。镜像减19%、启动快33%,迁移平滑,3.5.x支持至2026年11月。(239字)
|
存储 Java
Bitmap位图(Java实现)
本文介绍了使用Java实现一个简单的Bitmap,通过自定义byte数组存储数据,提供put和exist方法分别用于插入数据和查询数据是否存在。Bitmap利用位操作高效地管理大量布尔值,适用于空间优化的场景。代码中详细解释了位图的核心原理、方法实现及边界检查。后续计划探讨位图在海量数据去重中的应用及JDK BitSet源码分析。
888 7
|
12月前
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
XML Java API
List与String相互转化方法汇总
本文汇总了List与String相互转化的多种方法,包括使用`String.join()`、`StringBuilder`、Java 8的Stream API、Apache Commons Lang3的`StringUtils.join()`以及Guava的`Joiner.on()`方法实现List转String;同时介绍了使用`split()`方法、正则表达式、Apache Commons Lang3的`StringUtils.split()`及Guava的`Splitter.on()`方法实现String转List。
2546 1
List与String相互转化方法汇总
|
SQL XML Java
MyBatis配置中的#「」和$「」有什么区别?
Mybatis提供到的#号和$号,都是实现动态SQL的一种方式,通过这两种方式把参数传递到XML之后,在执行操作之前,Mybatis会对这两种占位符进行动态解析。
414 0
|
SQL Java 数据库连接
【潜意识Java】MyBatis中的动态SQL灵活、高效的数据库查询以及深度总结
本文详细介绍了MyBatis中的动态SQL功能,涵盖其背景、应用场景及实现方式。
1668 6
|
SQL 数据库
在mybatis-plus怎么使用自定义的sql语句
在mybatis-plus怎么使用自定义的sql语句
1334 0

热门文章

最新文章