MyBatis - XML CRUD 其他查询

news2025/3/9 7:47:39

1. XML 配置文件

使用 MyBatis 操作数据库的方式有两种:

  1. 注解 (在注解中定义 SQL 语句)
  2. XML 配置文件 (在 XML 文件中定义 SQL 语句)

在上一篇博客中, 已经讲解了如何使用注解操作数据库, 本篇文章来讲解如何使用 XML 进行 MyBatis 开发.

使用 XML 的步骤, 和使用注解的步骤是一致的:

  1. 导入 MyBatis 依赖和 MySQL 驱动的依赖
  2. 配置数据库信息(连接数据库)
  3. 定义接口
  4. 使用 XML 定义 SQL, 操作数据库

1.1 如何配置 XML 文件

1.1.1 步骤一: 导入相关依赖

首先, 需要导入 MyBatis 依赖和 MySQL 驱动依赖, 上篇文章已经讲过, 这里就不再赘述:

 1.1.2 步骤二: 配置数据库信息

然后, 需要配置数据库信息, 进行数据库连接, 上篇博客中也讲了, 也就不再赘述.

# 数据库配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 111111
    driver-class-name: com.mysql.cj.jdbc.Driver

 1.1.3 步骤三: 定义 Mapper 接口

定义 Mapper 接口, 接口中包含操作数据库的方法:

1.1.4 步骤四: 配置 XML 文件

既然使用 XML 操作数据库, 那么首先需要新建一个 XML 文件: 
(注意: XML 文件需要建于 resources 包下!!) 

为了提高代码可读性, 可维护性, 通常一个 XML 文件, 对应一个 MyBatis 的 Mapper 接口, 并且建议 XML 文件的命名与 Mapper 接口的命名保持一致:

在 XML 文件中, 需要配置对应 Mapper 接口的路径(接口的完全限定名).

通过 namespace 属性来关联 XML 文件和对应的 Mapper 接口(告诉 MyBatis, 我这个 XML 文件对应的是哪个接口):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
                <!--配置 Mapper 接口的路径-->
<mapper namespace="com.study.mybatis.Mapper.UserInfoMapperXML">

</mapper>

此外, 还需要在配置文件中, 配置 XML 文件的路径信息, 以便在项目启动时, 能够加载该 XML 文件:

mybatis:
  # 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
  mapper-locations: classpath:mapper/*Mapper.xml 

完成以上配置后, 我们就可以通过 MyBatis 以 XML 的形式来操作数据库了.

2. MyBatisX 插件

使用 XML 操作数据库前, 我们需要下载 MyBatisX 插件, 可以帮助我们简化相关操作:

3. 使用 XML 进行 CRUD

3.1 查询数据(<select>)

使用 xml 操作数据库, 不再使用注解定义 SQL, 而是在标签中定义 SQL.

在接口中声明方法, alt + 回车, MyBatisX(插件) 会根据方法的名称, 自动创建相应的标签(由于我的方法名为 selectAll, 所以生成的就是 <select> 标签), 接下来就可以在标签中定义查询相关的 SQL 语句:

其中, 标签中 id 属性的值, 就是对应的 Mapper 接口中方法的名称, 表示在调用该方法时, 执行标签中的 SQL 语句(将 SQL 和方法映射起来).

此外, select 标签中, 还有一个 resultType 属性, 表示查询结果集中, 每条记录的类型:
(只有 select 标签有这个属性, 因为只有查询操作才会返回结果集) 

 创建测试方法, 执行观察结果:

3.1.1 <resultMap> 标签

在上篇博客中讲到, 对于注解, 如果要实现 Java 属性和数据库字段的映射, 有三种方式:

  1. 数据库字段起别名
  2. @Results 注解
  3. 配置驼峰转换

对于 XML 来讲, 第一种和第三种同样适用. 由于我在上篇博客中已经进行了 驼峰转换 的配置, 因此在上文的 select 查询中, 数据库字段和 Java 属性能够映射成功.

但是, @Results 对于 XML 就不适用了, 在 XML 中, 需要使用 <resultMap> 标签进行映射的绑定:

  1. 设置 type 属性, 表示和哪个 Java 类型中的属性进行映射关系的绑定
  2. <id> 子标签, 配置主键的映射关系
  3. <result> 子标签, 配置其他非主键字段的映射关系

子标签中的映射方式, 和 @Results 一模一样: property 表示 Java 属性名, column 表示数据库字段名.

并且, 对 <resultMap> 设置 id 属性, 将其他 select 标签的 resultMap 属性设置为该 id 值, 就可直接使用对应的 <resultMap> 中的映射关系:

这样配置后, 便将数据库字段和 Java 属性成功进行映射了:

注意: 

  1. 如果使用 <resultMap> 的方式进行映射绑定, 即使数据库字段和 Java 属性本来就能成功映射, 但是也建议在 <resultMap> 中将所有 Java 属性和数据库字段全部手动进行映射绑定一遍!!
  2. 使用 XML 传递参数的方式和使用注解传递参数的方式都是一样的, 在 SQL 中都是使用 #{} 接收.

3.2 插入数据(<insert>)

给方法传入一个对象, 将对象中的一些属性值作为插入值, 插入表中:

同样, 若对象使用 @Param 进行重命名, SQL 中的 #{} 依旧需要使用 对象名.属性 的形式来声明参数:

此外, insert 标签中, 同样也是设置 useGenerateKey = true 和 keyProperty = "Java 属性" 的方式来获取新增记录的主键:

3.3 更新数据(<update>)

通过 XML 更新数据, 使用 <update> 标签.

3.4 删除数据(<delete>)

通过 MyBatis 使用 XML 删除数据库表中的记录, 使用 <delete> 标签.


4. 其它查询

4.1 联合查询

4.1.1 准备工作

联合查询需要用到多个表, 我们再创建一个 article_info 表, 并插入数据:

-- 创建文章表
DROP TABLE IF EXISTS article_info;
        
CREATE TABLE article_info (
        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 now(),
        update_time DATETIME DEFAULT now() 
) DEFAULT charset 'utf8mb4';

-- 插入测试数据
INSERT INTO article_info ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );

 并且, 创建一个 Java 类和表中字段相映射:

4.1.2 执行查询

联合查询虽然使用了多个表, 但其本质仍然是 select 语句, 我们直接在 <select> 标签中定义 SQL 即可.

将 article_info 和 user_info 两表联合查询, 以 article_info 为基准(左外连接), 联合查询 article_info 中 id = 1, 并且 article_info.uid = user_info.id 的记录:

观察结果, 查询成功: 

注意: 由于此时是联合查询, 定义 SQL 时, 额外接收了一个 user_info 表中的 username 字段, 因此, 我们需要在 ArticleInfo 类中多定义一个 username 属性, 以便将查询结果中的该字段映射到 Java 属性中:

注意: 由于联合查询时的 SQL 为 慢 SQL, 效率极低, 因此在实际工作中要避免使用多表联合查询!!

当查询的数据需要结合多张表时, 应先查询一个表的数据, 再根据得到的数据去查第二个表:

4.2 #{} 和 ${}

#{} 和 ${} 之间, 有三大主要区别:

  1. #{} 为预编译 sql, 提前预留参数位置, 自动识别参数类型, 性能更好.
  2. ${} 为即时 sql, 直接拼接参数.
  3. 由于 ${} 是直接拼接的方式, 如果参数是 String 类型, 需要手动加单引号, 因此存在 SQL 注入的安全问题. 而 #{} 可以自动识别参数类型, 无需加引号, 不存在 SQL 注入问题.

因此, 可以用 #{}, 就用 #{}!!

4.2.1 预编译 SQL, 即时 SQL

我们先将 @Select 注解中的 #{} 修改为 ${}, 观察执行结果:

观察日志发现, #{} 没有直接将参数传入 SQL 中, 而是使用占位符(?)进行占位; 而 ${} 是直接将参数拼接到了 SQL 中.

使用 ${} 传递字符串类型的参数, 继续观察效果:

 我们发现, 程序报错了. 其实原因就是: #{} 是将参数传入 SQL 的占位符中, 而 ${} 是直接将参数拼接到了 SQL 中.

${} 直接将参数拼接到了 SQL 中, 由于没有给字符串类型的参数加引号, 从而导致了 SQL 语法错误:

#{} 可以进行自动类型转换, 自动为字符串类型的参数加引号:

因此, 如果要使用 ${} 传递字符串类型的参数, 需要对 ${} 外手动加上单引号, 以便 MySQL 识别其为一个字符串:

导致以上情况的原因, 就是因为使用 #{} 的 SQL 为预编译 SQL, 使用占位符将参数的位置提前预留好, 收到参数后放入占位符中, 可以对参数自动进行类型转换, 无需手动加引号.

使用 ${} 的 SQL 为 即时 SQL, 采取直接拼接的方式拼接进 SQL 中, 若拼接的是字符串类型, 需要手动加引号.

此外, 由于 #{} 是预编译 SQL, 为参数进行了占位, 因此, MyBatis 会对参数之外的 SQL 进行缓存, 只需关注参数的变化, 根据传入参数的不同加载参数的变化即可, 不需加载参数之外的 SQL, 性能更高.

而 ${} 是即时 SQL, 不管 SQL 发生了什么变化, 每次都会重新加载整个 SQL, 因此性能较低.

 4.2.2 ${}: 存在 SQL 注入!!

上文提到的预编译 SQL 也好, 性能高也好, 其实都不是选择 #{} 作为首选的主要原因.

选择 #{} 而不选择 ${} 主要原因是:

  1. #{} 不存在 SQL 注入问题, 安全.
  2. ${} 由于其需要手动添加引号, 导致其有 SQL 注入的安全问题.

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

由于没有对用户输入的值进行充分检查, 而 SQL 又是拼接而成, 在用户输入参数时, 在参数中添加⼀些 SQL 关键字, 达到改变 SQL 运行结果的目的, 完成恶意攻击. 

${} 被 SQL 注入的示例如下:

 如上图所示, 攻击人利用 ${} 拼接参数的漏洞, 操作参数信息, 编写 1 = '1' 恒为 true 的 SQL, 导致所有人的信息都被泄露. 

SQL 注入常用于登录界面, 在不知道用户密码的情况下, 利用 SQL 注入, 实现成功登录.

而如果我们使用的是 #{} 进行参数传递, 那么 MyBatis 就会将攻击人编写的所有内容当做参数传入 SQL 中, 不会改变原本 SQL 的结构:

注意:

并非使用 ${} 就出现 SQL 注入问题, 还要结合代码分析, 如果代码进行了处理, 也是可以避免 SQL 注入的.

比如上例, 根据用户名和密码查询用户信息时, 我们可以设置查询结果只能是一条记录, 不能是多条记录, 即: 将返回值 List<UserInfo> 改为 UserInfo.

4.3 排序功能

上文说到, 为了避免 SQL 注入, 在能使用 #{} 的情况下, 尽量使用 #{}.

但是, 在传入某些特定参数时, 必须使用 ${} 才能完成相关操作, 比如: 排序功能.

我们先来看查询排序时正确 SQL :

接下来, 通过 MyBatis 进行排序查询操作. 

当使用 #{} 来传递排序规则的参数(desc/asc)时, 由于在 Java 中, 参数只能通过 String 类型来传入, 所以 MyBatis 会自动给 #{} 中的参数添加单引号(desc => 'desc'), 而正确的 SQL 中此处不应该有引号, 因此导致 SQL 语法错误:

${} 采用直接拼接参数的方式, 不会给参数加引号, 所以, 当实现排序功能时, 必须使用 ${} 进行参数传递:

虽然, 使用 ${} 可能具有 SQL 注入的风险, 但是我们可以通过代码进行校验, 在参数进入 Dao 层之前, 将 SQL 注入的风险排除掉即可. 如上例: 由于排序规则的参数只有 desc 和 asc 两个, 所以我们可以将传入的参数设为枚举类型, 对参数的值进行限制.

4.4 like 模糊查询

先来回顾下 like 查询的语法:

除了排序查询不能使用 #{} 外, like 查询也不能使用 #{} 来传递模糊参数. 如上图, 模糊参数为 "186", 不能将 % 传入到参数中:

此时, ${} 也能够完成: 

但是, 由于此时模糊参数的值是没有限制的, 不能通过设置枚举来校验, 因此, 我们不使用 ${} 来传递模糊参数, 而是使用 MySQL 的内置函数 --- CONCAT(), 进行字符串拼接.

因此, 通过 MyBatis , 在注解中使用 concat 进行字符串拼接, 进行模糊查询:

不仅排序查询和模糊查询传参时不能使用 #{}, 如果传入的是一些非字符串类型的参数(String 类型的参数到 SQL 中, 会自动加上单引号), 也不能使用 #{} 进行传递, 例如: 列名, 表名.

5. 数据库连接池

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

当需要与数据库建立连接时, 直接从连接池获取 Connection 对象即可, 当执行完毕后, 再将 Connection 放回连接池. 而不需像 jdbc 中频繁的获取和释放连接, 造成资源的消耗.

因此, 数据库连接池的优点如下:

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

常见的数据库连接池如下:

  1. C3P0
  2. DBCP
  3. Druid (流行)
  4. Hikari (流行)

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

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

Hikari 和 Druid 的性能不分伯仲.

如果想更换数据库连接池为 Druid, 引入 Druid 依赖即可:

// SpringBoot 3.x 版本
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-3-starter</artifactId>
    <version>1.2.21</version>
</dependency>
// SpringBoot 2.x 版本
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.17</version>
</dependency>

6. MySQL 开发规范

  1. 表名采用蛇形形式命名, 单词一律小写.(MySQL 在 Windows 下不区分大小写, 但在 Linux 下默认区分大小写, 因此一律采用小写)
  2. select 时, 不使用 * 作为查询列表字段
  3. 表必备三字段: id, create_time, update_time

END 

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

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

相关文章

牛客python蓝桥杯11-32(自用)

11 import os import sysdef huiwen(str):length len(str)# if length 0:# return -1result []for i in range(length-1): # 0 - length-2for j in range(i2,length1):# 取出从索引 i 到 j-1 的子串s str[i:j]# 正序倒序if s s[::-1]:result.append(len(s))if result…

rabbitmq版本升级并部署高可用

RabbitMQ版本升级 先检查是否已经安装rabbitmq rpm -qa|grep rabbitmq|wc -l //如果结果是0&#xff0c;表示没有安装 rpm -e --nodeps $(rpm -qa|grep rabbitmq) //如安装了&#xff0c;则进行卸载 先检查是否已经安装erlang rpm -qa|grep erlang|wc -l //如果结果…

数据集路径出错.yaml‘ images not found , missing path

方法一&#xff1a;删除settings.yaml 方法二&#xff1a;dataset_name.yaml改用绝对路径&#xff0c;如最后一张图 错误分析&#xff1a; dataset_name.yaml中的path的路径仅支持绝对路径&#xff0c;写相对路径就会搜索不到&#xff0c;使用settings.json中的路径&#xff0…

win32汇编环境,对话框中使用树形视图示例二

;运行效果 ;win32汇编环境,对话框中使用树形视图示例二 ;得到树形视图控件Treeview的全路径字符串,这里的方法是由子项向父项挨个找的算法找齐路径 ;直接抄进RadAsm可编译运行。重要部分加备注。 ;下面为asm文件 ;>>>>>>>>>>>>>>&g…

【连珠云弈】网页五子棋版项目测试报告

目录 一、项目背景 1.1、项目起源 1.2、市场需求 1.3、项目目标 二、项目功能 2.1 用户管理功能 2.2 游戏对战功能 三、测试报告 3.1.功能测试 ​编辑 3.1.1注册功能测试 解决bug&#xff1a; 测试总结&#xff1a; 3.1.2登录功能测试 测试总结&#xff1a; 3.…

OpenCV计算摄影学(15)无缝克隆(Seamless Cloning)调整图像颜色的函数colorChange()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::colorChange 是 OpenCV 中用于调整图像颜色的函数。它允许你通过乘以不同的系数来独立地改变输入图像中红色、绿色和蓝色通道的强度&#xf…

AI视频领域的DeepSeek—阿里万相2.1图生视频

让我们一同深入探索万相 2.1 &#xff0c;本文不仅介绍其文生图和文生视频的使用秘籍&#xff0c;还将手把手教你如何利用它实现图生视频。 如下为生成的视频效果&#xff08;我录制的GIF动图&#xff09; 如下为输入的图片 目录 1.阿里巴巴全面开源旗下视频生成模型万相2.1模…

用Python分割并高效处理PDF大文件

在处理大型PDF文件时&#xff0c;将它们分解成更小、更易于管理的块通常是有益的。这个过程称为分区&#xff0c;它可以提高处理效率&#xff0c;并使分析或操作文档变得更容易。在本文中&#xff0c;我们将讨论如何使用Python和为Unstructured.io库将PDF文件划分为更小的部分。…

RabbitMQ知识点

1.为什么需要消息队列&#xff1f; RabbitMQ体系结构 操作001&#xff1a;RabbitMQ安装 二、安装 # 拉取镜像 docker pull rabbitmq:3.13-management ​ # -d 参数&#xff1a;后台运行 Docker 容器 # --name 参数&#xff1a;设置容器名称 # -p 参数&#xff1a;映射端口号&…

2025-03-06 学习记录--C/C++-PTA 习题6-6 使用函数输出一个整数的逆序数

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h>int reverse( int number );int main…

力扣132. 分割回文串 II

力扣132. 分割回文串 II 题目 题目解析及思路 题目要求返回将s切割成若干回文串的最少切割次数 对于子串s[j...i]&#xff0c;若为回文串&#xff0c;则问题变为求s[0...j]的最少切割次数 因此可以考虑动态规划 对于问题s[j...i]是否为回文串&#xff0c;若s[i] s[j]则问…

调研:如何实现智能分析助手(Agent)(AutoCoder、FastGPT、AutoGen、DataCopilot)

文章目录 调研&#xff1a;如何实现智能分析助手&#xff08;Agent&#xff09;&#xff08;AutoCoder、FastGPT、AutoGen、DataCopilot&#xff09;一、交互流程二、数据流程三、架构分类四、开源产品4.1 AutoCoder&#xff08;知识库变体&#xff09;4.2 FastGPT&#xff08;…

学习使用ESP8266进行MQTT通信并在网页上可视化显示

目录 一、工具 二、 流程 三、代码实现 设置MQTT服务器地址 设置服务器和端口号 连接MQTT服务器并订阅话题 回调处理函数 发布数据到话题 四、调试软件使用 打开MQTTx 添加话题 五、网页使用 一、工具 arduino ide esp8266/32单片机 lot物联网网页 MQTTx软件或者m…

mysql进阶(三)

MySQL架构和存储引擎 1. MySQL架构 MySQL8.0服务器是由连接池、服务管理⼯具和公共组件、NoSQL接⼝、SQL接⼝、解析器、优化 器、缓存、存储引擎、⽂件系统组成。MySQL还为各种编程语⾔提供了⼀套⽤于外部程序访问服务器 的连接器。整体架构图如下所⽰&#xff1a; 2. 连接层 …

【MYSQL数据库异常处理】执行SQL语句报超时异常

MYSQL执行SQL语句异常&#xff1a;The last packet successfully received from the server was 100,107 milliseconds ago. The last packet sent successfully to the server was 100,101 milliseconds ago. 这个错误表明 MySQL 服务器与 JDBC 连接之间的通信超时了。通常由…

深入理解三色标记、CMS、G1垃圾回收器

三色标记算法 简介 三色标记算法是一种常见的垃圾收集的标记算法&#xff0c;属于根可达算法的一个分支&#xff0c;垃圾收集器CMS&#xff0c;G1在标记垃圾过程中就使用该算法 三色标记法&#xff08;Tri-color Marking&#xff09;是垃圾回收中用于并发标记存活对象的核心算…

60页PDF | 四川电信数据湖及数据中台实施方案!(附下载)

一、前言 这份报告是关于四川电信数据湖与数据中台实施方案的详细规划。报告从数据驱动、事件管理、数据湖构建、数据资产管理和数据治理等多个方面展开&#xff0c;介绍了如何通过数据湖与数据中台的建设&#xff0c;实现数据的高效采集、存储、分析与共享&#xff0c;提升数…

短分享-Flink图构建

一、背景 通过简单的书写map、union、keyby等代码&#xff0c;Flink便能构建起一个庞大的分布式计算任务&#xff0c;Flink如何实现的这个酷炫功能呢&#xff1f;我们本次分享Flink做的第一步&#xff0c;将代码解析构建成图 源码基于Flink 2.10&#xff0c;书籍参考《Flink核…

java常见的几种并发安全问题及解决方案

项目场景&#xff1a; 并发的应用场景&#xff0c;在开发过程会经常遇到。 例如&#xff1a;服务应用启动后&#xff0c;需要简单统计接口的总访问量&#xff1b;实时更新订单状态&#xff0c;成交总额。 问题描述&#xff1a; 比如统计接口访问次数&#xff0c;如下的实现&a…

【mysql系】mysql启动异常Can‘t create test file localhost.lower-test

1.查看通过下面命令获取对应mysql配置文件 whereis my.cnf 2.查看日志文件 下面这里是对应的错误日志 2025-03-03T06:33:56.402057Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see …