当前位置: 首页 > news >正文

MyBatis中的赋值语句:#{}和${}的区别差异(常见面试题)

我们开始先总结他们的差异,后面再使用代码展示差异

1.0.#{}和${}的差异

(1)${}可能存在sql注入的安全问题

(2)${}是即时sql(参数直接拼接),不能进行缓存;#{}是预编译sql(参数通过替换占位符的方式),可以缓存

(3)${}拼接字符串参数时不带引号,而#{}拼接参数会带上引号

(4)在不能自带引号的场景下,只能使用${};比如实现排序功能等

1.1.差异的原因

下面我们通过一段代码,就可以知道它们产生差异的原因了。

(1)参数是否拼接

分别使用不同符号的进行赋值

我们可以看到,当使用#{}的时候,参数位置使用的是一个占位符,而${}则是直接把参数拼接在上面了。这是它们两处不一样的地方。

(2)有无引号

下面我们将参数的类型从Integer换成String

测试结果:

发现直接使用$传参会报错,原因就是它没有自动加上双引号或者单引号;如果我们自己加上:

运行结果也就没有报错了 

由此可见,${}就是可以自己是否带引号的,这点就是让它成为有sql注入的主要原因

(3)sql注入

在上面可以知道,${}可以自主选择带引号,因此,就可以进行sql拼接,也就存在被sql注入的风险。

比如下面的sql语句:

SELECT * from userinfo where username = ' ' or 1= '1'
//参数:' or 1='1

运行结果:

很明显sql执行成了,也就是说,确实是真真实实存在sql注入的风险。(但是一般都可以通过java代码来预防注入风险)

(4)即时sql和预编译sql

sql的执行流程:sql语法检验和解析、sql优化、sql执行

因为#{}的参数使用占位符,每次只需要替换占位符就可以,因此第一、二步可以缓存下来,每次只需要执行第三步即可,效率也就更快;因此称为:预编译sql。

而${}每次都是需要拼接参数,所以不能缓存,因此称为:即时sql

1.2.${}的作用

上面说的全是${}的缺点,那它还有用武之地吗?其实没有被淘汰,也就是还有作用的,作用场景也就是参数不能有引号的情况。

(1)对某个字段排序

对数据库中的数据进行排序,相信大家不陌生吧,我们还是先复习一下排序的sql语句

默认排升序:select * from 表名  order by 列名/表达式  

排降序:select * from 表名  order by 列名/表达式 desc

如果我们需要排降序的话,就需要传参,也就是将desc作为参数,但是在sql语句中,desc是没有引号的,但是#{}对字符串传参时,会自动加上引号,进而会导致sql错误,所以只能使用${}

  • 使用#{}时

结果已经很明显了。

  • 使用${}

但是这样也会存在sql注入的安全问题,所以就需要将参数设置成枚举类型这样的可选类型。并且如果表名和字段名作为参数时也必须使用${},原因就是它们不能有引号

(2)模糊查询

模糊查询虽然不是使用${}和#{},但是也需要介绍一下原因。

复习一下模糊查询:

select * from userinfo where username like ' %min% '

%min%就是一个模糊的概念,两边是需要加上引号的。但是%min%是一个字符串,min就是我们需要的参数,不能有任何字符串。

  • #{}

报错

  • 使用${}

因为是${},所以依旧存在sql注入的风险,所以模糊查询不会使用${},而是使用内置函数

  • 使用内置函数
   @Select("select * from userinfo where username like concat('%',#{key},'%') ")List<UserInfo> queryUserInfoBylike(String key);


以上就是本文的全部内容。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Python机器学习】决策树的构造——划分数据集
  • 2024最新Uniapp的H5网页版添加谷歌授权验证
  • linux进程——解析命令行参数——环境变量详解
  • Spring Security面试三道题
  • 查找算法-二分查找(折半查找)
  • 《Unity3D高级编程 主程手记》第四章 用户界面(二) UGUI 系统的原理及其组件使用
  • 简化mybatis @Select IN条件的编写
  • Android monkey命令和monkey脚本详解
  • vim gcc
  • 【MQTT协议与IoT通信】MQTT协议的使用和管理
  • 追问试面试系列:开篇
  • HarmonyOS Next原生应用开发-从TS到ArkTS的适配规则(九)
  • 【React】useState:状态管理的基石
  • 【BUG】已解决:ERROR: No matching distribution found for PIL
  • 《GPT-4o mini:开启开发与创新的新纪元》
  • [NodeJS] 关于Buffer
  • 【mysql】环境安装、服务启动、密码设置
  • ➹使用webpack配置多页面应用(MPA)
  • HTTP中的ETag在移动客户端的应用
  • iOS 颜色设置看我就够了
  • Laravel5.4 Queues队列学习
  • Map集合、散列表、红黑树介绍
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • React的组件模式
  • Theano - 导数
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 高程读书笔记 第六章 面向对象程序设计
  • 给新手的新浪微博 SDK 集成教程【一】
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 前端面试之闭包
  • 提醒我喝水chrome插件开发指南
  • 消息队列系列二(IOT中消息队列的应用)
  • 用 Swift 编写面向协议的视图
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • Prometheus VS InfluxDB
  • 扩展资源服务器解决oauth2 性能瓶颈
  • ​configparser --- 配置文件解析器​
  • ### RabbitMQ五种工作模式:
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #pragma once与条件编译
  • #快捷键# 大学四年我常用的软件快捷键大全,教你成为电脑高手!!
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (回溯) LeetCode 131. 分割回文串
  • (六)激光线扫描-三维重建
  • (三)Honghu Cloud云架构一定时调度平台
  • (学习总结16)C++模版2
  • (一)utf8mb4_general_ci 和 utf8mb4_unicode_ci 适用排序和比较规则场景
  • (原創) 未来三学期想要修的课 (日記)
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转)Scala的“=”符号简介
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET Framework Client Profile - a Subset of the .NET Framework Redistribution
  • .NET 解决重复提交问题