JavaEE进阶----18.<Mybatis补充($和#的区别+数据库连接池)>

news2024/10/23 22:48:23

详解了

1.$和#的区别

2.数据库连接池。

3.简单了解MySQL企业开发规范

一、Mybatis面试题:$和#的区别是什么?

MyBatis 参数赋值有两种方式,咱们前面使用了 #{} 进行赋值,接下来我们看下二者的区别。

1.1 #是预编译SQL,$是即时SQL

SQL执行流程

1.语法解析,校验SQL有没有问题。

2.SQL优化,编译,制定执行计划。

3.执行SQL

因此

①#是预编译SQL,不是一个完整的SQL。可以进行缓存,参数是不固定的,性能更高。

   $时即时SQL,可以直接编译。但不能进行缓存,参数是固定的。性能更低。

②$存在SQL注入的风险

我们分别使用Integer与String类型参数举例

#是预编译SQL,预编译处理。

$是即时SQL,字符直接替换。

预编译SQL的性能更高一点。可以进行缓存

我们编写如下代码。用#和$分别去取值Integer类型参数和String类型参数。

参数为Integer类型时

使用#符号:预编译SQL。(select * from userinfo where id = ?)

@Select("select * from userinfo where id = #{userId}")
UserInfo queryUserInfo(Integer userId);


 使用$符号:即时SQL。(select * from userinfo where id = 1)

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

2.参数为String类型时

使用 # 符号:预编译SQL。(select * from userinfo where username = ?)

# 会拼接引号。

因此 # 适用于需要拼接引号的情况。

而不用拼接引号的情况就是 $ 符号发挥作用的时候了。

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

 使用$符号:即时SQL。(select * from userinfo where username = admin)(报错)

$不会拼接引号,而是直接拼接上。 

    @Select("select * from userinfo where username = ${name}")
    List<UserInfo> queryUserByName2(@Param("name") String name);
    @Test
    void queryUserByName2() {
        log.info(userInfoMapper.queryUserByName2("admin").toString());
    }

 使用$符号:即时SQL。(select * from userinfo where username = 'admin')

$不会拼接引号,而是直接拼接上。 因此注意加单引号。或者双引号。

这样就不会报错了

select * from userinfo where username = '${name}'

    @Select("select * from userinfo where username = '${name}'")
    List<UserInfo> queryUserByName2(@Param("name") String name);
    @Test
    void queryUserByName2() {
        log.info(userInfoMapper.queryUserByName2("admin").toString());
    }

注:

如果只有一条结果,那么使用对象接收也可以,使用List<UserInfo>接收也可以。

如果有多条结果,那么只能使用 List 来接收


1.2最主要区别($存在SQL注入的问题。

1.1.1$存在SQL注入的问题

最主要的区别是:$存在SQL注入的问题。

SQL注入:

是通过操作输入的数据(参数),来修改事先定义好的SQL语句(不完整SQL),以达到执行的代码对服务器进行攻击的方法。 

也就是把参数作为SQL的一部分,以达到对服务器进行攻击的目的。

示例:

这个就相当于

select * from userinfo where username = ture 

  • 空字符串 ' ' 的含义

    • 在 SQL 中,空字符串 ' ' 是一个非空的字符串,因此在布尔上下文中,它会被视为真值(TRUE)。
    • 因为空字符串不是NULL,所以在逻辑表达式中,它被认为是“有值”的。
  • 1 = '1' 的逻辑

    • SQL 中,字符串 '1' 和整数 1 在比较时通常会隐式转换为相同的数据类型。1 = '1' 会被解释为 1 = 1,结果为 TRUE

执行SQL语句后,我们得到的结果是将表内所有内容都打印出来了。相当于没有where

由于存在SQL注入的问题因此$符号不被广泛使用了。

早期SQL注入的问题:

可以将表删掉,

也可以更新表的数据,因此SQL注入是一个非常严重的问题。

delete的问题不存在了,是因为Mybatis帮我们拦截了,例如我们@select注解中有delete操作,那么就会将之拦截。

通过SQL注入完成无密码就可以登录

也不是说使用$就一定会存在SQL注入问题。而是看你的代码如何去实现的

模拟SQL注入 完成用户登录 代码演示:

1.在Controller包控制器层中(也算是三层架构中的视图层)
​​​​​​​​​    @RequestMapping("/login")
    public UserInfo login(String userName,String password){
        return userService.queryUserByNameAndPassword(userName,password);
    }
2.在Service服务层包中
    public UserInfo queryUserByNameAndPassword(String name,String password) {
        List<UserInfo> userInfos = userInfoMapper.queryUserByNameAndPassword(name,password);
        if(!userInfos.isEmpty()){
            //如果查出来
            return userInfos.get(0);
        }
        //如果没查出来
        return null;
    }
3.在Mapper数据访问层中:

​​​​​​​

4. 访问的数据库表如下

5.最终访问的结果如下:

我们发现:

当我们的密码输入为'or 1='1时数据也可以被访问到,这就是很严重的SQL注入问题。  

这就是一个漏洞。

这并不是说如果你使用$符号就一定有问题。如果Mapper层代码我们使用

对象UserInfo来接收的话,那么我们使用' or 1='1也登录不进去,因为这样会报错。是因为UserInfo默认返回一个对象的数据。而如果存在SQL注入,就会返回多个对象的数据。

如果只有一条结果,那么使用对象接收也可以,使用List<UserInfo>接收也可以。

如果有多条结果,那么只能使用 List 来接收。如果使用UserInfo对象来接收就会报错。

还有一些其他地方

如果我们根据userName去查再去通过password校验,这种情况使用' or 1='1也登录不进去

1.3在使用上的其他区别

表名,字段名作为参数时。这些情况需要使用${ }。

1.3.1使用淘宝进行排序问题(不能使用#):

此时需要使用$符号,

注:

此时也存在SQL注入的风险

解决办法:如果不让用户传参的话,那么就不存在SQL注入风险了

也就是不给用户在用$取值的输入框。

如何来去做呢?请往下看

SQL语句七 由Id进行倒序排序。

select * from userinfo order by id desc

假如我们这样在Mapper包中写数据。那么就会报错。

SQL语句出错,是因为#若参数是字符串会默认加上' '此时

SQL语句变成了

select * from userinfo order by id 'desc'

因此会报错,如果我们改成用$来取值,那么此时就可以编译通过了

注:

此时也存在SQL注入的风险,解决办法:如果不让用户传参的话,那么就不存在SQL注入风险了

也就是不给用户在用$取值的输入框。

如何来去做呢?请往下看

$存在SQL注入风险,如何处理?

实现方式非常多,简单列举以下方式

例如1:不接收用户输入的参数,参数由后台来处理。

代码要写的很严谨,就不存在SQL注入问题了。

升序:url1

降序:url2

不接收用户输入的参数,参数由后台来处理。

对参数进行校验,只接受desc(降序)      /      asc(升序) 这两个参数

在后端进行校验。如果不是这两个参数则立马报错进行处理。

order参数是Controller包中被用户传进来的

还有哪些情况#不能使用

不需要加引号的时候,比如表名,字段名。

表名,字段名作为变量的时候,

表明作为变量:

在分库分表的情况下,若将userinfo这张表分成userinfo1,userinfo2,...userinfo10这十张表,我们查询的时候,根据一定的规则,看哪张表里有我们想要的userId,此时表名就是变量了。

字段名作为变量:

1.一些大公司不让直接连数据库(不然账号密码直接登录数据库),连了就会有风险,如何规避风险,而是开发一个MySQL客户端,申请权限就可以直接连数据库不需要账号密码。需要解析SQL。字段都是生成的,

2.数据的导出,若只想导出某一些列,此时列名就会被作为变量。#不能使用。

1.3.2模糊查询问题(不能直接使用#,需要通过CONCAT(str1,str2,..)方式再用#实现):

SQL语句八:模糊查询

select * from userinfo where username like "%需要查询的名字%"

例:select * from userinfo where username like "%admin%"

数据库表

我们在Mapper中写出如下代码进行迷糊查询并进行测试:

只查询出来了一条,因为输入结果为admin,我们虽然加了%%但是被弄丢了。因此相当于我们只查了admin没有进行模糊查询。相当于等号。

也就是拼接成了

select * from userinfo where username like admin 

相当于

select * from userinfo where username = admin

换一种写法,我们将百分号写在外面

又报错了,SQL语句出错。 拼接成了

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

在里面又加上了引号。

因此模糊查询通过#无法实现。

通过$实现模糊查询

我们发现,成功得到了我们想要的结果。

模糊查询$存在SQL注入风险,如何处理?

使用MySQL的CONCAT(str1,str2,....)

CONCAT()是mysql内置函数

使用示例如下

select * from userinfo where username like CONCAT('%',admin,'%')

改成这种形式 就可以使用#来实现模糊查询

总结

#和$的区别

1.#是预编译SQL,预编译处理。$是即时SQL,字符直接替换。预编译SQL的性能更高一点。可以进行缓存

2.$存在SQL注入的风险。#{ }可以防止SQL注入。

3.查询语句中,可以使用#{ }推荐使用#{ }。#{ }不能完成如排序功能表名字段名作为参数时。这些情况需要使用${ }。

4.排序,模糊查询等方式不能直接用#来取值。排序可以进行校验,模糊查询可以通过使用MySQL内置函数进行转化再用#进行查询。

模糊查询虽然${}可以完成,但因为存在SQL注入的问题,所以通常使用mysql内置函数concat来完成

相同点:

#是取值用的

$也是取值用的

二、数据库连接池

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接, 而不是再重新建立一个。

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

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

使用数据库连接池的好处:

优点:

1. 减少了网络开销

2. 资源重用

3. 提升了系统的性能

常见数据库连接池:C3P0、DBCP、Druid、HiKari。

目前比较流行的数据库连接池是Hikari,Druid

2.1Hikari :

Hikari 是日语"光"的意思(ひかり),Hikari也是以追求性能极致为目标

是SpringBoot默认使用的数据库连接池

Hikaricp和Druid对比_数据库_晚风暖-华为云开发者联盟 (csdn.net)

2.2Druid

如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要引入相关依赖即可 

<dependency>

        <groupId>com.alibaba</groupId>

        <artifactId>druid-spring-boot-starter</artifactId>

        <version>1.1.17</version>

</dependency>

官方参考地址

Druid连接池是阿里巴巴开源的数据库连接池项目 功能强大,性能优秀是Java语言最好的数据库连接池之⼀。

学习文档:https://github.com/alibaba/druid/wiki/%E9%A6%96%E9%A1%B5

大总结

1.MySQL企业开发规范

重点:

1.表名,字段名用小写字母或数字,单词间用_分割。尽量避免出现数字开头或者两个下划线中间只出现数字。数据库字段名的修改代价很大,所以字段名称需要慎重考虑。

2.表必备三字段:id,create_time,update_time

3.在表查询中, 避免使用*作为查询的字段列表,标明需要哪些字段

2.#{} 和${} 区别

1. #{}:预编译处理, ${}:字符直接替换

2. #{} 可以防⽌SQL注⼊,${}存在SQL注⼊的⻛险,查询语句中,可以使⽤#{},推荐使⽤#{}

3. 但是⼀些场景,#{}不能完成,比如排序功能,表名,字段名作为参数时,这些情况需要使用${}

4. 模糊查询虽然${}可以完成,但因为存在SQL注⼊的问题,所以通常使⽤mysql内置函数concat来完成

3.数据库连接池

目前比较流行的数据库连接池是

Hikari:是SpringBoot默认使用的数据库连接池

Druid:是阿里巴巴开源的数据库连接池项目。功能强大,性能优秀是Java语言最好的数据库连接池之⼀。

优点:

1. 减少了网络开销

2. 资源重用

3. 提升了系统的性能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2221929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

序列化问题记录:Jackson 与 Fastjson 的注解

前言 Java 后端开发中&#xff0c;我们经常需要处理 JSON 序列化和反序列化的问题。Spring 框架默认使用 Jackson 作为 JSON 处理库&#xff0c;但在某些情况下&#xff0c;我们也可能会使用 Fastjson 来处理特定的序列化需求。由于这两种库的注解不完全兼容&#xff0c;因此在…

springboot扩展点都有哪些?

在Spring Boot中&#xff0c;扩展点指的是能够自定义或增强Spring Boot功能的机制。这些扩展点允许开发者在Spring Boot的基础设施之上做定制化配置、行为修改或增强。Spring Boot主要有以下几类扩展点&#xff1a; 1. ApplicationRunner 和 CommandLineRunner 这两个接口允许…

网络运输层之(1)TCP连接管理

网络运输层之(1)TCP连接管理 Author: Once Day Date: 2024年10月22日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文章可参考专栏: 通信网络技术_Once-Day的博客…

【四】企业级JavaScript开发开发者控制台

多行输入 通常&#xff0c;当我们向控制台输入一行代码后&#xff0c;按 Enter&#xff0c;这行代码就会立即执行。 如果想要插入多行代码&#xff0c;请按 ShiftEnter 来进行换行。这样就可以输入长片段的 JavaScript 代码了。 总结 开发者工具允许我们查看错误、执行命令、…

【python爬虫课程设计】天气预报——分类数据爬取+数据可视化

一、选题的背景 随着人们对天气的关注逐渐增加&#xff0c;天气预报数据的获取与可视化成为了当今的热门话题&#xff0c;天气预报我们每天都会关注&#xff0c;天气情况会影响到我们日常的增减衣物、出行安排等。每天的气温、相对湿度、降水量以及风向风速是关注的焦点。通过…

【Linux】线程互斥与同步,生产消费模型(超详解)

目录 线程互斥 进程线程间的互斥相关背景概念 数据不一致问题 锁 深度理解锁 原理角度理解&#xff1a; 实现角度理解&#xff1a; 线程同步 条件变量 测试代码 生产消费模型 生产消费模型概念 编写生产消费模型 BlockingQueue &#xff08;1&#xff09;创建生产…

Dell服务器导入idrac 授权文件 (适用iDRAC7、iDRAC8、iDRAC9)

iDRAC Enterprise、iDRAC Datacenter 和 CMC Enterprise 的 30 天试用许可证,供熟悉高级功能集,例如使用虚拟控制台等 OpenManage Enterprise Advanced 或 Advanced+ 许可证支持高级功能,例如自动部署、服务器配置合规性和激活可用插件,如 OpenManage Enterprise Power Ma…

MySQL 数据库迁移至达梦 DM8 常见问题

目录 如何让迁移到 DM 的表名大小写和 MySQL 保持一致 MySQL 迁移到 DM 报错&#xff1a;列[NAMES]长度超出定义 MySQL 迁移到 DM 报错&#xff1a;记录超长 索引错误 DM大小写敏感配置 表空间 新建用户 用户与模式的关系 省略模式名的优势 实际操作 如何让迁移到 DM…

知识图谱的概念、特点及应用领域(详解)

目录 什么是知识图谱&#xff1f; 二、特点 三、应用领域 什么是知识图谱&#xff1f; 知识图谱&#xff08;Knowledge Graph&#xff09;是一种将知识进行结构化、组织和表示的方法&#xff0c;它利用图形模型表示事物之间的关系和属性。知识图谱通过节点&#xff08;实体&…

qt QWidget详解

一、概述 QWidget是容器组件&#xff0c;继承自QObject类和QPaintDevice类。能够绘制自己和处理用户输入&#xff0c;是QT中所有窗口组件类的父类&#xff0c;是所有窗口组件的抽象&#xff0c;每个窗口组件都是一个QWidget&#xff0c;QWidget类对象常用作父组件或顶级组件使…

T113 内核中 adbd相关配置1

准备工作 1. 配置 系统&#xff1a;ubuntu24.04docker&#xff08;ubuntu18.04&#xff09; 软件vscode, sdk:Tina-linux&#xff08;BingPi-M2&#xff09; 2. 构建环境直接使用自带的 source ./build/envsetup.sh lunch 选择 6 编译开启16线程 make -j16boot编译 mboot 打包…

关于jmeter中没有jp@gc - response times over time

1、问题如下&#xff1a; jmeter没有我们要使用的插件 2、解决方法&#xff1a; 选择下面文件&#xff0c;点击应用&#xff1b; 3、问题解决 ps&#xff1a;谢谢观看&#xff01;&#xff01;&#xff01;

力扣 简单 746.使用最小花费爬楼梯

文章目录 题目介绍题解 题目介绍 题解 思路分析&#xff1a; 确定dp数组以及下标的含义&#xff1a;dp[i]的定义为到达第i台阶所花费的最少体力。确定递推公式&#xff1a;可以有两个途径得到dp[i]&#xff0c;一个是dp[i-1] 一个是dp[i-2]。dp[i - 1] 跳到 dp[i] 需要花费 d…

玩转springboot之springboot异步执行

springboot异步执行 使用EnableAsync开启异步执行 在接口方法上使用Async注解进行标注&#xff0c;该接口是一个异步接口 自定义异步线程执行器 Configuration public class CustomAsyncConfigurer implements AsyncConfigurer {Overridepublic Executor getAsyncExecutor() {T…

WebGL编程指南 - 颜色与纹理

将顶点的其他&#xff08;非坐标&#xff09;数据——如颜色等——传入顶点着色器。 发生在顶点着色器和片元着色器之间的从图形到片元的转化&#xff0c;又称为图元光栅化 &#xff08;rasterzation process&#xff09;。 将图像&#xff08;或称纹理&#xff09;映射到图形…

C++笔记---哈希表

1. 哈希的概念 哈希(hash)又称散列&#xff0c;是一种组织数据的方式。从译名来看&#xff0c;有散乱排列的意思。 本质就是通过哈希函数把关键字Key跟存储位置建立一个映射关系&#xff0c;查找时通过这个哈希函数计算出Key存储的位置&#xff0c;进行快速查找。 STL中的un…

推荐IDE中实用AI编程插件,目前无限次使用

插件介绍 一款字节跳动推出的“基于豆包大模型的智能开发工具” 以vscode介绍【pycharm等都可以啊】&#xff0c;这个插件提供智能补全、智能预测、智能问答等能力&#xff0c;节省开发时间 直接在IDE中使用&#xff0c;就不用在网页中来回切换了 感觉还可以&#xff0c;响应速…

Excel表格如何修改“打开密码”,简单几步,轻松搞定

在保护Excel文件的安全性时&#xff0c;设置打开密码是常见且有效的方式。然而&#xff0c;有时我们需要修改已经设置的打开密码&#xff0c;以确保文件安全性或更新密码信息。今天小编来分享一下修改Excel文件打开密码的方法&#xff0c;操作简单&#xff0c;一起来看看吧&…

设置OpenAI API的环境变量

获取openai API 密钥 https://platform.openai.com/api-keys 设置环境变量 为什么不在代码中直接写入&#xff0c;而是设置环境变量&#xff1f; 安全性&#xff1a;将 API 密钥存储在环境变量中&#xff0c;而不是直接写在代码中&#xff0c;可以降低泄露密钥的风险。易于…

第二期:第15节,beep 大海

首先是 代码的编写&#xff1a; 里面已经有了解释了。 1 /*2 * main.c3 *4 * Created on: 2023-3-85 * Author: pengdan6 */7 #include "exynos_4412.h"89 void delay_ms(unsigned int num)10 {11 int i,j;12 for(inum; i>0;i--)13 …