【Mybatis】MyBatis 探秘:#{} 与 ${} 参传差异解码,数据库连接池筑牢数据交互根基

发布于:2024-12-19 ⋅ 阅读:(12) ⋅ 点赞:(0)

前言

🌟🌟本期讲解关于Spring IOC&DI的详细介绍~~~

🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客

🔥 你的点赞就是小编不断更新的最大动力                                       

🎆那么废话不多说直接开整吧~~

目录

📚️1. #{} 与 ${}的使用

1.1integer类型数据

1.2String类型数据

📚️2. #{} 与 ${}的区别

2.1性能

2.2安全性 

📚️3.${ }使用场景

3.1排序

3.2模糊查询

📚️4.数据库连接池

4.1介绍

4.2使用

📚️5.总结

 

📚️1. #{} 与 ${}的使用

我们在之前的学习中,了解到了“#{}”,但是这里的${}是什么呢?其实这里的${}也具有参数传递的功能但是我们之前为什么不使用$符号呢?且听下面的分析过程~~~

1.1integer类型数据

我们可以通过id类整型参数的传递进行实验,首先得先创建一个数据库,如下所示:

接下来我们知己使用XML的方式进行代码的编写:

在Mapper类中:

 List<UserInfo> select2(Integer id);

 这里先定义数据的返回类型,然后再在XML文件中实现查询SQL的方法:

<select id="select2" resultType="com.example.mybatis.Model.UserInfo">
        select * from user_info where id=#{id}
    </select>

然后再测试类进行测试后们可以看到如下的打印的日志:

解释:

可以发现在SQL查询语句中,参数被“?”给替代了,然后下面的参数就是“2”,此时可以了解到我们输⼊的参数并没有在后⾯拼接,id的值是使⽤ ? 进⾏占位. 这种SQL 我们称之为"预编译SQL"

然后我们将这里的“#{ }” 替换成“${}”,具体的情况就是如下所示的:

解释:

可以发现此时SQL语句,就没有“?”,然后下面的paramters参数就为空了,然后我们就知道${} 会直接进⾏字符替换, ⼀起对SQL进⾏编译,不会像#号一样使用占位符;这种我们就称之为即时SQL

1.2String类型数据

这里我们使用String类来进行匹配查询,具体的操作还是和上面差不多;

Mapper类的代码如下:

 List<UserInfo> selectAllByUsername(String username);

然后再XML写SQL语句的操作:

解释:

此时可以看到,和上面的string类型的数据是一样的,这里会标明参数的类型为string类型,然后再进行替换占位的时候会自动添加引号;

然后我们将这里的“#{ }” 替换成“${}”,具体的情况就是如下所示的:

 <select id="selectAllByUsername" resultType="com.example.mybatis.Model.UserInfo">
        select * from user_info where username=${username}
    </select>

这里就是通过输入的名字进行查询,将这#号替换成了$符号,然后再测试类进行测试后打印的日志报错了,具体的打印日志如下所示:

解释:

这里可以看到此时的$符号的操作,出现了报错,原因就是BadSql,我们在上面看到,由于直接代替的原因,查询条件中字符串没有出现“ '  '  ”符号,即引号,然后就是SQL语句语法不正确导致错误;

解决办法:

在XML编写SQL语句的时候进行手动添加' ';

代码如下:

<select id="selectAllByUsername" resultType="com.example.mybatis.Model.UserInfo">
        select * from user_info where username='${username}'
    </select>

此时进行测试打印,打印的日志就是如下所示的:

解释:此时可以看到在字符串添加了“ ' ' ”双引号,然后参数仍然为空;

综上所述:

#{} 使⽤的是预编译SQL, 通过 ? 占位的⽅式, 提前对SQL进⾏编译, 然后把参数填充到SQL语句中. #{} 会根据参数类型, ⾃动拼接引号 '' .
${} 使用的就是即时编译SQL,会直接进⾏字符替换, ⼀起对SQL进⾏编译. 如果参数为字符串, 需要加上引号 ''

📚️2. #{} 与 ${}的区别

2.1性能

当客⼾发送⼀条SQL语句给服务器后, ⼤致流程如下:

1. 解析语法和语义, 校验SQL语句是否正确
2. 优化SQL语句, 制定执⾏计划
3. 执⾏并返回结果

⼀条 SQL如果⾛上述流程处理, 我们称之为 Immediate Statements(即时 SQL) 

但是绝⼤多数情况下, 某⼀条 SQL 语句可能会被反复调⽤执⾏, 或者每次执⾏的时候只有个别的值不同(⽐如 select 的 where ⼦句值不同, update 的 set ⼦句值不同, insert 的 values 值不同). 如果每次都需要经过上⾯的语法解析, SQL优化、SQL编译等,则效率就明显不⾏了

总结: 

所以预编译SQL就在执行上述的优化操作后,遇到同样的SQL语句,就不会对SQL进行再次的优化编译了,就直接改变参数,省去了解析优化等过程, 以此来提⾼效率

预编译SQL的性能比即时SQL的性能更高;

2.2安全性 

这里出现的安全性就是(SQL注入

SQL注⼊:是通过操作输⼊的数据来修改事先定义好的SQL语句,以达到执⾏代码对服务器进⾏攻击的⽅法。由于没有对⽤⼾输⼊进⾏充分检查,⽽SQL⼜是拼接⽽成,在⽤⼾输⼊参数时,在参数中添加⼀些SQL关键字,达到改变SQL运⾏结果的⽬的,也可以完成恶意攻击

注意:这里只针对的就是${ }符号;

假如我们在此符号中添加    ' or 1='1

然后在#{ }运行中,可以发现此时的此时的打印日志告诉我们,这里的字符串在数据库中没有找到

如下所示:

这里的结果确实如我们所料,但是在${ }符号中,如下所示:

解释:

哎奇怪,怎么会出现这种情况,这个字符串在我们的数据库列中就没有这个字段;但是为啥就全部搜索出来了呢??

因为拼接的问题和原因,所以这里出现了误判,'  {'    or     1='1}  ' 拼接后成了以下SQL语句

'  '    or     1='1'

解释:

具体的意思就是为空或者为true,这就是为啥全部搜索出来了,这里存在SQL关键字or;

所以SQL注⼊是⼀种⾮常常⻅的数据库攻击⼿段, SQL注⼊漏洞也是⽹络世界中最普遍的漏洞之⼀.
如果发⽣在⽤⼾登录的场景中, 密码输⼊为 ' or 1='1 , 就可能完成登录;

总之在后面的学习中能用#{} 那么就使用#{ },${ }非特殊情况尽量不要使用 

📚️3.${ }使用场景

3.1排序

在实现排序功能的时候,由于“desc”不需要使用引号,所以这里我们就可以使用${}符号

具体的代码如下所示:

<select id="selectAllById" resultType="com.example.mybatis.Model.UserInfo">
        select * from user_info order by id ${sort}
    </select>

这里即时XML的写法,可以看到此时order by id然后排序关键词,就不需要引号,那么此时我们就可以使用$符号;

在测试类中的实现代码:

 @Test
    void selectAllById() {
        userInfoXMLMapper.selectAllById("desc");
    }

我们这里就是按照降序排序进行查询结果的排序的,最后打印的日志如下所示:

解释:

上面的两行就是SQL语句和参数,参数为空,然后即时SQL进行拼接,SQL语句就成为了一个查询语句按照降排序的方式进行查询结果的展示;

3.2模糊查询

代码如下所示:

 <select id="selectByUsername" resultType="com.example.mybatis.Model.UserInfo">
        select * from user_info where username like '%${username}%'
    </select>

这里也是不需要引号,然后也可以使用$符号,在测试类中代码:

@Test
    void selectByUsername() {
        userInfoXMLMapper.selectByUsername("o");
    }

最后打印的日志如下所示:

解释:

这里的模糊查询,中间的参数是不需要自动添加引号的,并且这里的模糊查询的条件就是查找名字里包含“o”的那一段数据;

但是这里由于注入等安全性,这里我们可以使用#进行另一种写法,具体的代码如下所示:

 <select id="selectByUsername2" resultType="com.example.mybatis.Model.UserInfo">
        select * from user_info where username like concat('%',#{username},'%')
    </select>

解释:

这里使用concat关键字,实现需要引号的拼接操作,这样就可以使用#{}来进行参数的传递,几避免了SQL注入的安全问题,还可能提高了执行的效率;

📚️4.数据库连接池

4.1介绍

数据库连接池负责分配、管理和释放数据库连接,它允许应⽤程序重复使⽤⼀个现有的数据库连接,⽽不是再重新建⽴⼀个

没有使⽤数据库连接池的情况: 每次执⾏SQL语句, 要先创建⼀个新的连接对象, 然后执⾏SQL语句, SQL语句执⾏完, 再关闭连接对象释放资源. 这种重复的创建连接, 销毁连接⽐较消耗资源

使⽤数据库连接池的情况: 程序启动时, 会在数据库连接池中创建⼀定数量的Connection对象, 当客⼾请求数据库连接池, 会从数据库连接池中获取Connection对象, 然后执⾏SQL, SQL语句执⾏完, 再把Connection归还给连接池 

优点:

1. 减少了⽹络开销
2. 资源重⽤
3. 提升了系统的性能 

4.2使用

常⻅的数据库连接池:

• C3P0
• DBCP
• Druid
• Hikari

主流就是Hikari,Druid;

我们的SpringBoot默认使用的就是Hikari;日志如下所示:

可以看到这就是springboot默认使用的就是Hikari;

📚️5.总结

本期小编主要讲解了关于#{ },${ },的区别与如何进行使用,讲解了两者的性能比较,比较重要的SQL注入的问题,以及简单的阐述了数据库连接池的介绍~~~

🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!


💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。

       😊😊  期待你的关注~~~


网站公告

今日签到

点亮在社区的每一天
去签到