MyBatis:查询与连接池

news2024/9/23 20:08:28

一、查询

1、多表查询

尽量避免使用多表查询,尤其是对性能要求较高的项目。因为多表查询必然会导致性能变低。

例如:select *from ta运行需要10ms,select *from tb 运行也需要10s。但是,select *from ta left join tb on ta.xx==tb.xx 必然大于10ms,

并且数据库集群是很多项目一起使用的,当出现慢查询时,会影响整个集群,也就是会影响其他服务的速度。

在数据库上再建立一个文章表:

DROP TABLE IF EXISTS articleinfo;

CREATE TABLE articleinfo (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(100) NOT NULL,
    content TEXT NOT NULL,
    uid INT NOT NULL,
    delete_flag TINYINT(4) DEFAULT 0 COMMENT '0-正常, 1-删除',
    create_time DATETIME DEFAULT CURRENT_TIMESTAMP,
    update_time DATETIME DEFAULT CURRENT_TIMESTAMP
) DEFAULT CHARSET = 'utf8mb4';

INSERT INTO articleinfo (title, content, uid) VALUES ('Java', 'Java正文', 1);
INSERT INTO articleinfo (title, content, uid) VALUES ('Python', 'Python正文', 2);

对应Model层的实体类:

package com.example.mybatisdemo.model;

import lombok.Data;

import java.util.Date;

@Data
public class ArticleInfo {
     private Integer id;
     private String title;
     private String content;
     private Integer uid;
     private Integer deleteFlag;
     private Date createTime;
     private Date updateTime;
}

根据uid查询作者的名称等相关信息,进行多表查询的sql语句应该为:

SELECT ta.*, tb.username
FROM articleinfo ta
LEFT JOIN userinfo tb ON ta.uid = tb.id
WHERE ta.id = 1;

所以,我们要补充实体类,在刚刚的ArticleInfo类中加入用户相关信息,便于映射:

@Data
public class ArticleInfo {
     private Integer id;
     private String title;
     private String content;
     private Integer uid;
     private Integer deleteFlag;
     private Date createTime;
     private Date updateTime;
     //用户相关信息
     private String username;
     private Integer age;
}

对应的ArticlenInfoMapper接口:

@Mapper
public interface ArticlenInfoMapper {
    //多表查询
    @Select("select ta.*,tb.username from articleinfo ta " +
            "left join userinfo tb on ta.uid = tb.id " +
            "where ta.id = #{articleId}")
    ArticleInfo selectArticlenAndUserByID(Integer articleId);
}

如果名称不⼀致的,采⽤ResultMap,或者别名的方式解决, 和单表查询⼀样。Mybatis 不管单表还是多表,主要就是三部分:SQL, 映射关系和实体类通过映射关系,把SQL运⾏结果和实体类关联起来。

2、#{} 和 ${}

Ⅰ、区别

#{}和${}都是MyBatis框架中使用的占位符。

@Select("select username, `password`, age, gender, phone from userinfo where username= #{name} ")
UserInfo selectByName(String name);

image-20240319102440963

然后把#{}换成${}

@Select("select username, `password`, age, gender, phone from userinfo where username= ${name} ")
UserInfo selectByName(String name);

image-20240319102604288

使用${}时,MyBatis不会自动添加引号。{}用于直接替换SQL语句中的文本,因此在某些情况下,如果替换的值是字符串,则需要手动添加引号。

#{}利用预编译SQL的方式工作,它通过在SQL语句中使用?占位符来提前编译SQL命令,并在执行时将参数值安全地绑定到这些占位符上。MyBatis会根据参数的类型自动添加必要的引号,例如字符串类型的参数会被加上引号'',以确保SQL语句的正确性和安全性。相反,${}则采用简单的字符串替换机制,它在SQL语句编译之前直接将参数值替换到SQL命令中。这意味着如果参数值是字符串,需要手动添加引号''来确保SQL语句的语法正确性。

总结:

#{}${}在MyBatis中的区别主要体现在以下几个方面:

  1. 预编译处理
    • #{}:使用预编译语句(PreparedStatement),参数会被替换为?,并在SQL执行时绑定参数值。这种方式可以防止SQL注入,因为参数值会被数据库引擎视为数据,而不是SQL命令的一部分。
    • ${}:不使用预编译语句,参数值会直接替换到SQL语句中。这种方式不会防止SQL注入,因为参数值被视为SQL语句的一部分,如果参数值中包含SQL关键字或特殊字符,可能会改变原SQL语句的结构。
  2. 参数替换方式
    • #{}:参数替换后,MyBatis会根据参数的类型自动添加引号,例如字符串类型的参数会被加上引号''
    • ${}:参数替换后,不会自动添加引号,如果参数是字符串类型,需要手动添加引号。
  3. 使用场景
    • #{}:适用于大部分情况,尤其是处理用户输入或不可信数据时,提供安全保障。
    • ${}:适用于需要动态指定表名、列名或其他SQL关键字的情况,但使用时需要确保参数值的安全性。
  4. 性能影响
    • #{}:通常不会对性能产生负面影响,因为预编译语句可以被数据库缓存和重用。
    • ${}:如果用于字符串替换,可能会导致数据库无法有效缓存执行计划,从而影响性能。
  5. 安全性
    • #{}:提供了更好的安全性,可以防止SQL注入攻击。
    • ${}:存在SQL注入的风险,应该尽量避免使用,或者在确保参数值安全的情况下谨慎使用。

Ⅱ、SQL注入

${}存在一个非常大的问题,那就是SQL注入。当使用${}时,MyBatis不会对替换的参数值进行任何转义或预处理。这意味着,如果参数值包含特殊字符或SQL关键字,它们将直接插入到SQL语句中。如果这些值来自于用户的输入,且没有得到适当的验证和清理,攻击者就可以利用这一点来执行恶意SQL代码。

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

测试代码:

@Test
void selectUserByName() {
    log.info(userInfoMap.selectUserByName("' or 1 = '1").toString());
}

image-20240319112222814

SQL注⼊代码: ' or 1='1。这里可以看见,结果被正确查询出来了, 其中参数 or 被当做了SQL语句的⼀部分。由于没有对用户输⼊进行充分检查,而SQL⼜是拼接⽽成,在用户输⼊参数时,在参数中添加⼀些SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

3、排序查询

@Select("SELECT id, username, age, gender, phone, delete_flag, create_time, update_time " +
        "FROM userinfo " +
        "ORDER BY id ${sort}")
List<UserInfo> selectAllUserBySort(String sort);

这里使用 ${sort} 可以实现排序查询,而使用#{sort} 就不能实现排序查询。因为,此处 sort 参数为String类型,但是SQL语句中,排序规则是不需要加引号 '' 的,所以此时的${sort} 也不加引号。如果此时,使用 #{sort} 查询时, sort参数前后会自动给加了引号, 导致出现 sql 错误。

4、模糊查询

@Select("select id, username, age, gender, phone, delete_flag, create_time, update_time " +
"from userinfo where username like '%#{key}%' ")
List<UserInfo> selectAllUserByLike(String key);

和前面的排序查询一样,在这个查询中,由于#{}的工作方式,MyBatis会把'%#{key}%'当作一个整体,所以 '%#{key}%' 的预期结果是,参数key被包围在两个%通配符之间。所以,当使用like查询的时候,应该使用${},但是这样又会出现SQL注入的安全问题。

为了解决这个问题,可以使用MySQL 的CONCAT函数来动态地构造like查询的参数,像这样:

@Select("select id, username, age, gender, phone, delete_flag, create_time, update_time " +
"from userinfo where username like concat('%',#{key},'%')")
List<UserInfo> selectAllUserByLike(String key);

CONCAT是MySQL中的一个函数,用于将两个或多个字符串连接在一起。

基本的语法:CONCAT(string1, string2, ..., string_n)

like查询中,你可以使用CONCAT函数来动态地构造查询参数。例如,以下查询将查找用户名包含关键词"John"的所有用户:

SELECT * FROM user WHERE username LIKE CONCAT('%', 'John', '%');

在这个例子中,CONCAT('%', 'John', '%')将返回字符串"%John%“,这将在任意位置匹配关键词"John”。

二、数据库连接池

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

image-20240319124043111

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

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

目前比较流行的是:Hikari,Druid

  1. Hikari : SpringBoot默认使用的数据库连接池
  2. Druid:阿里巴巴开源的数据库连接池

如果想把默认的数据库连接池从Hikari连接池切换为Druid连接池, 只需要在pom.xml中引入相关依赖即可

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.17</version>
</dependency>

学习文档:常见问题 · alibaba/druid Wiki (github.com)

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

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

相关文章

【Web APIs】DOM节点

目录 1.节点操作 1.1DOM节点 1.2查找节点 1.2.1父节点查找 1.2.2子节点查找 1.2.3兄弟节点查找 1.3增加节点 1.4克隆节点 1.5删除节点 2.时间对象 2.1实例化 2.2时间对象方法 2.3时间戳 3.重绘和回流 1.节点操作 1.1DOM节点 DOM节点&#xff1a;DOM树中的每一个…

计算机网络:物理层中的数字传输系统全景概览解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

windows一键快速安装python方法

正常我们安装python的时候&#xff0c;需要先去下载python压缩包&#xff0c;然后再一步步安装&#xff0c;今天发现一个windows10下&#xff0c;一键安装python的方法&#xff1b; 电脑环境&#xff1a;windows10以上 安装方法&#xff1a; 0&#xff1a;在应用商店搜索pyt…

nodejs+vue反诈科普平台的设计与实现pythonflask-django-php

相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低反诈科普平台的运营人员成本&#xff0c;实现了反诈科普平台的标准化、制度化、程序化的管理&#xff0c;有效地防止了反诈科普平台的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够…

flask_Restful数据解析参数设置

add_argument 方法参数详解 add_argument方法可以指定这个字段的名字&#xff0c;这个字段的数据类 型等&#xff0c;验证错误提示信息等&#xff0c;具体如下&#xff1a; default&#xff1a;默认值&#xff0c;如果这个参数没有值&#xff0c;那么将使用这个参数 指定的默认…

防外破警示灯:高压线“守护神”,照亮安全之路

近年来&#xff0c;随着城市施工建设项目不断增多&#xff0c;大型施工机械在输电通道内活动越来越频繁&#xff0c;线路外破隐患点大幅增多。一旦施工机械在作业过程中碰触到高压线&#xff0c;将会造成线路外破事故&#xff0c;严重威胁输电线路和施工人员的安全。 哪些境况下…

STM32之HAL开发——HAL库框架介绍

HAL库外设设计思想 HAL库借鉴面向对象的设计思想&#xff0c;将外设驱动封装为对象。 HAL库使用主线 HAL使用的主要用在俩个地方&#xff0c;无外乎外设初始化以及外设的使用。想用好这两个功能&#xff0c;我们首先得对外设的封装有一定的了解。 句柄结构体 xx_HandleTypeDef…

二. CUDA编程入门-使用CUDA进行矩阵乘法的加速

目录 前言0. 简述1. 初步计算 MatMul1.1 执行一下我们的第三个CUDA程序1.2 host端与device端的数据传输1.3 CUDA Core的矩阵乘法计算1.4 代码分析 2. CUDA中的error handler2.1 为什么需要有error handler 3. 获取GPU信息3.1 执行一下我们的第五个CUDA程序3.2 为什么要注意硬件…

3月23日笔记

广播域与泛洪范围是相同的 广播&#xff1a;在同一个泛洪范围内&#xff0c;强迫交换机泛洪&#xff08;主动&#xff09; 泛洪&#xff08;被动&#xff09; ARP的工作原理&#xff1a;ARP先通过广播发送请求包&#xff0c;所有收到该广播包的设备都会将其中的源IP和源MAC相…

Node.js新手必备:超实用命令行入门教程

1.安装Node.js和npm 首先&#xff0c;我们需要下载并安装Node.js&#xff0c;它自带了npm&#xff08;Node Package Manager&#xff09;。安装完成后&#xff0c;在命令行输入&#xff1a; node -v npm -v 这两个命令分别显示已安装的Node.js和npm版本&#xff0c;确认安装成…

LeetCode 热题 HOT 100(P21~P30)

系列文章&#xff1a; LeetCode 热题 HOT 100(P1~P10)-CSDN博客 LeetCode 热题 HOT 100(P11~P20)-CSDN博客 LeetCode 热题 HOT 100(P21~P30)-CSDN博客 LC48rotate_image . - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 给定一个 n n 的二维矩阵 matrix 表…

【电路笔记】-场效应管(FET)电流源

场效应管(FET)电流源 文章目录 场效应管(FET)电流源1、概述2、偏置结 FET2.1 N沟道JFET偏置2.2 N沟道JFET输出特性3、JFET 作为恒流源4、JFET 零电压偏置5、JFET 负电压偏置6、FET 恒流源示例17、JFET电流源8、FET 恒流源示例29、FET 恒流源示例310、总结FET 恒流源使用 JFET 和…

SpringBoot3集成PostgreSQL

标签&#xff1a;PostgreSQL.Druid.Mybatis.Plus&#xff1b; 一、简介 PostgreSQL是一个功能强大的开源数据库系统&#xff0c;具有可靠性、稳定性、数据一致性等特点&#xff0c;且可以运行在所有主流操作系统上&#xff0c;包括Linux、Unix、Windows等。 通过官方文档可以…

学习刷题-13

3.23 hw机试【二叉树】 剑指offer32 剑指 offer32&#xff08;一、二、三&#xff09;_剑指offer 32-CSDN博客 从上到下打印二叉树I 一棵圣诞树记作根节点为 root 的二叉树&#xff0c;节点值为该位置装饰彩灯的颜色编号。请按照从 左 到 右 的顺序返回每一层彩灯编号。 输…

WiFi已连接却不可上网是什么原因?

很多使用wifi上网的用户都遇到过这样的问题,就是电脑已经连接了wifi,但就是上不了网。着到底是怎么回事呢?今天,极客狗带大家一起来找找WiFi已连接却不可上网是什么原因,并给出对应的解决方。 原因分析: 可能是ip地址冲突所导致,也有可能是宽带出先故障,不妨试试下面的…

OpenHarmony使用智能指针管理动态分配内存对象

概述 智能指针是行为类似指针的类&#xff0c;在模拟指针功能的同时提供增强特性&#xff0c;如针对具有动态分配内存对象的自动内存管理等。 自动内存管理主要是指对超出生命周期的对象正确并自动地释放其内存空间&#xff0c;以避免出现内存泄漏等相关内存问题。智能指针对…

装修行业万能DIY小程序源码系统 带完整的安装的代码包以及搭建教程

在如今数字化、智能化的时代背景下&#xff0c;装修行业也迎来了前所未有的发展机遇。为了满足广大装修从业者及业主的需求&#xff0c;罗峰给大分享了这款装修行业万能DIY小程序源码系统。该系统不仅提供了完整的安装代码包&#xff0c;还附带了详细的搭建教程&#xff0c;让用…

零基础入门数据挖掘系列之「特征工程」

摘要&#xff1a;对于数据挖掘项目&#xff0c;本文将学习应该从哪些角度做特征工程&#xff1f;从哪些角度做数据清洗&#xff0c;如何对特征进行增删&#xff0c;如何使用PCA降维技术等。 特征工程&#xff08;Feature Engineering&#xff09;对特征进行进一步分析&#xf…

详解机器学习概念、算法

目录 前言 一、常见的机器学习算法 二、监督学习和非监督学习 三、常见的机器学习概念解释 四、深度学习与机器学习的区别 基于Python 和 TensorFlow 深度学习框架实现简单的多层感知机&#xff08;MLP&#xff09;神经网络的示例代码&#xff1a; 欢迎三连哦&#xff01; 前言…

美团2024届秋招笔试第二场编程真题

要么是以0开头 要么以1开头 选择最小的答案累加 import java.util.Scanner; import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和…