第三阶段-03MyBatis 中使用XML映射文件详解
MyBatis 中使用XML映射文件
什么是XML映射
使用注解的映射SQL的问题:
- 长SQL需要折行,不方便维护
- 动态SQL查询拼接复杂
- 源代码中的SQL,不方便与DBA协作
MyBatis建议使用XML文件映射SQL才能最大化发挥MySQL的功能
- 统一管理SQL, 方便协作
- 不需要 “ ” + 等语法,方便“长”SQL
- 方便处理动态SQL连接
参考连接: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html
HelloWorld
开发步骤:
- 创建项目(不要使用Spring Boot 3!), 选择依赖:

-
配置application.properties, 设置数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/bootdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true spring.datasource.username=root spring.datasource.password=root# 设定 mapper xml 文件的位置, classpath 就是指 resources 位置 mybatis.mapper-locations=classpath:mappers/*.xml # 查看MyBatis执行的SQL logging.level.cn.tedu.boot2209.mapper=debug -
创建文件夹 /resources/mappers
-
添加一个XML文件,文件从doc.canglaoshi.org 下载
-
改名为 DemoMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- namespace 的值设定为被映射的包名.类名 --> <mapper namespace="cn.tedu.boot2209.mapper.DemoMapper"><!-- select 元素用于映射查询语句到方法,id值必须和mapper接口中的方法名一致!需要设定返回值类型resultType,类型与方法返回值类型一致select 元素中定义SQL,SQL查询结果将自动映射到方法返回值, 不要使用分号结尾!!--><select id="hello" resultType="java.lang.String">SELECT 'Hello World!'</select> </mapper>
-
-
创建mapper.DemoMapper接口:
- 接口名和 xml文件的namespace 一致
- 方法名和xml文件的select元素的id一致
- 方法返回值类型和 resultType 的值一致
/*** 编写Mapper接口,用于映射SQL语句*/ @Mapper public interface DemoMapper {String hello(); } -
编写MyBatis配置文件 config.MyBatisConfig
- 包名、文件名,没有限制!
- 文件中使用 MapprScan 扫描 Mapper包:
/*** 创建一个配置文件,MyBatisConfig* 在配置文件中,启动Mapper接口扫描功能* Mapper 接口扫描功能会自动创建 Mapper接口的实现对象(使用的JDK动态代理技术)*/ @MapperScan(basePackages = "cn.tedu.boot2209.mapper") @Configuration public class MyBatisConfig { } -
测试案例: 测试结果说明,SQL被执行了,方法返回了SQL语句的结果
@SpringBootTest public class DemoMapperTests {@AutowiredDemoMapper demoMapper;@Testvoid test(){String str = demoMapper.hello();System.out.println(str);} }
Spring Boot 中的配置类(配置文件)
@Configuration 用于声明新的配置文件类。
Spring Boot 中的主配置文件,就是Spring Boot 的启动类,可以作为配置文件使用。如果将全部配置信息放到主配置文件,就会很混乱。一般在开发中,将配置文件分开放置,相关的放到一起。
- MyBatis 放到一个文件中
- 安全配置放到一个文件中
- … …
创建一个配置包 config 管理全部的配置,然后创建MyBatis的配置类, 配置类需要标注 @Configuration
/*** 创建一个配置文件,MyBatisConfig* 在配置文件中,启动Mapper接口扫描功能* Mapper 接口扫描功能会自动创建 Mapper接口的实现对象(使用的JDK动态代理技术)*/
@MapperScan(basePackages = "cn.tedu.boot2209.mapper")
@Configuration
public class MyBatisConfig {
}
MyBatis XML映射文件工作原理

关于XML语法:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.tedu.boot2209.mapper.ProductMapper"><select id="countProduct" resultType="java.lang.Integer">SELECT COUNT(*) FROM product</select>
</mapper>
- 处理节点:
<?xml version="1.0" encoding="UTF-8" ?>从来没有变过!- 可以省略,但是不建议省略!
- 文档定义: ”DOCTYPE“ 用于约定XML文件中的 元素、属性、嵌套关系
- 可以约束标签和属性
- 标签/标记:
<mapper>- 必须成对使用,有开启标签就必须结束标签:
<mapper></mapper>
- 必须成对使用,有开启标签就必须结束标签:
- 开始标签上可以定义属性:
id="countProduct"- 属性名不可以重复,属性无顺序
- XML文件只能有唯一的根元素!!!
- XML 可扩展的标记语言:
- 标签可以任意名称,标签名可以扩展
- 标签嵌套关系可以扩展,标签可以任意嵌套
- 属性可以扩展
- XML 中大小写敏感,不同!
有参数的查询
处理一个参数查询
例子:
SELECT count(*) FROM product WHERE price > ?

处理多个参数查询

处理实体类型返回值
使用 Product 实体类作为返回值, 在resultType上指定实体类型就可以了

desc product;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(50) | YES | | NULL | |
| price | double(10,2) | YES | | NULL | |
| num | int(11) | YES | | NULL | |
+-------+--------------+------+-----+---------+----------------+
定义实体类型 Product
/*** 产品实体类型*/
public class Product {private Integer id;private String title;private Double price;private Integer quantity; //数量public Product() {}public Product(Integer id, String title, Double price, Integer quantity) {this.id = id;this.title = title;this.price = price;this.quantity = quantity;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}public Integer getQuantity() {return quantity;}public void setQuantity(Integer quantity) {this.quantity = quantity;}@Overridepublic String toString() {return "Product{" +"id=" + id +", title='" + title + '\'' +", price=" + price +", quantity=" + quantity +'}';}
}
编写ProductMapper接口方法
/*** 根据ID返回一个对象*/
Product findById(Integer id);
编写映射文件 ProductMapper.xml
<select id="findById" resultType="cn.tedu.boot2209.entity.Product">SELECT id, title, price, num AS quantityFROM productWHERE id = #{id}
</select>
测试:ProductMapperTests
@Test
void findById(){Product product = productMapper.findById(4);System.out.println(product);
}
返回实体集合
在ProductMapper接口中添加方法:
/*** 返回一组实体对象* @param title %手机* @return 匹配的一组对象*/
List<Product> findByTitle(String title);
在 ProductMapper.xml 添加SQL语句:
<!-- 返回一组实体对象,必须有 resultType 值是返回集合中的元素类型-->
<select id="findByTitle" resultType="cn.tedu.boot2209.entity.Product">SELECT id, title, price, num AS quantityFROM productWHERE title LIKE #{title}
</select>
测试方法 ProductMapperTests
@Test
void findByTitle(){List<Product> products = productMapper.findByTitle("%手机");for (Product product : products){System.out.println(product);}
}
插入和更新
使用变量传递参数
参数少,没有问题,但是参数多了以后就麻烦了,书写繁琐复杂
插入数据SQL:
INSERT INTO product (id, title, price, num ) VALUES (null, ?, ? ,?)
ProductMapper接口:插入、更新、删除方法只有一个默认返回int值,表示SQL影响行数
Integer saveProduct(@Param("title") String title,@Param("price") Double price,@Param("quantity") Integer quantity);
在MyBatis ProductMapper.xml:
<!-- insert 插入语句不需要定义 resultType,默认就有int返回值 -->
<insert id="saveProduct">INSERT INTO product (id, title, price, num ) VALUES (null, #{title}, #{price}, #{quantity})
</insert>
测试:ProductMapperTests
@Test
void saveProduct(){Integer n = productMapper.saveProduct("大力手机", 2000.0, 100);System.out.println(n);
}
使用POJO对象打包传递参数
POJO 就是传统Java对象,实体对象 Product 对象就是 POJO。

使用POJO对象作为Mapper方法参数: ProductMapper, 无需定义@Parm
Integer saveProductItem(Product product);
MyBatis 自动将POJO对象的属性, 映射传递到 #{占位符}
<!-- MyMatis 会自动的将 product 的属性 映射到#{title}, #{price}, #{quantity}要求 #{title}, #{price}, #{quantity} 占位符必须和 product 的属性(getXXX)一致-->
<insert id="saveProductItem">INSERT INTO product (id, title, price, num ) VALUES (null, #{title}, #{price}, #{quantity})
</insert>
测试
@Test
void saveProductItem(){Product product = new Product(null, "大力手机", 2000.0, 100);Integer n = productMapper.saveProductItem(product);System.out.println(n);
}
返回自动增加的ID
使用POJO作为参数插入数据时候,可以返回自增的ID:
- useGeneratedKeys=“true” 使用生成的key
- keyProperty=“id” key 的属性名
<!-- useGeneratedKeys="true" 使用生成的keykeyProperty="id" key 的属性名 -->
<insert id="saveProductItem" useGeneratedKeys="true" keyProperty="id">INSERT INTO product (id, title, price, num)VALUES (null, #{title}, #{price}, #{quantity})
</insert>
测试:
@Test
void saveProductItem(){Product product = new Product(null, "他的手机", 3000.0, 100);Integer n = productMapper.saveProductItem(product);System.out.println(n);System.out.println(product); //输出刚刚生成的 ID
}
更新数据 update
更新数据 SQL, 更新一行的全部数据:
UPDATE product SET title=?, price=?, num=? WHERE id=?
ProductMapper接口:
Integer updateProduct(Product product);
ProductMapper.xml:
<update id="updateProduct">UPDATE product SET title=#{title}, price=#{price}, num=#{quantity} WHERE id=#{id}
</update>
测试:
@Test
void updateProduct(){Product product = new Product(12, "老虎的手机", 100.99, 10);Integer num = productMapper.updateProduct(product);System.out.println(product);System.out.println(num);
}
MyBatis 动态SQL拼接
根据参加参数条件动态生成SQL,提示SQL效率。
动态SQL标签: if choose when for 等
/*** 动态SQL更新* @param product* @return*/
Integer updateProductPart(Product product);
XML:
<!-- 检查参数,动态拼接SQL -->
<!-- test="title != null" 检查title不为空,这拼接一段SQL title=#{title}<set> 标签会自动删除多余的逗号 -->
<update id="updateProductPart">UPDATE product<set><if test="title != null">title=#{title},</if><if test="price != null">price=#{price},</if><if test="quantity != null">num=#{quantity}</if></set>WHERE id = #{id}
</update>
测试:
@Test
void updateProductPart(){Product product = new Product(10, null, 1500.0, null);Integer num = productMapper.updateProductPart(product);System.out.println(product);System.out.println(num);//一定要检查 SQL 处理结果!不是1,就是更新失败!!
}
相关文章:
第三阶段-03MyBatis 中使用XML映射文件详解
MyBatis 中使用XML映射文件 什么是XML映射 使用注解的映射SQL的问题: 长SQL需要折行,不方便维护动态SQL查询拼接复杂源代码中的SQL,不方便与DBA协作 MyBatis建议使用XML文件映射SQL才能最大化发挥MySQL的功能 统一管理SQL, 方…...
从0开始学python -41
Python3 命名空间和作用域 命名空间 先看看官方文档的一段话: A namespace is a mapping from names to objects.Most namespaces are currently implemented as Python dictionaries。 命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是…...
如何将Google浏览器安装到D盘(内含教学视频)
如何将Google浏览器安装到D盘(内含教学视频) 教学视频下载链接地址:https://download.csdn.net/download/weixin_46411355/87503968 目录如何将Google浏览器安装到D盘(内含教学视频)教学视频下载链接地址:…...
三战阿里测试岗,成功上岸,面试才是测试员涨薪真正的拦路虎...
第一次面试阿里记得是挂在技术面上,当时也是技术不扎实,准备的不充分,面试官出的面试题确实把我问的一头雾水,还没结束我就已经知道我挂了这次面试。 第二次面试,我准备的特别充分,提前刷了半个月的面试题…...
Java代码弱点与修复之——ORM persistence error(对象关系映射持久错误)
弱点描述 ORM persistence error, ORM 持久化错误 。表示 ORM 工具在尝试将对象保存到数据库中时出现了问题。可能的原因包括: 数据库连接错误:ORM 工具无法连接到数据库,或者连接到数据库的权限不足。数据库表结构错误:ORM 工具无法正确映射对象和数据库表之间的关系,可…...
原始GAN-pytorch-生成MNIST数据集(原理)
文章目录1. GAN 《Generative Adversarial Nets》1.1 相关概念1.2 公式理解1.3 图片理解1.4 熵、交叉熵、KL散度、JS散度1.5 其他相关(正在补充!)1. GAN 《Generative Adversarial Nets》 Ian J. Goodfellow, Jean Pouget-Abadie, Yoshua Be…...
Vue下载安装步骤的详细教程(亲测有效) 1
目录 一、【准备工作】nodejs下载安装(npm环境) 1 下载安装nodejs 2 查看环境变量是否添加成功 3、验证是否安装成功 4、修改模块下载位置 (1)查看npm默认存放位置 (2)在 nodejs 安装目录下,创建 “node_global…...
[Android Studio] Android Studio生成数字证书,为应用签名
🟧🟨🟩🟦🟪 Android Debug🟧🟨🟩🟦🟪 Topic 发布安卓学习过程中遇到问题解决过程,希望我的解决方案可以对小伙伴们有帮助。 📋笔记目…...
应用IC 卡继续教育网络管理系统前后影响因素比较
3.1 实现了继续护理教育网络化管理近年来,随着一些医院继续护理教育管理信息系统的建立,有效改进了学分档案管理模式和教学模式,但这些继续护理教育管理信息系统一般为局域网,仅能达到满足自身管理的基本需求,而系统如…...
Clickhouse学习(一):MergeTree概述
MergeTree一、Clickhouse表引擎概述二、MergeTree表引擎<一>、ReplacingMergeTree引擎<二>、SummingMergeTree引擎<三>、AggregatingMergeTree引擎三、MergeTree分区一、Clickhouse表引擎概述 MergeTree表引擎:允许根据日期和主键创建索引 1、ReplacingMerge…...
Windows离线安装rust
目前rust安装常用的方式就是通过Rustup安装,此安装方式需要访问互联网。在生产环境中由于网络限制,不能直接访问互联网或者不能访问目标网站,这时候需要用离线安装的方式,本文将详细介绍离线安装步骤,并给出了vscode如…...
Android与flutter混合开发
这里我使用的android studio版本是2020.3.1;flutter版本2.5.3。此前在网上搜索的很多教教程版本都不一样,新版的IDE和SDK让我遇到了很多坑故这里整理一下。一、创建项目1.在Android项目中点击File->New->New Flutter Project。File->New->Ne…...
Linux和C语言的学习方法你真的知道吗?
★Linux的使用 第一天,就给我们讲了为什么要先学c、学linux:因为嵌入式的根本就是软件驱动硬件,而C语言是最接近硬件的语言、有指针的概念、可以直接操作硬件,另外,功能复杂的硬件是含有操作系统的,这就需…...
代码随想录day42
1049. 最后一块石头的重量 II https://leetcode.cn/problems/last-stone-weight-ii/ 这个自己还是没想出来01背包对应。 本题其实就是尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。 stones [2,7,4,1,8,1]也就是sum…...
【笔记】两台1200PLC进行S7 通信(1)
使用两台1200系列PLC进行S7通信(入门) 文章目录 目录 文章目录 前言 一、通信 1.概念 2.PLC通信 1.串口 2.网口 …...
统一网关Gateway
为什么需要网关 网关功能: 身份认证和权限校验服务路由,负载均衡 根据请求判断找到对应的服务路由,然后服务可能有多个实例,这个时候网关就会做一个负载均衡去挑选一个实例调用.请求限流 限制请求的数量,这是微服务的…...
6、kubernetes(k8s)安装
本文内容以语雀为准 文档 等等,Docker 被 Kubernetes 弃用了?容器运行时端口和协议kubeadm initkubeadm config安装网络策略驱动使用 kubeadm 创建集群 控制平面节点隔离 持久卷为容器设置环境变量在CentOS上安装Docker引擎Pod 网络无法访问排查处理 说明 本文…...
python-批量下载某短视频平台音视频标题、评论、点赞数
python-批量下载某短视频平台音视频标题、评论数、点赞数前言一、获取单个视频信息1、获取视频 url2、发送请求3、数据解析二、批量获取数据1、批量导入地址2、批量导出excel文件3、批量存入mysql数据库三、完整代码前言 1、Cookie中文名称为小型文本文件,指某些网…...
【数据结构与算法】单链表的增删查改(附源码)
这么可爱的猫猫不值得点个赞吗😽😻 目录 一.链表的概念和结构 二.单链表的逻辑结构和物理结构 1.逻辑结构 2.物理结构 三.结构体的定义 四.增加 1.尾插 SListpushback 2.头插 SListpushfront 五.删除 1.尾删 SListpopback 2.头删 SListpo…...
华为OD机试 - 回文字符串
题目描述 如果一个字符串正读和反渎都一样(大小写敏感),则称它为一个「回文串」,例如: leVel是一个「回文串」,因为它的正读和反读都是leVel;同理a也是「回文串」art不是一个「回文串」,因为它的反读tra与正读不同Level不是一个「回文串」,因为它的反读leveL与正读不…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...
Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...
