经典重现丨面试题之MyBatis中的#和$有什么区别?!

一. 什么是MyBatis

MyBatis是一款优秀的持久层框架,特别是在国内(国外据说还是 Hibernate 的天下)非常的流行,我们常说的SSM组合中的M指的就是MyBatis。

MyBatis支持定制化SQL、存储过程以及高级映射等多种特性,单纯从代码上来看,MyBatis避免了几乎所有的JDBC代码和手动设置参数以及手动处理结果集。而且MyBatis的使用也非常方便,可以通过简单的XML或注解来配置和映射数据信息。

对MyBatis不熟悉的小伙伴,可以关注公众号,回复【MyBatis】直接领取学习哦~

Java架构栈

专注分享Java技术干货,包括多线程、JVM、Spring Boot、Spring Cloud、Intellij IDEA、Dubbo、Zookeeper、Redis、架构设计、微服务、消息队列、Git、面试题、最新动态等。

252篇原创内容

公众号

二. 什么是动态 SQL

MyBatis的强大特性之一便是它的动态SQL,凡是使用过JDBC或其他类似框架,如DBUtils、JdbcTemplate等数据库操作工具的同学,都能体会到根据不同条件拼接SQL语句是有多么的痛苦!

我们不仅要拼接SQL,还要拼接参数,特别费事,而且拼接的时候还要确保不能忘了必要的空格,还要注意省略掉列名列表最后的逗号.......操作过这样代码的小伙伴应该都明白这里的弊端。然而利用MyBatis的动态SQL特性,就可以彻底摆脱这种痛苦。

MyBatis 支持使用 ${} 和 #{}两种符号来进行动态SQL的拼接,可能有些人没有留意到,认为 ${} 和 #{} 的作用是差不多的,其实这两者的功能虽然相似,但区别是比较大的!而且,关于这两者的区别,也是Mybatis面试时的一个高频问题,今天百泽老师就带各位一起来看看两者的区别到底有哪些。

三. `#` 和 `$`

1.基本用法

我们先来了解一下 `#`和 `$` 的基本用法。这两个都可以进行动态 SQL 的拼接,但用法上略微有一些差异。

我们先来看 `#` 的用法:

select * from t_user where name = #{param}

如果想执行相同的 SQL,用 $ 写法如下:

select * from t_user where name = '${param}'

眼尖的小伙伴可能已经发现,使用 `$` 比使用 `#` 多了一对单引号,为什么要这样呢?这里就涉及到了两者的第一个区别了:

  • # 会进行预编译,而且会进行类型匹配,参数是在编译之后填充进去的,所以不需要加上单引号;

  • $ 不会进行数据类型的匹配,只是单纯地进行字符串的拼接,所以要自己手动加上单引号,否则最终拼接出来的SQL语句就不对了。

用过JDBC的小伙伴可能会知道,这就跟JDBC中的Prepare Statement和Statement的区别是一样的,使用 `#` 就相当于使用 PrepareStatement,而使用 `$` 就相当于使用 Statement。

好啦,这就是两者的第一个区别!那么还有其他的区别吗?在讲第二个区别之前,百泽老师先给小伙伴们介绍一下什么是SQL注入。

2.什么是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语句!

3.`#`和`$`的区别

看了上面的例子,现在大家就明白了,相比于 $ ,#有一个重要的作用,那就是可以防止SQL注入

  • 变量传递时,必须使用#。使用 #{} 就等于使用了JDBC 中 PrepareStatement 这种占位符的形式,既可以提高SQL的执行效率,又可以防止SQL注入等问题。

  • $ 只是一种简单的字符串拼接,要特别小心 SQL注入的问题。如果我们在项目中使用了$,那么可以自定义过滤器或者通过Druid等工具,来防止SQL注入。

  • 如果在一个场景中,既能使用 # 又能使用 $,那么建议首选 #。

四. 什么情况下只能用$

另外有一个特殊场景只能用$那就是将数据库对象作为参数传递,其中最常见的就是 group by了我们现在想要对某个进行排序查询,但参与排序的字段不确定,而是要通过前端参数传递过来,那么此时就必须使用 $ 了因为 # 预处理之后,会把数据库中的字段名识别为字符串,进而会出错,如下所示:

select count(*) from user group by ${param}

当然,上面这只是其中的一个例子,实际情况是,只要遇到将数据库的字段名作为参数传递的情况,都得用 $!

五. 小结

最后,百泽老师再来给大家简单总结一下两者的区别:

  • # 会进行预编译,而且会进行类型匹配,参数是在编译之后填充进去的,所以不需要加上单引号;

  • $ 不会进行数据类型匹配,只是一种单纯的字符串拼接,所以要自己手动加上单引号,否则最终拼接出来的 SQL语句会有问题。不过也要看具体的使用场景,如果参数是列名,就不用加单引号;

  • `#` 能够预防 SQL 注入问题,$ 不能;

  • 当需要遇到将数据库的字段名作为参数传递时,应该使用用 $。

现在,你知道Mybatis中的#与$有哪些区别了吗?

 

扫码添加请备注:java

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

威哥爱编程(马剑威)

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值