Spring Boot 整合 MyBatis Plus

目录

一、初始化演示数据

二、创建应用

二、应用配置

三、实体类

四、Mapper

五、Mapper 映射文件

六、Service

七、Service 层抽象接口

八、配置 Mapper 扫描包

九、在日志中输出 SQL

十、测试


MyBatis Plus 是 MyBatis 框架的一个增强。除了基本的 MyBatis 功能外,它还提供了快速的 CURD 方法,以及投影查询、分页查询、动态条件等等功能,极大的提高了开发效率。

本文将会通过案例教你如何在 Spring Boot 中整合 MyBatis Plus。

文中使用的软件版本如下:

  • Spring Boot:3.0.3
  • MySQL:8.0.0
  • MyBatis Plus:3.5.4

一、初始化演示数据

首先在本地数据库执行以下 SQL 脚本,创建一张名为 t_user 的数据表:

CREATE TABLE `t_user` (`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`enabled` tinyint unsigned NOT NULL COMMENT '是否启用。0:禁用,1:启用',`name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名字',PRIMARY KEY (`id`),UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户';

然后再执行如下脚本,创建初始记录:

INSERT INTO `demo`.`t_user` (`id`, `create_at`, `enabled`, `name`) VALUES (3, '2023-10-31 15:11:34', 1, '刘备');
INSERT INTO `demo`.`t_user` (`id`, `create_at`, `enabled`, `name`) VALUES (4, '2023-10-31 15:11:34', 1, '关羽');
INSERT INTO `demo`.`t_user` (`id`, `create_at`, `enabled`, `name`) VALUES (5, '2023-10-31 15:11:34', 1, '张飞');

二、创建应用

通过 Spring Initializer 快速初始化一个 Spring Boot 工程。添加 mybatis-plus-boot-starter 以及 mysql-connector-j (MySQL 驱动)依赖。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.4</version>
</dependency>
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId>
</dependency>

二、应用配置

在 application.yaml 中配置必要的基础配置信息:

spring:# 基本的数据源配置datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=trueusername: rootpassword: root# MyBatis Plus 的配置
mybatis-plus:# mybatis 配置文件的路径# config-location: "classpath:mybatis/mybatis.config"# mapper 映射文件的路径,可以有多个 mapper-locations:- "classpath*:mappers/**/*.xml"

除了必须的数据源配置外,还定义了 MyBatis Plus 的配置。

  • config-location:指定了 MyBatis 配置文件的路径(非必须的)。
  • mapper-locations:指定要加载 mapper 文件,支持使用通配符。本例中的配置表示加载 classpath 下 mappers 目录以及其所有子目录下所有以 xml 结尾的文件。该配置是一个数组,可以配置多个加载路径。

更多关于 MyBatis Plus 的可用配置,可以参考其 官方文档。

三、实体类

创建一个实体类 User,对应上面的 t_user 表:

package cn.springdoc.demo.entity;import java.time.LocalDateTime;import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;@TableName("t_user")
public class User {@TableId(type = IdType.AUTO)private Long id;@TableFieldprivate String name;@TableFieldprivate Boolean enabled;@TableFieldprivate LocalDateTime createAt;// 省略 get/set/toString 等方法
}

@TableName 注解是必须的,用于指定数据库中的表名称。 @TableId 注解也是必须的,用户指定表的 ID 字段,并且通过 type 属性设置了 ID 值为 “数据库自增”。

使用 @TableField 注解来定义与数据表中对应的列。注意,表中的列名使用的是下划线,而实体类中字段名称使用的是驼峰。 框架会自动完成这个转换,你不用担心。

如果你的表列名和实体属性名称之间不能自动完成这种转换,需要通过该注解的 value 属性来定义列名,如:@TableField("u_nick_name")。

@TableField 注解还有一个重要的 boolean 属性:exist,用于定义那些在实体中的 “非 DB 列” 字段。

例如:需要在实体中添加一个额外的 nickName 字段,用于封装检索的结果,这个字段并在表中并没有对应的数据列,此时就需要设置 exist 属性为 false。

@TableField(exist = false)
private String nickName;

否则在运行时你可能会遇到 “Unknown column” 异常:

org.springframework.jdbc.BadSqlGrammarException: 
### Error querying database.  Cause: java.sql.SQLSyntaxErrorException: Unknown column 'nick_name' in 'field list'
### The error may exist in cn/springdoc/demo/mapper/UserMapper.java (best guess)
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT  id,name,enabled,create_at,nick_name  FROM t_user
### Cause: java.sql.SQLSyntaxErrorException: Unknown column 'nick_name' in 'field list'
; bad SQL grammar []

更多可用的注解,可以参阅 官方文档。

四、Mapper

创建 UserMapper 接口,继承 BaseMapper,并且通过泛型指定实体类类型:

package cn.springdoc.demo.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import cn.springdoc.demo.entity.User;public interface UserMapper extends BaseMapper<User>{/*** 根据 name 检索一条记录* @param name* @return*/User getByName (String name);
}

BaseMapper 已经预置了很多 CRUD 的方法,可以直接使用。

并且,还在这个接口中定义了一个自定义方法 getByName(),根据 name 检索一条记录。添加这个方法的目的是测试 Mapper 映射文件是否成功加载。

五、Mapper 映射文件

在 src/main/resources/mappers 目录下创建 UserMapper.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 namespace="cn.springdoc.demo.mapper.UserMapper"><select id="getByName" resultType="cn.springdoc.demo.entity.User">SELECT * FROM `t_user` WHERE `name` = #{name}</select></mapper>

在 UserMapper.xml 中,通过 select 节点实现了 UserMapper 接口中的 getByName 方法。

六、Service

MyBatis Plus 甚至还提供了一个 ServiceImpl<M extends BaseMapper<T>, T> 抽象类,它也预定义了很多 CRUD 的方法。

我们的 Service 类可以直接继承它,指定泛型为实体类的 Mapper 接口以及实体类类型。

package cn.springdoc.demo.service;import org.springframework.stereotype.Service;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import cn.springdoc.demo.entity.User;
import cn.springdoc.demo.mapper.UserMapper;@Service
public class UserService extends ServiceImpl<UserMapper, User>{}

七、Service 层抽象接口

如果你喜欢抽象出 Service 接口的话,MyBatis Plus 也提供了一个接口:IService<T> 可用于继承。

定义业务接口,继承 IService:

import com.baomidou.mybatisplus.extension.service.IService;
import cn.springdoc.demo.entity.User;
// UserService 继承 IService 接口
public interface UserService  extends IService<User>{
}

业务接口实现类 UserServiceImpl,实现业务接口并且继承 ServiceImpl 抽象类:

package cn.springdoc.demo.service;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.springdoc.demo.entity.User;
import cn.springdoc.demo.mapper.UserMapper;// UserServiceImpl 实现类,实现 UserService 接口,并且继承 ServiceImpl 抽象类
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}

我个人觉得除非实在是有必要,不然真的没必要在 Service 抽象出接口。写一辈子代码,也遇不到几次 Service 多实现的场景。

八、配置 Mapper 扫描包

在 main 类上添加 @MapperScan 注解,指定 mapper 接口所在的包:

package cn.springdoc.demo;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("cn.springdoc.demo.mapper") // mapper 接口所在的包
public class DemoApplication {public static void main(String[] args) {SpringApplication.run(DemoApplication.class, args);}
}

九、在日志中输出 SQL

为了看到执行的 SQL 日志,可以在 application.yaml 把 mapper 所在包的日志级别设置为 DEBUG:

logging:level:cn.springdoc.demo.mapper: DEBUG

至此,整合就完成了。

十、测试

创建测试类:

package cn.springdoc.demo.test;import java.util.List;import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;import cn.springdoc.demo.entity.User;
import cn.springdoc.demo.mapper.UserMapper;
import cn.springdoc.demo.service.UserService;@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {static final Logger log = LoggerFactory.getLogger(DemoApplicationTests.class);@AutowiredUserService userService;@Testpublic void test() throws Exception {// 检索所有记录List<User> users = this.userService.list();users.stream().forEach(user -> {log.info("user = {}", user);});// 从 Service 中获取到注入的 Mapper,强制转换为具体的实体 MapperUserMapper userMapper = (UserMapper) this.userService.getBaseMapper();// 调用 Mapper 中的方法User user = userMapper.getByName("刘备");log.info("user = {}", user);}
}

在测试类中注入了 UserService,执行了 2 个查询。

首先,使用 MyBatis Plus 提供的 list() 方法检索出表中的所有记录。

然后,再通过 getBaseMapper() 方法获取到 Service 中注入的 BaseMapper 接口,并且强制转换为对应的 UserMapper。然后调用我们在接口中自定义的方法。

执行测试,输出日志如下:

[           main] c.s.demo.mapper.UserMapper.selectList    : ==>  Preparing: SELECT id,name,enabled,create_at FROM t_user
[           main] c.s.demo.mapper.UserMapper.selectList    : ==> Parameters: 
[           main] c.s.demo.mapper.UserMapper.selectList    : <==      Total: 3
[           main] c.s.demo.test.DemoApplicationTests       : user = User [id=3, name=刘备, enabled=true, createAt=2023-10-31T15:11:34]
[           main] c.s.demo.test.DemoApplicationTests       : user = User [id=4, name=关羽, enabled=true, createAt=2023-10-31T15:11:34]
[           main] c.s.demo.test.DemoApplicationTests       : user = User [id=5, name=张飞, enabled=true, createAt=2023-10-31T15:11:34]
[           main] c.s.demo.mapper.UserMapper.getByName     : ==>  Preparing: SELECT * FROM `t_user` WHERE `name` = ?
[           main] c.s.demo.mapper.UserMapper.getByName     : ==> Parameters: 刘备(String)
[           main] c.s.demo.mapper.UserMapper.getByName     : <==      Total: 1
[           main] c.s.demo.test.DemoApplicationTests       : user = User [id=3, name=刘备, enabled=true, createAt=2023-10-31T15:11:34]

如你所见,一切OK!

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

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

相关文章

浅谈安科瑞电力监控系统在百事亚洲研发中心的应用

摘要&#xff1a;介绍百事亚洲研发中心&#xff0c;采用智能电力仪表、采集配电现场的各种电参量和开关信号。系统采用现场就地组网的方式&#xff0c;组网后通过现场总线通讯并远传至后台&#xff0c;通过Acrel-2000型电力监控系统实现配电所配电回路用电的实时监控和管理。 …

【AI视野·今日Robot 机器人论文速览 第六十一期】Tue, 24 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Tue, 24 Oct 2023 Totally 50 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers Robot Fine-Tuning Made Easy: Pre-Training Rewards and Policies for Autonomous Real-World Reinforcement Learning Autho…

全球互联网信息,中文内容只占1.3%,学好英语,这几条路子让你赚认知外的钱

在全世界的整个互联网上&#xff0c;中文内容只占1.3%&#xff0c;而英文内容接近60%&#xff0c;如果你不会英语&#xff0c;你的眼界和思维将局限在这1.3%里面。 单单就说赚钱这个事情&#xff0c;学好英语&#xff0c;你可以有很多特殊的路子赚到大钱&#xff0c;可以赚到你…

c语言练习(9周)(16~20)

输入12个一位整数&#xff0c;创建二维数组a[3][4]&#xff0c;显示二维数组及各列的平均值&#xff0c;平均值四舍五入到小数点后一位。 题干输入12个一位整数&#xff0c;创建二维数组a[3][4]&#xff0c;显示二维数组及各列的平均值&#xff0c;平均值四舍五入到小数点后一…

uni-app 应对微信小程序最新隐私协议接口要求的处理方法

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 一&#xff0c;问题起因 最新在开发小程序的时候&#xff0c;调用微信小程序来获取用户信息的时候经常报错一个问题 fail api scope is not declared in the privacy agreement&#xff0c;api更具公告…

STM32:AHT20温湿度传感器驱动程序开发

注&#xff1a;温湿度传感器AHT20数据手册.pdf http://www.aosong.com/userfiles/files/AHT20%E4%BA%A7%E5%93%81%E8%A7%84%E6%A0%BC%E4%B9%A6(%E4%B8%AD%E6%96%87%E7%89%88)%20B1.pdf 一、分析AHT数据手册文档 (1).准备工作 1.新建工程。配置UART2 2.配置I2C1为I2C标准模式&…

Rocky9 上安装 redis-dump 和redis-load 命令

一、安装依赖环境 1、依赖包 dnf -y install perl gcc gcc-c zlib-devel2、编译openssl 1.X ### 下载编译 wget https://www.openssl.org/source/openssl-1.1.1t.tar.gz tar xf openssl-1.1.1t.tar.gz cd openssl-1.1.1t ./config --prefix/usr/local/openssl make make ins…

[Hive] 查询结果保存

文章目录 1.插入新表追加 2.插入hdfs文件系统 1.插入新表 使用INSERT OVERWRITE语句的情况&#xff1a; 整个表&#xff1a;可以使用INSERT OVERWRITE TABLE table_name语句将查询结果直接覆盖整个表中的数据。 INSERT OVERWRITE TABLE table_name SELECT * FROM ...特定分区…

Vue项目创建与启动(2023超详细的图文教程)

目录 一、下载node.js 二、下载vue-cli与webpack插件 三、项目初始化(项目配置详细信息) 四、项目启动 五、Vue项目工程结构&#xff08;扩展知识&#xff09; 一、下载node.js 1.检测是否已经安装过node.js 打开控制台,输入 npm -v如果有会显示对应版本 如果没有会显示…

centos中mongodb设置服务自启动并 允许远程IP访问

安装mongodb参考 注意的是配置文件需要把journal设置为true 制作为系统服务 创建MongoDB服务文件。运行以下命令创建服务文件/etc/systemd/system/mongod.service&#xff1a; vi /etc/systemd/system/mongod.service [Unit] DescriptionMongoDB Database Server Documenta…

Python框架之Flask入门和视图

一、Flask入门和视图 需要安装Pycharm专业版 1. Flask简介 Python后端的2个主流框架 Flask 轻量级框架Django 重型框架 Flask是一个基于Python实现的web开发微框架 官方文档&#xff1a;https://flask.palletsprojects.com/ 中文文档&#xff1a;https://dormousehole.readthe…

lambda表达式和Stream(流)

Lambda表达式是Java 8引入的一项重要特性&#xff0c;它允许您以一种更简洁的方式定义匿名函数&#xff08;也称为闭包&#xff09;。Lambda表达式是函数式编程的一部分&#xff0c;它提供了在Java中处理函数式接口的能力。函数式接口是一个只有一个抽象方法的接口。Lambda表达…

防范欺诈GPT

去年&#xff0c;ChatGPT的发布让全世界都感到惊讶和震惊。 突然间出现了一个平台&#xff0c;它比之前的任何其他技术都更深入地了解互联网。人工智能可以被训练成像阿姆一样说唱&#xff0c;以世界著名诗人的风格写作&#xff0c;并精确地翻译内容&#xff0c;以至于它似乎能…

分析web应用防火墙与防火墙的功能与用途

随着互联网的普及和信息技术的发展&#xff0c;网络安全问题日益受到关注。防火墙和Web应用防火墙作为网络安全的重要组成部分&#xff0c;起着至关重要的作用。小编将对防火墙和Web应用防火墙的功能和用途进行比较分析&#xff0c;以帮助读者了解两者的区别和联系。 一、防火墙…

【Unity实战】最全面的库存系统(二)

文章目录 先来看看最终效果前言箱子库存箱子存储物品玩家背包快捷栏满了,物品自动加入背包修复开着背包拾取物品不会刷新显示的问题将箱子库存和背包分开,可以同时打开完结先来看看最终效果 前言 本期紧跟着上期,继续来完善我们的库存系统,实现箱子库存和人物背包 箱子库…

R语言的DICE模型实践技术

随着温室气体排放量的增大和温室效应的增强&#xff0c;全球气候变化问题受到日益的关注。我国政府庄严承诺在2030和2060年分别达到“碳达峰”和“碳中和”&#xff0c;因此气候变化和碳排放已经成为科研人员重点关心的问题之一。气候变化问题不仅仅是科学的问题&#xff0c;同…

React中的状态管理

目录 前言 1. React中的状态管理 1.1 本地状态管理 1.2 全局状态管理 Redux React Context 2. React状态管理的优势 总结 前言 当谈到前端开发中的状态管理时&#xff0c;React是一个备受推崇的选择。React的状态管理机制被广泛应用于构建大型、复杂的应用程序&#xf…

贪心算法学习------优势洗牌

目录 一&#xff0c;题目 二&#xff0c;题目接口 三&#xff0c;解题思路和代码 全部代码&#xff1a; 一&#xff0c;题目 给定两个数组nums1和nums2,nums1相对于nums2的优势可以用满足nums1[i]>nums2[i]的索引i的数目来描述。 返回nums1的任意排序&#xff0c;使其优…

[AUTOSAR][诊断管理][ECU][$3E] 测试设备在线|会话保持

文章目录 一、简介二、服务请求报文定义三、肯定响应四、支持的NRC四、示例步骤(1)supportPosRspMsgIndicationBit=0(2)supportPosRspMsgIndicationBit=1三、示例代码3e_test_present.c一、简介 这个服务的目的是确保诊断服务或者之前激活的通信还处在激活的状态,可以保持…

【51单片机】矩阵键盘与定时器(学习笔记)

一、矩阵键盘 1、矩阵键盘概述 在键盘中按键数量较多时&#xff0c;为了减少I/O口的占用&#xff0c;通常将按键排列成矩阵形式 采用逐行或逐列的“扫描”&#xff0c;就可以读出任何位置按键的状态 2、扫描的概念 数码管扫描&#xff08;输出扫描&#xff09;&#xff1a;…