【JavaEE进阶】 #{}和${}

简介: 【JavaEE进阶】 #{}和${}


🍃前言

MyBatis参数赋值有两种⽅式,使⽤ #{} 和 ${}进⾏赋值,接下来我们看下⼆者的区别

🌳#{}和${}使⽤

我们先来看一下两者在基础数据类型与string类型下的使用

🚩Interger类型的参数(基础数据类型)

🎈使用#{}

@Select("select * from userinfo where id= #{id}")
List<UserInfo> selectId(Integer id);

我们观察一下我们的打印日志:

发现我们输出的SQL语句:

select * from userinfo where id= ?

我们输⼊的参数并没有在后⾯拼接,id的值是使⽤ ? 进⾏占位.这种SQL我们称之为"预编译SQL"

🎈使用${}

@Select("select * from userinfo where id= ${id}")
List<UserInfo> selectId1(Integer id);

可以看到,这次的参数是直接拼接在SQL语句中了.

🚩String类型的参数

使用🎈#{}

@Select("select * from userinfo where username = #{name}")
List<UserInfo> selectId2(String name);

观察打印日志

结果与上面一样成功返回

使用🎈${}

再使用一下${}

@Select("select * from userinfo where username = #{name}")
List<UserInfo> selectId3(String name);

再次进行打印日志:

可以看到,这次的参数依然是直接拼接在SQL语句中了,但是字符串作为参数时,需要添加引号 ‘’ ,使⽤ ${} 不会拼接引号 ‘’ ,导致程序报错.

修改代码如下:

@Select("select * from userinfo where username = '${name}'")
List<UserInfo> selectId3(String name);

再次运行

结果实现正常

从上⾯两个例⼦可以简单看出:

#{} 使⽤的是预编译SQL,通过 ? 占位的⽅式,提前对SQL进⾏编译,然后把参数填充到SQL语句中.

#{} 会根据参数类型,⾃动拼接引号 ‘’ .${} 会直接进⾏字符替换,⼀起对SQL进⾏编译.如果参数为字符串,需要加上引号 ’ ’

参数为数字类型时,也可以加上,查询结果不变,但是可能会导致索引失效,性能下降

🎍#{}和${}区别

#{}和${}的区别就是预编译SQL即时SQL的区别.

🚩#{}性能更⾼

绝⼤多数情况下,某⼀条SQL语句可能会被反复调⽤执⾏,或者每次执⾏的时候只有个别的值不同(⽐如select的where⼦句值同,update的set⼦句值不同,insert的values值不同).

如果每次都需要经过上⾯的语法解析,SQL优化、SQL编译等,则效率就明显不⾏了.

预编译SQL,编译⼀次之后会将编译后的SQL语句缓存起来,后⾯再次执⾏这条语句时,不会再次编译(只是输⼊的参数不同),省去了解析优化等过程,以此来提⾼效率

🚩#{}更安全(防⽌SQL注⼊)

SQL注⼊:是通过操作输⼊的数据来修改事先定义好的SQL语句,以达到执⾏代码对服务器进⾏攻击的⽅法

原因:由于没有对⽤⼾输⼊进⾏充分检查,⽽SQL⼜是拼接⽽成,在⽤⼾输⼊参数时,在参数中添加⼀些SQL关键字,达到改变SQL运⾏结果的⽬的,完成恶意攻击

接下来我们先看一个sql注入的例子:

注入sql代码: ’ or 1='1

首先我们有以下代码:

@Select("select * from userinfo where username = '${name}'")
List<UserInfo> selectId4(String name);

当我们正常传参数时,代码如下:

@Test
void selectId4() {
    List<UserInfo> list = assignmentMapper.selectId3("陈平安");
    System.out.println(list);
}

正常运行结果如下:

接下来我们注入sql代码如下:

@Test
void selectId4() {
    List<UserInfo> list = assignmentMapper.selectId3("' or 1='1 ");
    System.out.println(list);
}

再次运行:结果依然被正确查询出来了,其中参数or被当做了SQL语句的⼀部分

但是呢,我们需要查询的应该是一个人的信息,这里却将所有人的信息给打印了出来。

🚩${}的使⽤场景

从上⾯的例⼦中,可以得出结论:$ {}会有SQL注⼊的⻛险,所以我们尽量使⽤#{}完成查询

既然如此,是不是$ { }就没有存在的必要性了呢?

当然不是.接下来我们看下${}的使⽤场景

🎈排序功能

接下来我们来实现通过传递参数让表实现升序降序排序:

我们先用#{}

@Select("select * from userinfo order by id #{sort}")
List<UserInfo> selectId5(String sort);

当我们进行传参:

@Test
void selectId5() {
    List<UserInfo> list = assignmentMapper.selectId5("asc");
    System.out.println(list);
}

进行启动:

可以发现,当使⽤ #{sort} 查询时,asc前后⾃动给加了引号,导致sql错误

使用${}就可以避免这种情况:

除了这个之外,还有表名作为参数时,也只能使⽤ ${}

🎈like查询

同样,like使⽤#{}报错

@Select("select * from userinfo where username = like '%#{key}%' ")
List<UserInfo> selectId7(String key);

把#{}改成$ {}可以正确查出来,但是$ {}存在SQL注⼊的问题,所以不能直接使⽤${}

@Select("select * from userinfo where username = like concat('%',#{key},'%') ")
List<UserInfo> selectId7(String key);

🍀#{}和${}区别总结

  1. #{}:预编译处理,${}:字符直接替换
  2. #{}可以防⽌SQL注⼊,${}存在SQL注⼊的⻛险,查询语句中,可以使⽤#{},推荐使⽤#{}
  3. 但是⼀些场景,#{}不能完成,⽐如排序功能,表名,字段名作为参数时,这些情况需要使⽤${}
  4. 模糊查询虽然${}可以完成,但因为存在SQL注⼊的问题,所以通常使⽤mysql内置函数concat来完成

⭕总结

关于《【JavaEE进阶】 #{}和${}》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

相关文章
|
6月前
|
前端开发 JavaScript Java
JAVAEE框架技术之4springMVC入门
JAVAEE框架技术之4springMVC入门
133 0
JAVAEE框架技术之4springMVC入门
|
开发框架 分布式计算 Java
【面试题精讲】JavaSe和JavaEE的区别
【面试题精讲】JavaSe和JavaEE的区别
|
5月前
|
Java Spring 容器
【JavaEE进阶】 @ControllerAdvice源码分析
【JavaEE进阶】 @ControllerAdvice源码分析
|
6月前
|
XML Java 数据库连接
【JAVA基础篇教学】第十五篇:Java中Spring详解说明
【JAVA基础篇教学】第十五篇:Java中Spring详解说明
|
6月前
|
前端开发 JavaScript Java
JavaEE初阶 Day1
JavaEE初阶 Day1
33 0
|
6月前
|
存储 人工智能 算法
JavaSE 进阶-javase进阶(一)
JavaSE 进阶-javase进阶
61 0
|
6月前
|
安全 Java API
JavaSE 进阶-javase进阶(二)
JavaSE 进阶-javase进阶
50 0
|
6月前
|
安全 算法 Java
JavaSE 进阶-javase进阶(三)
JavaSE 进阶-javase进阶
58 0
|
6月前
|
安全 Java Maven
【JavaEE进阶】 SpringBoot的创建与简单使用
【JavaEE进阶】 SpringBoot的创建与简单使用
|
前端开发 Java 应用服务中间件
Java 学习之入门springBoot
# 简介 SpringBoot是Pivotal团队提供的全新框架,其设计目的来简化Spring应用的初始搭建以及开发过程。 ## 对比之前的框架 笔者之前也学习应用过很多框架,包括Spring,SpringMVC,MyBatis等等....... 拿SpringMVC来举例,在SpingMVC中配置了处理请求的时候,会遇到静态资源无法访问的问题,这是因为我们对于getSeverletMappings中的设置是控制所有的路由,那么这问题就来了,我们对于访问静态资源这个事情,并不会经手Tomcat,而是经过SpringMVC,他会直接拦截我们的请求,而拦截后springMVC会发现我们并没