经典面试题:MyBatis中的#和$有什么区别?
一. 什么是MyBatis
MyBatis是一款优秀的持久层框架,特别是在国内(国外据说还是 Hibernate 的天下)非常的流行,我们常说的SSM组合中的M指的就是MyBatis。
MyBatis支持定制化SQL、存储过程以及高级映射等多种特性,单纯从代码上来看,MyBatis避免了几乎所有的JDBC代码和手动设置参数以及手动处理结果集。而且MyBatis的使用也非常方便,可以通过简单的XML或注解来配置和映射数据信息。
二. 什么是动态 SQL
MyBatis的强大特性之一便是它的动态SQL,凡是使用过JDBC或其他类似框架,如DBUtils、JdbcTemplate等数据库操作工具的同学,都能体会到根据不同条件拼接SQL语句是有多么的痛苦!我们不仅要拼接SQL,还要拼接参数,特别费事,而且拼接的时候还要确保不能忘了必要的空格,还要注意省略掉列名列表最后的逗号.......操作过这样代码的小伙伴应该都明白这里的弊端。然而利用MyBatis的动态SQL特性,就可以彻底摆脱这种痛苦。
MyBatis 支持使用 ${} 和 #{}两种符号来进行动态SQL的拼接,可能有些人没有留意到,认为 ${} 和 #{} 的作用是差不多的,其实这两者的功能虽然相似,但区别是比较大的!而且,关于这两者的区别,也是Mybatis面试时的一个高频问题,今天就带各位一起来看看两者的区别到底有哪些。
三. `#` 和 `$`
基本用法
我们先来了解一下 `#`和 `$` 的基本用法。这两个都可以进行动态 SQL 的拼接,但用法上略微有一些差异。
我们先来看 `#` 的用法:
select * from t_user where name = #{param}
如果想执行相同的 SQL,用 $ 写法如下:
select * from t_user where name = '${param}'
眼尖的小伙伴可能已经发现,使用 `$` 比使用 `#` 多了一对单引号,为什么要这样呢?这里就涉及到了两者的第一个区别了:
# 会进行预编译,而且会进行类型匹配,参数是在编译之后填充进去的,所以不需要加上单引号;
$ 不会进行数据类型的匹配,只是单纯地进行字符串的拼接,所以要自己手动加上单引号,否则最终拼接出来的SQL语句就不对了。
用过JDBC的小伙伴可能会知道,这就跟JDBC中的PrepareStatement和Statement的区别是一样的,使用 `#` 就相当于使用 PrepareStatement,而使用 `$` 就相当于使用 Statement。
好啦,这就是两者的第一个区别!那么还有其他的区别吗?在讲第二个区别之前,百泽老师先给小伙伴们介绍一下什么是SQL注入。
什么是SQL注入
在我们的日常开发中,对于网页上的操作,归根结底无外乎就是增删改查,所以有很多同行都自嘲自己是CURD工程师。
在CURD的过程中,以SQL查询为例,假设我们想根据用户名和密码查询某一个用户是否存在,现在要让用户在前端根据用户名和密码进行查询。
现在假设我们后台的SQL语句如下:
select * from user where username='${username}' and password='${password}'
前端网页有两个输入框,一个是用户名输入框,另一个是密码输入框。假设用户老老实实地输入用户名为zhangsan,密码为123,那么最终生成的SQL语句如下:
select * from user where username='zhangsan' and password='123'
以上过程似乎很完美!
但是!!!要是有人不老实呢?
假设用户输入的用户名是 `zhangsan' or 1=1 #`,密码则随意给了个值 111,那么最终生成的 SQL语句可能就是下面这样了:
select * from user where username='zhangsan' or 1=1 #' and password='123'
大家知道,# 在 SQL语句中的含义是注释,#后面的SQL内容是不执行的。所以这个SQL无论怎么执行,最终都会返回true。这就是所谓的SQL注入了。
如果我们想要防止SQL注入,其实有很多解决办法,其中最直接的一种,就是不要使用$符号来拼接 SQL语句!
`#`和`$`的区别
看了上面的例子,现在大家就明白了,相比于 $ ,#有一个重要的作用,那就是可以防止SQL注入!
变量传递时,必须使用#。使用 #{} 就等于使用了JDBC 中 PrepareStatement 这种占位符的形式,既可以提高SQL的执行效率,又可以防止SQL注入等问题。
$ 只是一种简单的字符串拼接,要特别小心 SQL注入的问题。如果我们在项目中使用了$,那么可以自定义过滤器或者通过Druid等工具,来防止SQL注入。
如果在一个场景中,既能使用 # 又能使用 $,那么建议首选 #。
四. 什么情况下只能用$
另外有一个特殊场景只能用$!那就是将数据库对象作为参数传递,其中最常见的就是 group by了。假设我们现在想要对某个表进行排序查询,但参与排序的字段并不确定,而是要通过前端参数传递过来,那么此时就必须使用 $ 了!因为 # 预处理之后,会把数据库中的字段名识别为字符串,进而会出错,如下所示:
select count(*) from user group by ${param}
当然,上面这只是其中的一个例子,实际情况是,只要遇到将数据库的字段名作为参数传递的情况,都得用 $!
相关推荐HOT
更多>>如何添加Java环境变量?
要添加Java环境变量,可以按照以下步骤:并安装Java开发工具包(JDK)、找到Java安装路径、设置JAVA_HOME环境变量、添加Java可执行文件路径到PATH...详情>>
2023-05-04 11:00:56从零开始学Java之String字符串的编码
对很多小白来说,可能不明白什么是字符编码,也不知道为什么要有字符编码,所以先来给大家简要地介绍一下字符编码。详情>>
2023-05-04 10:21:02新手速来!几步带你掌握MyBatis Plus
Mybatis-Plus(简称MP)是一款Mybatis的增强工具,它是在Mybatis的基础上实现的简化开发工具。Mybatis-Plus给我们提供了开箱即用的CRUD操作、自动...详情>>
2023-04-28 10:57:09学习java需要什么基础?基础知识有哪些?
网络编程:了解基本的网络编程概念和协议,熟悉 Java 网络编程 API。建议在学习 Java 之前,先学习一些基础的编程语言,如 C 或 Python 等,这...详情>>
2023-04-28 10:41:14