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等都读出来)。


目录
相关文章
|
XML Java 数据库
SpringBoot系列----注解详解
SpringBoot系列----注解详解
633 0
|
JSON 数据格式
【异常】com.alibaba.fastjson.JSONException: unclosed string : U
【异常】com.alibaba.fastjson.JSONException: unclosed string : U
3656 0
|
Java 开发者 Docker
五种常用的 Spring Boot 热部署方式
【2月更文挑战第5天】
5073 0
五种常用的 Spring Boot 热部署方式
|
SQL XML Java
MyBatis配置中的#「」和$「」有什么区别?
Mybatis提供到的#号和$号,都是实现动态SQL的一种方式,通过这两种方式把参数传递到XML之后,在执行操作之前,Mybatis会对这两种占位符进行动态解析。
624 0
|
关系型数据库 MySQL 数据库
Docker下Mysql8数据备份与恢复
通过以上步骤,您可以在Docker环境下高效地备份和恢复MySQL 8数据库。备份数据时,使用 `mysqldump`工具生成逻辑备份文件,并存储到指定目录;恢复数据时,使用 `mysql`工具从备份文件中读取数据并恢复到数据库。自动化脚本和定时任务的配置可以进一步简化备份和恢复的管理过程。
1405 41
|
SQL 数据库
在mybatis-plus怎么使用自定义的sql语句
在mybatis-plus怎么使用自定义的sql语句
1551 0
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
2525 24
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
|
JavaScript 小程序 Java
【工具】用nvm管理nodejs版本切换,真香!
本文详细介绍了如何使用 nvm(node.js 版本管理工具)解决在不同项目间频繁切换 Node.js 版本的问题。通过实例展示了 A、B 两个项目分别依赖 v14.19.1 和 v16.15.0 版本时的解决方案,并提供了 nvm 的下载、安装及常用命令等实用信息,帮助读者轻松管理 Node.js 版本。文章还包括了卸载已安装的 Node.js、配置环境变量等步骤,确保切换顺畅无阻。
2460 1
【工具】用nvm管理nodejs版本切换,真香!
|
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。
2841 1
List与String相互转化方法汇总