Spring Boot 如何集成 MyBatis 进行数据库访问?

大家好,我是磊磊落落,目前我在技术上主要关注:Java、Golang、架构设计、云原生和自动化测试。欢迎来我的博客(leileiluoluo.com)获取我的最近更新!

本文原始链接:https://leileiluoluo.com/posts/spring-boot-mybatis-integration.html

MyBatis 是一个适用于 Java 语言的持久层框架。MyBatis 支持以注解或 XML 配置的方式来定义 SQL 查询,以及查询结果和 Java 对象的映射。MyBatis 相比于 Java 另一个流行持久层框架 JPA 来说(具体使用请参看「如何使用 Spring Data JPA 进行数据库访问?
」),最大的特点是 MyBatis 具有更灵活的 SQL 控制能力。

本文以一个使用 Maven 管理的 Spring Boot 工程为例,结合本地搭建的 MySQL 数据库(版本为 8.1.0)来演示 Spring Boot 与 MyBatis 的集成。

下面列出示例工程所使用的 JDK、Maven、Spring Boot 与 MyBatis Starter 的版本:

JDK:Amazon Corretto 17.0.8
Maven:3.9.2
Spring Boot:3.2.3
Mybatis Spring Boot Starter:3.0.3

接下来,我们以实现 User 的增、删、改、查为例来探索 MyBatis 的使用。

1 准备测试数据

首先,在本地 MySQL 数据库执行如下 SQL 来创建一个测试数据库、创建一个 user 表,并在 user 表插入 3 条测试数据:

CREATE DATABASE test DEFAULT CHARSET utf8 COLLATE utf8_general_ci;DROP TABLE IF EXISTS user;
CREATE TABLE user (id BIGINT AUTO_INCREMENT PRIMARY KEY,email VARCHAR(100) NOT NULL,name VARCHAR(100) NOT NULL,role ENUM('ADMIN', 'EDITOR', 'VIEWER') DEFAULT 'VIEWER',description VARCHAR(300) NOT NULL,created_at TIMESTAMP NOT NULL DEFAULT '2024-01-01 00:00:00',updated_at TIMESTAMP NOT NULL DEFAULT '2024-01-01 00:00:00',deleted BOOLEAN DEFAULT FALSE
);INSERT INTO user(email, name, role, description, created_at, updated_at, deleted) VALUES('larry@larry.com', 'Larry', 'ADMIN', 'I am Larry', '2024-01-01 08:00:00', '2024-01-01 08:00:00', false),('jacky@jacky.com', 'Jacky', 'EDITOR', 'I am Jacky', '2024-02-01 08:00:00', '2024-02-01 08:00:00', false),('lucy@lucy.com', 'Lucy', 'VIEWER', 'I am Lucy', '2024-03-01 08:00:00', '2024-03-01 08:00:00', false);

2 开始使用 MyBatis

测试数据准备好后,即可以尝试使用 MyBatis 了。

2.1 POM 依赖项

如下为本文示例工程 pom.xml 的配置信息:

<!-- pom.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.3</version><relativePath/></parent><groupId>com.example</groupId><artifactId>spring-boot-mybatis-integration-demo</artifactId><version>0.0.1-SNAPSHOT</version><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.3.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version></dependency><!-- testing --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.10.2</version><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>17</source><target>17</target></configuration></plugin></plugins></build>
</project>

可以看到,本工程基于 Java 17,使用的 Spring Boot 版本为 3.2.3,用到的依赖有 spring-boot-starter-webmybatis-spring-boot-startermysql-connector-jlombok

2.2 application.yaml 配置

如下为 application.yaml 文件的配置信息:

# src/main/resources/application.xml
spring:datasource:url: jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8username: rootpassword: root
mybatis:mapper-locations: classpath:mapper/*Mapper.xml
logging:level:com.example.demo.dao.UserDaoMapper: DEBUG

可以看到,我们使用了 Spring Boot 的标准配置方式来指定数据库的连接信息。针对 MyBatis 的配置部分,我们使用 mybatis.mapper-locations 指定了 MyBatis Mapper 文件的路径。此外,还将接下来要编写的 Mapper 接口的日志级别定义为了 DEBUG,以便在控制台打印对应的 SQL。

2.3 Java POJO 类

如下为 User Model 类的内容:

// src/main/java/com/example/demo/model/User.java
package com.example.demo.model;import lombok.Data;import java.util.Date;@Data
public class User {private Long id;private String email;private String name;private Role role;private String description;private Date createdAt;private Date updatedAt;private Boolean deleted;public enum Role {ADMIN,EDITOR,VIEWER}
}

可以看到,我们为数据库表 user 新建了对应的 Model 类 User.java,该类中各个字段的含义与类型与前面的建表语句一一对应。

2.4 Mapper 接口

接下来我们定义一个接口 UserDaoMapper.java,针对 User 的增、删、改、查方法均定义于其中:

// src/main/java/com/example/demo/dao/UserDaoMapper.java
package com.example.demo.dao;import com.example.demo.model.User;import java.util.List;public interface UserDaoMapper {List<User> list(int offset, int rows);long count();User getById(Long id);boolean existsByEmail(String email);List<User> searchByName(String name);void save(User user);void batchSave(List<User> users);void update(User user);void deleteById(Long id);
}

可以看到,我们针对 User 定义了分页列表查询(list)、总数查询(count)、单条查询(getById)、根据邮箱判断是否存在(existsByEmail)、根据名称搜索(searchByName)、批量保存(batchSave)、更新(update)、单条删除(deleteById)等各种常用方法。

2.5 Mapper XML 配置文件

下面即是本文最关键的部分,MyBatis Mapper 文件的配置。该文件用于配置上一部分 UserDaoMapper 接口中定义的各种方法的具体 SQL 语句以及接收查询结果的类型或对象。

UserDaoMapper.xml 的内容如下:

<!-- src/main/resources/mapper/UserDaoMapper.xml -->
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.UserDaoMapper"><sql id="insert_columns">email,name,role,description,created_at,updated_at,deleted</sql><sql id="select_columns">id,email,name,role,description,created_at as createdAt,updated_at as updatedAt,deleted</sql><select id="list" resultType="com.example.demo.model.User">SELECT<include refid="select_columns"/>FROM userWHERE deleted = falseORDER BY created_at DESCLIMIT #{offset}, #{rows}</select><select id="count" resultType="long">SELECTCOUNT(*)FROM userWHERE deleted = false</select><select id="getById" resultType="com.example.demo.model.User">SELECT<include refid="select_columns"/>FROM userWHERE deleted = falseAND id = #{id}</select><select id="existsByEmail" resultType="boolean">SELECTEXISTS (SELECT 1FROM userWHERE deleted = falseAND email = #{email})</select><select id="searchByName" resultType="com.example.demo.model.User">SELECT<include refid="select_columns"/>FROM userWHERE deleted = false<if test="name != null and name != ''">AND name LIKE CONCAT('%', #{name}, '%')</if></select><insert id="save" useGeneratedKeys="true" keyProperty="id">INSERT INTO user (<include refid="insert_columns"/>) VALUES (#{email},#{name},#{role},#{description},now(),now(),false)</insert><insert id="batchSave" useGeneratedKeys="true" keyProperty="id">INSERT INTO user (<include refid="insert_columns"/>) VALUES<foreach item="item" collection="list" separator=",">(#{item.email}, #{item.name}, #{item.role}, #{item.description}, now(), now(), false)</foreach></insert><update id="update">UPDATE userSETemail = #{email},name = #{name},role = #{role},description = #{description},updated_at = now()WHERE id = #{id}</update><delete id="deleteById">DELETEFROM userWHERE id = #{id}</delete>
</mapper>

可以看到,我们在该配置文件中使用 namespace 指定了其是 UserDaoMapper.java 的实现。且对接口中定义的增、删、改、查方法分别使用标签 <insert><delete><update><select> 定义了具体的 SQL 语句。对于这些 SQL 语句,我们使用 <sql> 来抽取了共用的片段。此外还使用了 <foreach><if> 标签。此外,对于插入与批量插入我们还使用对应的配置(useGeneratedKeys="true" keyProperty="id")实现了插入后自增 ID 的自动设置。

2.6 单元测试

到目前为止,我们的数据库连接配置、Model 类、查询接口、Mapper 配置均已编写好了。下面即对 UserDaoMapper 接口编写一个单元测试类来测试一下其功能:

// src/test/java/com/example/demo/dao/UserDaoMapperTest.java
package com.example.demo.dao;import com.example.demo.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
public class UserDaoMapperTest {@Autowiredprivate UserDaoMapper userDaoMapper;@Testpublic void testList() {List<User> users = userDaoMapper.list(2, 10);// assertionassertFalse(users.isEmpty());}@Testpublic void testCount() {long count = userDaoMapper.count();// assertionassertTrue(count > 0);}@Testpublic void testGetById() {User user = userDaoMapper.getById(1L);// assertionassertNotNull(user);}@Testpublic void testExistsByEmail() {boolean exists = userDaoMapper.existsByEmail("larry@larry.com");// assertionassertTrue(exists);}@Testpublic void testSearchByName() {List<User> users = userDaoMapper.searchByName("La");// assertionassertFalse(users.isEmpty());}@Testpublic void testSave() {User user = new User();user.setEmail("david@david.com");user.setName("David");user.setRole(User.Role.VIEWER);user.setDescription("I am David");// saveuserDaoMapper.save(user);// assertionassertNotNull(user.getId());}@Testpublic void testBatchSave() {User user1 = new User();user1.setEmail("ross@ross.com");user1.setName("Ross");user1.setRole(User.Role.EDITOR);user1.setDescription("I am Ross");User user2 = new User();user2.setEmail("linda@linda.com");user2.setName("Linda");user2.setRole(User.Role.VIEWER);user2.setDescription("I am Linda");List<User> users = List.of(user1, user2);// batch saveuserDaoMapper.batchSave(users);// assertionusers.forEach(user -> assertNotNull(user.getId()));}@Testpublic void testUpdate() {User user = userDaoMapper.getById(1L);user.setRole(User.Role.EDITOR);user.setDescription("Hello, I am Larry!");// updateuserDaoMapper.update(user);}@Testpublic void testDeleteById() {userDaoMapper.deleteById(1L);}
}

可以看到,UserDaoMapper 接口的各个方法提供的功能均运行正常,符合我们的预期。

综上,我们完成了 Spring Boot 与 MyBatis 的集成,了解了 MyBatis 基础功能的使用。完整示例工程已提交至本人 GitHub,欢迎关注或 Fork。

参考资料

[1] MyBatis 3 Reference Documentation - https://mybatis.org/mybatis-3/

[2] What is MyBatis-Spring-Boot-Starter? - https://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

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

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

相关文章

c/c++ 判断质数(素数)

目录 一.常规方法 二.进阶方法 三.代码示例&#xff08;运用进阶方法&#xff09; 质数是整数且仅能被自身和1整除 一.常规方法 所以我们根据质数的这个定义便可用以下思路判断&#xff1a;设需要检测的数为x。y为除1和自己的除数 逐步检测x是否可被y整除&#xff0c;如x…

Stable Diffusion详解

Stable Diffusion详解 一、Stable Diffusion简介 Stable Diffusion是一种生成对抗网络&#xff08;GAN&#xff09;的变体&#xff0c;专注于高质量图像生成。它利用扩散过程和去噪技术逐步生成图像&#xff0c;并且在各类图像生成任务中表现出色。本文将详细介绍Stable Diff…

MySQL之架构设计与历史(一)

架构设计与历史 概述 和其他数据库系统相比&#xff0c;MySQL有点与众不同&#xff0c;它的架构可以在多种不同场景中应用并发挥好的作用&#xff0c;但同时也会带来一点选择上的困难。MySQL并不完美&#xff0c;却足够灵活&#xff0c;能够适应高要求的环境&#xff0c;例如…

笔记:前端知识梳理

一、JavaScript ECMAScript&#xff1a;脚本语言的标准&#xff0c;不同版本的标准称为ESx&#xff0c;如&#xff1a;ES5、ES6。 JavaScript&#xff1a;对ES标准的一种实现&#xff0c;ES标准的其他实现还有JScript。 JavaScript引擎&#xff1a;让JavaScript能够在目标机器…

Android 逆向学习【1】——版本/体系结构/代码学习

#Android 历史版本 参考链接&#xff1a;一篇文章让你了解Android各个版本的历程 - 知乎 (zhihu.com) 三个部分&#xff1a;api等级、版本号、代号&#xff08;这三个东西都是指的同一个系统&#xff09; API等级&#xff1a;在APP开发的时候写在清单列表里面的 版本号&…

Vitis HLS 学习笔记--控制驱动TLP - Dataflow视图

目录 1. 简介 2. 功能特性 2.1 Dataflow Viewer 的功能 2.2 Dataflow 和 Pipeline 的区别 3. 具体演示 4. 总结 1. 简介 Dataflow视图&#xff0c;即数据流查看器。 DATAFLOW优化属于一种动态优化过程&#xff0c;其完整性依赖于与RTL协同仿真的完成。因此&#xff0c;…

力扣第206题-反转链表

反转链表的效果示意图 要改变链表结构时&#xff0c;通常加入一个创建的临时头结点会更容易操作 时间复杂度&#xff1a;遍历2遍&#xff0c;2n 空间复杂度&#xff1a;额外创建一个栈&#xff0c;n (空间创建一个数组长度最大为5000&#xff0c;你说这个数组是栈也可以&…

【C++】详解多态

目录 初识多态 多态的条件 接口继承和实现继承 override 和 final 多态原理 继承与虚函数表 析构函数与多态 抽象类 本篇内容关联知识的链接 【C】详解C的继承-CSDN博客 【C】详解C的模板-CSDN博客 【C】C的内存管理-CSDN博客 初识多态 父类被不同子类继承后&#…

代码随想录算法训练营Day47 | 198.打家劫舍 213.打家劫舍II 337.打家劫舍III

代码随想录算法训练营Day47 | 198.打家劫舍 213.打家劫舍II 337.打家劫舍III LeetCode 198.打家劫舍 题目链接&#xff1a;LeetCode 198.打家劫舍 思路&#xff1a; 当前打劫或者不打劫 class Solution { public:int rob(vector<int>& nums) {vector<int>…

基于时频模糊算子的数据增强方法

关键词&#xff1a;时频模糊&#xff0c;数据增强&#xff0c;机器学习&#xff0c;音频预处理 我们引入时频模糊算子&#xff0c;该算子将信号的短时傅里叶变换与指定的核进行卷积&#xff0c;在SpeechCommands V2数据集上训练了一个使用ResNet-34架构的卷积神经网络(CNN)和一…

vscode C++调试设置

cmakelist需要改成set(CMAKE_BUILD_TYPE "Debug") 如果有set(CMAKE_CXX_FLAGS "-O0 -g3 -stdliblibstdc -no-pie -pthread -Wall -D_GLIBCXX_USE_NANOSLEEP -DLINUX")//"-O0优化项目改成0&#xff0c;否者-O2/3部分编译优化后打不了断点 然后创建la…

freertos的信号量和互斥锁学习笔记

freertos的信号量和互斥锁有两个比较形象的例子可以解释两者的主要用途。 第一个是信号量&#xff1a; 使用信号量的最初目的是为了给共享 资源建立一个标志&#xff0c;该标志表示该共享资源被占用情况。这样&#xff0c;当一个任务在访问共享资源之前&#xff0c;可以先对这…

【MySQL精通之路】InnoDB(6)-磁盘结构(4)-双写缓冲区

主博客&#xff1a; 【MySQL精通之路】InnoDB(6)-磁盘上的InnoDB结构-CSDN博客 上一篇&#xff1a; 【MySQL精通之路】磁盘上的InnoDB结构-表空间-CSDN博客 下一篇&#xff1a; 【MySQL精通之路】InnoDB(6)-磁盘上的InnoDB结构-Redolog-CSDN博客 目录 1.介绍 1.1 配置变量…

报名开启!2024 开源之夏丨Serverless Devs 课题已上线!

Serverless 是近年来云计算领域热门话题&#xff0c;凭借极致弹性、按量付费、降本提效等众多优势受到很多人的追捧&#xff0c;各云厂商也在不断地布局 Serverless 领域。 Serverless Devs 是一个由阿里巴巴发起的 Serverless 领域的开源项目&#xff0c;其目的是要和开发者们…

leetcode以及牛客网单链表相关的题、移除链表元素、链表的中间节点、合并两个有序链表、反转链表、链表分割、倒数第k个节点等的介绍

文章目录 前言一、移除链表元素二、链表的中间节点三、合并两个有序链表四、反转链表五、链表分割六、倒数第k个节点总结 前言 leetcode以及牛客网单链表相关的题、移除链表元素、链表的中间节点、合并两个有序链表、反转链表、链表分割、倒数第k个节点等的介绍 一、移除链表元…

最近最少使用缓存

题目&#xff1a;请设计实现一个最近最少使用缓存&#xff0c;要求如下两个操作的时间复杂度都是O(1)。 get(key)&#xff1a;如果缓存中存在键key&#xff0c;则返回它对应的值&#xff1b;否则返回-1.put(key,value)&#xff1a;如果缓存中之前包含键key&#xff0c;则它的值…

扫盲:如何提升医学图像分割性能-to do list

导读&#xff1a;本文主要讨论了如何改进图像分割项目中的分割性能&#xff0c;包括一般性和具体性的问题解决方案&#xff0c;以及如何通过调整模型参数、改善数据集质量、优化模型架构、调整超参数、增加训练时长、改善图像分辨率和后处理技术等方法来提高分割效果。 图像分…

【MySQL精通之路】MySQL的使用(9)-设置环境变量

可以在命令提示符下设置环境变量&#xff0c;以影响命令处理器的当前调用&#xff0c;也可以永久设置环境变量以影响未来的调用。 要永久设置变量&#xff0c;可以在启动文件中进行设置&#xff0c;也可以使用系统为此提供的接口进行设置。 有关具体细节&#xff0c;请参阅命…

拼多多暂时超越阿里成为电商第一

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 拼多多的财报又炸裂了&#xff1a; 拼多多发布了第一季度财报&#xff0c;营收868亿&#xff0c;增长了131%&#xff0c;净利润279亿&#xff0c;增长了246%&#xff0c;营销服务收入424亿&#xff0c;也就是商家的…

小林coding笔记

MySQL执行流程 MySQL 的架构共分为两层&#xff1a;Server 层和存储引擎层。Server 层负责建立连接、分析和执行 SQL。存储引擎层负责数据的存储和提取。 Mysql执行 启动Mysql net start mysql登陆 mysql -u root -p输入密码