❝
「MP官网」:https://baomidou.com/
期待越是高昂,越是留下厚重遗憾。
《来晚》
❞
1、简介
MyBatis-Plus 是一个 MyBatis的增强工具,在 MyBatis 的基础上只做「增强不做改变」,为简化开发、提高效率而生。

2、特性
-
「无侵入」:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑; -
「损耗小」:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作; -
「强大的 CRUD 操作」:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求; -
「支持 Lambda 形式调用」:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错; -
「支持主键自动生成」:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 – Sequence),可自由配置,完美解决主键问题; -
「支持 ActiveRecord 模式」:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作; -
「支持自定义全局通用操作」:支持全局通用方法注入( Write once, use anywhere ); -
「内置代码生成器」:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用; -
「内置分页插件」:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询; -
「分页插件支持多种数据库」:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库; -
「内置性能分析插件」:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询; -
「内置全局拦截插件」:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作;
3、支持数据库
-
DB2 -
MySQL -
Oracle -
H2 -
HSQL -
SQLite -
PostgreSQL -
SQLServer -
Phoenix -
Gauss -
ClickHouse -
Sybase -
OceanBase -
Firebird -
Cubrid -
Goldilocks -
Csiidb -
Informix -
TDengine -
Redshift -
达梦数据库 -
虚谷数据库 -
人大金仓数据库 -
南大通用(华库)数据库 -
南大通用数据库 -
神通数据库 -
瀚高数据库 -
优炫数据库 -
星瑞格数据库
4、框架结构

5、安装依赖
全新的 MyBatis-Plus 3.0
版本基于 JDK8,提供了 lambda 形式的调用,所以安装集成 MP3.0 要求如下:
-
JDK 8+ -
Maven or Gradle
版本对应关系
在开始使用 MyBatis-Plus 之前,你需要先熟悉 Spring 和 MyBatis 这两个框架和有关它们的术语。
MyBatis-Spring | MyBatis | Spring Framework | Spring Batch | Java |
---|---|---|---|---|
3.0 | 3.5+ | 6.0+ | 5.0+ | Java 17+ |
2.1 | 3.5+ | 5.x | 4.x | Java 8+ |
2.0 | 3.5+ | 5.x | 4.x | Java 8+ |
1.3 | 3.4+ | 3.2.2+ | 2.1+ | Java 6+ |
版本依赖选用
经过具体的Demo实测,我们最终选用的对应版本如下。
-
JDK 20 -
Spring Boot 3.1.0 -
MyBatis-Plus 3.5.3.2
<?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>
<groupId>boot.hub</groupId>
<artifactId>hub-boot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hub-boot</name>
<description>一个集成多种功能的项目</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.0</version>
<relativePath/>
</parent>
<properties>
<java.version>20</java.version>
<ibatis-plus.version>3.5.3.2</ibatis-plus.version>
<snakeyaml.version>2.2</snakeyaml.version>
</properties>
<dependencies>
<!--spring web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- snakeyaml:修复snakeyaml:1.33版本存在的漏洞 -->
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>${snakeyaml.version}</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${ibatis-plus.version}</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--...etc-->
</dependencies>
<!--...etc-->
</project>
⚠️注:仅展示部分依赖配置。
6、MP配置
MyBatis-Plus的配置异常的简单,我们仅需要一些简单的配置即可使用 MyBatis-Plus 的强大功能!
数据源配置
server:
#随机端口
#port: ${random.int[8080,8081]}
port: 7201
spring:
# 数据源
datasource:
username: root
password: root
url: jdbc:mysql://127.0.0.1:3306/hub-boot?allowMultiQueries=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&nullDatabaseMeansCurrent=true
driver-class-name: com.mysql.cj.jdbc.Driver
# MP配置
mybatis-plus:
configuration:
# 驼峰原则-关闭
map-underscore-to-camel-case: false
# 日志记录方式-控制台
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
拓展功能配置
我们也可以通过配置类方式去开启MP提供的其他拓展功能,比如「自动填充」、「选装件」等。
-
基准模型
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.sql.Timestamp;
@Data
@Schema(description="MyBatis基准模型")
public class CustomModel{
@TableId(value = "id",type = IdType.ASSIGN_UUID)
@Schema(name = "id", description="标识ID")
private String id;
@TableField(value = "create_time",fill = FieldFill.INSERT)
@Schema(name = "create_time", description="创建时间")
private Timestamp create_time;
@TableField(value = "update_time",fill = FieldFill.UPDATE)
@Schema(name = "update_time", description="更新时间")
private Timestamp update_time;
}
⚠️注:为了减少冗余代码,把所有实体都有的字段提取出来!
-
核心配置
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@MapperScan(basePackages = {"org.hub.core.*.mapper"}) //这个不写在这,也能写在启动类(必须)
@EnableTransactionManagement
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
@Bean
public CustomDefaultSqlInjector insertBatchInjector() {
return CustomDefaultSqlInjector.builder().build();
}
}
-
SQL注入器
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
import lombok.Builder;
import java.util.List;
@Builder
public class CustomDefaultSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> list = super.getMethodList(mapperClass, tableInfo);
// 选装件 - 批量插入
list.add(new InsertBatchSomeColumn(field -> field.getFieldFill() != FieldFill.UPDATE));
return list;
}
}
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
public interface CustomMapper<T> extends BaseMapper<T> {
/**
* 批量插入
* @param data 插入对象
* @return {@link Integer}
*/
@SuppressWarnings("unused")
int insertBatchSomeColumn(List<T> data);
}
-
自动填充
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.sql.Timestamp;
import java.time.LocalDateTime;
@Slf4j
@Component
public class CustomMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.strictInsertFill(metaObject, "create_time", LocalDateTime::now, LocalDateTime.class);
this.strictInsertFill(metaObject, "create_time", Timestamp.class,Timestamp.valueOf(LocalDateTime.now()));
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "update_time", LocalDateTime::now, LocalDateTime.class);
this.strictUpdateFill(metaObject, "update_time", Timestamp.class,Timestamp.valueOf(LocalDateTime.now()));
}
}
7、案例演示
在上述我们已经对MP的配置进行了补充,那么现在我们需要测试下配置是不是完备,准备好如下「用户」表。
create table HUB_USER(
id varchar(128) not null comment '用户id' primary key,
account varchar(128) null comment '账号',
name varchar(128) null comment '用户名',
password varchar(32) null comment '密码',
enabled tinyint null comment '是否启用',
accountNonExpired tinyint null comment '是否过期',
credentialsNonExpired tinyint null comment '密码是否过期',
accountNonLocked tinyint null comment '是否锁定',
create_time timestamp default CURRENT_TIMESTAMP null comment '创建时间',
update_time timestamp null comment '更新时间',
constraint hub_user_pk2 unique (account)
);
INSERT INTO HUB_USER (id, account, name, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, create_time, update_time) VALUES ('1', 'caixibei', '蔡熙贝', '123456', 1, 1, 1, 1, '2023-09-06 03:10:23', null);
INSERT INTO HUB_USER (id, account, name, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, create_time, update_time) VALUES ('165a7c359c962c85c3486412d836758a', 'tangwentian@139.com', '唐问龙', '123456', 0, 0, 0, 0, null, '2023-10-07 11:54:04');
INSERT INTO HUB_USER (id, account, name, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, create_time, update_time) VALUES ('1d834fa2f336d370b7fe67d61d88a0fe', 'zhangjunhao', '张均浩', 'zhangjunhao', 1, 1, 1, 1, '2023-09-06 16:09:24', null);
INSERT INTO HUB_USER (id, account, name, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, create_time, update_time) VALUES ('a511a254b775216f3b342a1742c2f14e', 'renzhenyu', '任振玉', 'renzhenyu', 1, 1, 1, 1, '2023-09-06 16:20:42', null);
INSERT INTO HUB_USER (id, account, name, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, create_time, update_time) VALUES ('e10b276de180533a0d8c85e2cde9c431', 'caiwl@163.com', '啊哈哈1', '123456', 0, 0, 0, 0, '2023-10-07 13:53:05', '2023-10-07 16:28:19');
实体层
既然表结构已经明确,我们就需要进行实体类的创建工作。
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import org.hub.system.config.ibatis.CustomModel;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Data
@TableName("HUB_USER")
@Schema(name = "系统用户表", description = "系统用户表")
@EqualsAndHashCode(callSuper = true)
public class User extends CustomModel {
@TableField("name")
@Schema(name = "name", description = "用户名")
private String name;
@TableField("account")
@Schema(name = "account", description = "账号")
private String account;
@TableField("password")
@Schema(name = "password", description = "密码")
private String password;
@TableField("enabled")
@Schema(name = "enabled", description = "是否启用")
private boolean enabled;
@TableField("accountNonExpired")
@Schema(name = "accountNonExpired", description = "是否过期")
private boolean accountNonExpired;
@TableField("credentialsNonExpired")
@Schema(name = "credentialsNonExpired", description = "认证是否锁定")
private boolean credentialsNonExpired;
@TableField("accountNonLocked")
@Schema(name = "accountNonLocked", description = "账号是否锁定")
private boolean accountNonLocked;
@TableField(exist = false)
@Schema(name = "authorities", description = "用户权限列表", hidden = true)
private List<SimpleGrantedAuthority> authorities;
}
控制层
package org.hub.core.user.controller;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.hub.core.user.pojo.User;
import org.hub.core.user.service.UserService;
import org.hub.system.config.result.ResponseResult;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController("/user")
@Tag(name = "系统用户管理")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@Operation(summary = "系统用户查询")
@PostMapping("/queryUsers")
public ResponseResult<?> queryUsers(@RequestBody User user, @RequestParam String start, @RequestParam String limit) {
Assert.isTrue(StringUtils.isNotBlank(start), "请传入当前页码");
Assert.isTrue(NumberUtil.isNumber(start), "传入页码不正确");
Assert.isTrue(NumberUtil.isNumber(limit), "每页条数不正确");
Page<User> page = Page.of(ObjectUtil.isNull(start) ? 1 : Integer.parseInt(start),
ObjectUtil.isNull(limit) ? 20 : Integer.parseInt(limit));
page.setOptimizeCountSql(true);
return ResponseResult.success(userService.queryUsers(page, user));
}
@Operation(summary = "新增单个用户")
@PostMapping("/insertSingleUser")
@Transactional(rollbackFor = Exception.class,timeout = 5000)
public ResponseResult<?> insertSingleUser(@RequestBody User user){
Assert.notNull(user, "传入用户不能为空");
return ResponseResult.success(userService.insertSingleUser(user));
}
@Operation(summary = "批量新增用户")
@PostMapping("/insertMultiUser")
@Transactional(rollbackFor = Exception.class,timeout = 30000)
public ResponseResult<?> insertMultiUser(@RequestBody List<User> users){
Assert.isTrue(!users.isEmpty(), "至少传入一个用户");
return ResponseResult.success(userService.insertMultiUser(users));
}
@Operation(summary = "修改单个用户")
@PostMapping("/updateSingleUser")
@Transactional(rollbackFor = Exception.class,timeout = 30000)
public ResponseResult<?> updateSingleUser(@RequestBody User user){
Assert.isTrue(ObjectUtil.isNotNull(user), "传入用户不得为空!");
return ResponseResult.success(userService.updateSingleUser(user));
}
@Operation(summary = "删除单个用户")
@PostMapping("/deleteSingleUser")
@Transactional(rollbackFor = Exception.class,timeout = 30000)
public ResponseResult<?> deleteSingleUser(@RequestBody User user){
Assert.isTrue(ObjectUtil.isNotNull(user), "传入用户不得为空!");
return ResponseResult.success(userService.deleteSingleUser(user));
}
@Operation(summary = "批量删除用户")
@PostMapping("/deleteMultipleUser")
@Transactional(rollbackFor = Exception.class,timeout = 30000)
public ResponseResult<?> deleteMultipleUser(@RequestBody List<User> users){
Assert.isTrue(!users.isEmpty(), "至少传入一个用户");
return ResponseResult.success(userService.deleteMultipleUser(users));
}
}
持久层
import org.apache.ibatis.annotations.Mapper;
import org.hub.core.user.pojo.User;
import org.hub.system.config.ibatis.CustomMapper;
@Mapper
public interface UserMapper extends CustomMapper<User> {
}
<?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="org.hub.core.user.mapper.UserMapper">
</mapper>
服务层
package org.hub.core.user.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.lang3.StringUtils;
import org.hub.core.user.mapper.UserMapper;
import org.hub.core.user.pojo.User;
import org.hub.core.user.service.UserService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public User queryUserByAccount(String account) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getAccount, account);
return userMapper.selectOne(wrapper);
}
@Override
public IPage<User> queryUsers(Page<User> page, User user) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
String account = user.getAccount();
String name = user.getName();
boolean enabled = user.isEnabled();
wrapper.eq(StringUtils.isNotBlank(account), User::getAccount, user.getAccount());
wrapper.like(StringUtils.isNotBlank(name), User::getName, user.getName());
wrapper.eq(ObjectUtil.isNotNull(enabled), User::isEnabled, enabled);
return userMapper.selectPage(page, wrapper);
}
@Override
public int insertSingleUser(User user) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(true, User::getAccount, user.getAccount());
boolean exists = userMapper.exists(wrapper);
Assert.isTrue(!exists, "该用户(" + user.getAccount() + ")已存在!");
return userMapper.insert(user);
}
@Override
public int insertMultiUser(List<User> users) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.in(!users.isEmpty(), User::getAccount, users.stream().map(User::getAccount).collect(Collectors.toList()));
boolean exists = userMapper.exists(wrapper);
Assert.isTrue(!exists, "新增用户可能已存在!");
return userMapper.insertBatchSomeColumn(users);
}
@Override
public int updateSingleUser(User user) {
String account = user.getAccount();
LambdaUpdateWrapper<User> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(true, User::getAccount, account);
return userMapper.update(user,wrapper);
}
@Override
public int deleteSingleUser(User user) {
String account = user.getAccount();
LambdaUpdateWrapper<User> wrapper = Wrappers.lambdaUpdate();
wrapper.eq(true, User::getAccount, account);
return userMapper.delete(wrapper);
}
@Override
public int deleteMultipleUser(List<User> users) {
LambdaUpdateWrapper<User> wrapper = Wrappers.lambdaUpdate();
wrapper.in(true, User::getAccount, users.stream().map(User::getAccount).collect(Collectors.toList()));
return userMapper.delete(wrapper);
}
}
package org.hub.core.user.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.hub.core.user.pojo.User;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface UserService /*extends IService<User>*/ {
/**
* 根据用户账号查询用户
*
* @param account 用户账号、唯一
* @return {@link User}
*/
User queryUserByAccount(String account);
/**
* 分页查询用户
*
* @param page 分页条件
* @param user 查询条件
* @return {@link User}
*/
IPage<User> queryUsers(Page<User> page, User user);
/**
* 新增单个用户
*
* @param user 用户实体
* @return {@link Integer}
*/
int insertSingleUser(User user);
/**
* 批量新增用户
*
* @param users 多个用户
* @return {@link Integer}
*/
int insertMultiUser(List<User> users);
/**
* 修改单个用户
*
* @param user 用户实体
* @return {@link Integer}
*/
int updateSingleUser(User user);
/**
* 删除单个用户
* @param user 用户
* @return {@link Integer}
*/
int deleteSingleUser(User user);
/**
* 批量删除用户
* @param users 用户列表
* @return {@link Integer}
*/
int deleteMultipleUser(List<User> users);
}
小结
通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!
从以上步骤中,我们可以看到集成MyBatis-Plus非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可。
📢 注:不使用IService
接口纯属个人习惯,你也可以使用!
>>👉更多拓展使用,请移步
原文始发于微信公众号(青衫大叔灬):Spring Boot 3.x集成MyBatis-Plus概述
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/179737.html