一、问题引入

我们先来看这段代码,我想从取值为${category}的表中查询全部信息。

@Mapper
public interface CategoryMapper {
@Select("select * from ${category}")
List<Commodity> queryAllByCategory(String category);
}

刚开始觉得没毛病,但是令人失望的是抛出了下面的异常。

org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'category' in 'class java.lang.String'

二、${ }与#{ }的区别

为了搞清楚背后的原因,首先我们来聊一聊${}与#{}的区别。

我们通过一个例子来简述两者的区别。

select * from commodity where id=#{id} AND title='${title}'

在动态 SQL 解析阶段, #{ } 和 ${ } 会有不同的表现:

#{ } 解析为一个JDBC 预编译语句的参数标记符占位符 ?。

上面的例子就被解析为

select * from commodity where id= ?

${ } 仅仅为一个纯碎的 string 替换,在mybatis的动态 SQL 解析阶段将会进行变量替换。比如:传入的参数是“牙膏”,就会将${title}替换成牙膏。

select * from commodity where id=? AND title='牙膏'

然后把解析好的语句再通过JDBC执行。

所以因为在${ } 在预编译之前已经被变量替换了,这会存在 sql 注入问题。比如:传入的studentName参数是“‘1' OR '1'='1’”

在mybatis中解析完成后变成了

select * from commodity where id=? AND title='1' OR '1'='1'

此时不管id为任何值,都可以查出全部内容。

因此能使用#{ }就尽量不要使用${ } ,因为${ }存在sql注入问题。

所以通俗来说${ }是直接用变量替换值的,而#{}会将变量转换为字符串再进行替换。

三、问题解决

通过理解上面的${ }的传值方式,可以知道${ } 在预编译之前已经被变量替换了,它是被直接注入的,所以会在String中去获取category的getter方法。

那么我们通过什么方法去解决这个问题呢?此时就要引入@Param。

@Mapper
public interface CategoryMapper {
@Select("select * from ${category}")
List<Commodity> queryAllByCategory(@Param("category") String category);
}

@Param的作用就是给参数命名,参数命名后就能根据名字得到参数值,正确的将参数传入sql语句中

其实可以理解为@Param将参数包装成一个Map(因为我们知道,如果想要sql语句中有多个参数的时候,可以通过将这些参数封装成一个Map,在通过Map的key来取出参数),即{"category", "xxxx"},然后在${category}中取到xxx。

然后就能查出结果啦。

当然,如果采用${value}这种写法,就没这个问题了,不过这个写法仅适用于参数只有一个的情况。

@Mapper
public interface CategoryMapper {
@Select("select * from ${value}")
List<Commodity> queryAllByCategory(String category);
}
 

Mybatis中由于${}直接注入引发的问题的更多相关文章

  1. mybatis中#{}与${}的差别(如何防止sql注入)

    默认情况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义. # ...

  2. 什么是SQL注入以及mybatis中#{}为什么能防止SQL注入而${}为什么不能防止SQL注入

    1.什么是SQL注入 答:SQL注入是通过把SQL命令插入到web表单提交或通过页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL指令. 注入攻击的本质是把用户输入的数据当做代码执行. 举例如: ...

  3. mybatis中的#和$的区别 以及 防止sql注入

    声明:这是转载的. mybatis中的#和$的区别 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sq ...

  4. mybatis中resultMap引发的吐血bug

    简单的讲: 问题背景:如果在写mybatis中的resultMap时,不下心将resultMapde id写成映射接口的名字,会发生什么? 结论:单元测试进度条卡住但不报错, Tomcat运行不报错, ...

  5. MyBatis中sql语句

    一.select <!-- 查询学生,根据id --> <select id="getStudent" parameterType="String&qu ...

  6. MyBatis怎么防止SQL注入

    SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者).[摘自] SQL injection - Wikipedia SQL ...

  7. Mybatis中SqlMapper配置的扩展与应用(3)

    隔了两周,首先回顾一下,在Mybatis中的SqlMapper配置文件中引入的几个扩展机制: 1.引入SQL配置函数,简化配置.屏蔽DB底层差异性 2.引入自定义命名空间,允许自定义语句级元素.脚本级 ...

  8. java持久层框架mybatis如何防止sql注入

    看到一篇很好的文章:http://www.jfox.info/ava-persistence-framework-mybatis-how-to-prevent-sql-injection sql注入大 ...

  9. Mybatis 中在传参时,${} 和#{} 的区别

    介绍 MyBatis中使用parameterType向SQL语句传参,parameterType后的类型可以是基本类型int,String,HashMap和java自定义类型. 在SQL中引用这些参数 ...

随机推荐

  1. 9. Lock wait timeout exceeded

    一. 现象 用户打开消息推送有概率报错,后续发现推送消息阅读数.点赞数无法正常更新,mysql报警有行锁, DBA抓到有锁表语句,kill该语句未正常恢复,elk日志有大量的java.sql.SQLE ...

  2. Node.js require 模块加载原理 All In One

    Node.js require 模块加载原理 All In One require 加载模块,搜索路径 "use strict"; /** * * @author xgqfrms ...

  3. CSS Shapes

    CSS Shapes shape-outside & shape-image-threshold <img class="element" src="ima ...

  4. PWA & TWA

    PWA & TWA https://www.bilibili.com/video/av68082979/ Service Worker workbox.js https://developer ...

  5. 什么是NGK算力挖矿?怎么使用USDN购买算力?

    NGK公链项目即将正式上线,NGK项目中重要生态NGK算力挖矿也将启动,正式开启DPOSS挖矿.因为具有低能耗,低搭建费用,高收益等特点,可以想象如果正式上线必将引起行业瞩目. NGK算力挖矿项目为N ...

  6. MySQL 导入外部数据

    手工为数据库录入数据: 1 -- 使用数据库 2 use test; 3 4 -- 创建fruits数据表 5 create table fruits( 6 f_id char(10) not nul ...

  7. JVM 字节码之 int 入栈指令

    本文转载自JVM 字节码之 int 入栈指令(iconst.bipush.sipush.ldc) 前言 本文介绍 int 入栈指令 iconst.bipush.sipubh.Idc. 当 int 取值 ...

  8. Typescript快速入门

    目录 什么是Typescript 为什么学习Typescript 快速搭建开发环境 1.安装node.js 2.使用node自带的npm安装Typescript编译器 3.配置vscode编辑环境 4 ...

  9. 3分钟学会如何上手supervisor看门狗

    软硬件环境 centos7.6.1810 64bit cat /etc/redhat-release #查看系统版本 supervisor 3.4.0 python 2.7.5 supervisor简 ...

  10. Navicat Premium的数据传输功能----将远程Mysql数据库复制到本地数据库的方法

    1.先连上本地.远程的数据库 2.在本地建一个和你要复制的远程数据库的名称一样的数据库 3.数据转移.工具-->数据传输-->填写源数据库和目标数据库-->下一步-->开始 注 ...