MyBatis中传参时为什么要用#{},这个问题和MyBatis如何防止SQL注入类似。不过在解释这个问题之前,先解释一下什么是SQL注入,还有些称作注入攻击这个问题。

  SQL注入就是SQL 对传入参数的拼接。sql语句是 String类型的,如果用  +  来拼接,表示的是直接操作这个String 类型的字符串,这是改变了sql的具体内容了,如果用#{id},表示的是操作字改变里面字段的参数值。

例如:

  • 用+拼接的: "select * from user where code="+code+ " and password="+password;

    那么code = “1233 or code=456”  password="2123":

  结果:  select * from user where code='123' or  code='456' and password=‘2123’那么这个sql的规则就乱了。

  • 用#操作的 select * from user where code=#{code} and password=#{password};

那么code = “1233 or code=456”  password="2123":

  结果:  select * from user where code=' 1233 or code=456 ' and password='2123'那么这个sql的规则还是老样子。

  综上所述就是会发生拼接错误!其实应该是参数传递出现的问题,#{}传递参数时,会在传递的参数上加上引号,在传递属性比如   password=? 时,可以很方便的使用#{password}。#{}传递的参数实际上是通过占位符(类似于JDBC中的?,在JDBC中会利用?去代替参数先进行编译,然后代入参数执行,这样就可以避免注入,因为注入不安全因素是发生在编译期,用占位符后就避免了这个问题)去传入到已经预编译好的SQL中去的,所以此时的SQL已经完成编译,只需要传参数就完成执行了。如:

1 <select id =“ getBlogById ”resultType =“ Blog ”parameterType =“ int ”>
2         SELECT id,title,author,content
3 FROM blog
4 WHERE id =#{id}
5 </select>

  在这里的id传参就是使用了#{},这部分打印后会看到的SQL语句是:

1 SELECT id,title,author,content FROM blog WHERE id =?

  就是不管输入什么参数打印出的SQL都是这样的。这是因为MyBatis的启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译,执行时,直接使用编译好的SQL ,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。

  具体可以看底层实现:其原理就是采用了JDBC的PreparedStatement。就会将sql语句:“select id,no from user where id =?” 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该SQL语句的语法结构了,因为语法分析已经完成了,而语法分析主要是分析sql命令,比如select,from,where,and,or,order by等等。所以即使你后面输入了这些sql命令,也不会被当成sql命令来执行了,因为这些SQL命令的执行,必须先得通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为SQL命令来执行的,只会被当做字符串字面值参数。所以的sql语句预编译可以防御SQL注入。而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。

  同样的,想要避免SQL注入,只能使用上述的#{}结构,在MyBatis中,还有一种结构是${},使用该结构就不会避免注入。因为${}不会添加引号,传递的是什么就会直接放到SQL中去执行。

  简单滴说:# {}是经过预编译的,是安全的 ;$ {}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入。

参考:

  1. https://www.cnblogs.com/jy107600/p/7097983.html
  2. https://bbs.csdn.net/topics/391069848
  3. https://blog.csdn.net/weixin_40773255/article/details/80426307
  4. https://blog.csdn.net/weixin_39986856/article/details/83651847

MyBatis中传参时为什么要用#{}的更多相关文章

  1. Mybatis中传参包There is no getter for property named 'XXX' in 'class java.lang.String'

    Mybatis中传参包There is no getter for property named 'XXX' in 'class java.lang.String' 一.发现问题 <select ...

  2. mybatis中传集合时 报异常 invalid comparison: java.util.Arrays$ArrayList and java.lang.String

    犯了一个低级的错误,在传集合类型的参数时,把他当成字符串处理了,导致报类型转换的错误 把  and nsrsbh!=' ' 删掉就行了

  3. C++ 传参时传内置类型时用传值(pass by value)方式效率较高

    来源:唐磊的个人博客<C++ 传参时传内置类型时用传值(pass by value)方式效率较高> 在<Effective C++>里提到对内置(C-like)类型在函数传参时 ...

  4. URL传参时中文参数乱码的解决方法

    URL传参时,中文参数乱码的解决: 今天在工作中遇到了这样的一个问题,在页面之间跳转时,我将中文的参数放入到url中,使用location进行跳转传参,但是发现接收到的参数值是乱码.我的代码是这样写的 ...

  5. 浅谈对java中传参问题的理解

    之前用的c/c++比较多,在c/c++中对于传参类型,无外乎就是传值.传引用.传指针这几种.但在java中,由于没有指针类型,其传参的方式也发生了相应的变化.在网上找了找,按我之前的理解,java中传 ...

  6. Hutool工具里,POST方法,body中传参的几种调用方法

    接口说明: POSTMAN测试: JAVA代码: package com.provy.guard.api; import java.util.HashMap; import java.util.Map ...

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

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

  8. Mybatis中使用 #{} 和 ${} 向sql传参时的区别

    今天在工作时,使用MyBatis中向sql传递两个参数时,一直显示SQL语法错误,仔细检查,才发现传入的参数被加上了引号,导致传入的参数(要传入的参数是表名)附近出现语法错误. 错误写法: } a } ...

  9. 关于SQL Server 2017中使用json传参时解析遇到的多层解析问题

    开发新的系统,DB部分使用了SQL Server从2016版开始自带的Json解析方式. 用了快半年,在个人项目,以及公司部分项目上使用了,暂时还没遇到大的问题,和性能问题. 今天在解析Json的多级 ...

随机推荐

  1. 使用gui_upload的总结

    今天使用gui_upload函数将文本文件的内容读取到内表.出现了一个问题,总是程序宕掉,出项的提示是 Type conflict when calling a function module. 原来 ...

  2. Ice系列--傻瓜式服务开发IceBox

    前言 相信大家在没有接触过框架之前,都自己或多或少的开发过一些应用服务.每个应用服务除了业务配置还有很多环境配置,资源配置等,这些跟部署相关的配置.服务跟配置文件是一种静态绑定的方式,更新配置还需要重 ...

  3. Nginx架构赏析

    淘宝的某位大佬曾经做过测试,在一台24G内存的机器上,Nginx的最大并发连接数达到了200万.同学们听到这个结论后,是不是被Nginx的超高性能深深折服了,它内部的架构设计究竟是怎么样的呢?这篇文章 ...

  4. 权限管理3-整合Spring Security

    一.Spring Security介绍 1.框架介绍 Spring 是一个非常流行和成功的 Java 应用开发框架.Spring Security 基于 Spring 框架,提供了一套 Web 应用安 ...

  5. elasticsearch-head:5连接elasticsearch 6.x无法显示浏览数据的解决方案

    问题 在docker安装了elasticsearch-head:5和elasticsearch:6.3.2 打开界面连接es时发现数据无法展示. 解决方案 因docker使用的版本问题,可能名称略有变 ...

  6. Django的数据库读写分离

    Django的数据库读写分离 1.首先是配置数据库 在settings.py文件中增加多个数据库的配置: DATABASES = { 'default': { 'ENGINE': 'django.db ...

  7. 常用的hadoop和yarn的端口总结

    节点 默认端口 用途说明 HDFS DataNode 50010 datanode服务端口,用于数据传输 50075 http服务的端口 50475 https服务的端口 50020 ipc服务的端口 ...

  8. jmeter报Address already in use: connect

    jmeter报Address already in use: connect   用windows进行jmeter压测出现java.net.BindException: Address already ...

  9. Beating JSON performance with Protobuf https://auth0.com/blog/beating-json-performance-with-protobuf/

    Beating JSON performance with Protobuf https://auth0.com/blog/beating-json-performance-with-protobuf ...

  10. 406 UDP协议是面向非连接的协议 Keep-Alive

    HTTP The Definitive Guide   Table 3-1. Common HTTP methods   Method Description Message body?   GET ...