当前位置: 首页 > news >正文

SpringBoot第28讲:SpringBoot集成MySQL - MyBatis-Plus方式

SpringBoot第28讲:SpringBoot集成MySQL - MyBatis-Plus方式

本文是SpringBoot第28讲,MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。MyBatis-Plus在国内也有很多的用户,本文主要介绍MyBatis-Plus和SpringBoot的集成。

文章目录

  • SpringBoot第28讲:SpringBoot集成MySQL - MyBatis-Plus方式
    • 1、知识准备
      • 1.1、为什么会诞生MyBatis-Plus?
      • 1.2、支持数据库
      • 1.3、整体架构
    • 2、简单示例
      • 2.1、准备DB和依赖配置
      • 2.2、定义dao
      • 2.3、定义Service接口和实现类
      • 2.4、controller
      • 2.5、分页配置
    • 3、进一步理解
      • 3.1、比较好的实践
      • 3.2、除了分页插件之外还提供了哪些插件?
    • 4、示例源码

1、知识准备

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

1.1、为什么会诞生MyBatis-Plus?

正如前文所述(SpringBoot第24讲:SpringBoot集成MySQL - MyBatis XML方式),为了更高的效率,出现了MyBatis-Plus这类工具,对MyBatis进行增强。

  1. 考虑到MyBatis是半自动化ORM,MyBatis-Plus 启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作; 并且内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求;总体上让其支持全自动化的使用方式(本质上借鉴了Hibernate思路);
  2. 考虑到Java8 Lambda(函数式编程)开始流行,MyBatis-Plus支持 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错;
  3. 考虑到MyBatis还需要独立引入PageHelper分页插件,MyBatis-Plus支持了内置分页插件,同PageHelper一样基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询;
  4. 考虑到自动化代码生成方式,MyBatis-Plus也支持了内置代码生成器,采用代码或者 Maven 插件可快速生成 Mapper、Model、 Service、Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用;
  5. 考虑到SQL性能优化等问题,MyBatis-Plus内置性能分析插件, 可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询;(能对慢查询做到聚类吗?)
  6. 其它还有解决一些常见开发问题,比如支持主键自动生成,支持4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题;以及内置全局拦截插件,提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

1.2、支持数据库

任何能使用 MyBatis 进行 CRUD, 并且支持标准 SQL 的数据库,具体支持情况如下:

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
  • 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库

1.3、整体架构

  • img

2、简单示例

这里沿用上一篇文章的数据库, 向你展示SpringBoot + MyBatis-Plus的使用等。

2.1、准备DB和依赖配置

创建MySQL的schema test_db, 导入SQL 文件如下

DROP TABLE IF EXISTS `tb_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_role` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) NOT NULL,`role_key` varchar(255) NOT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_role`
--LOCK TABLES `tb_role` WRITE;
/*!40000 ALTER TABLE `tb_role` DISABLE KEYS */;
INSERT INTO `tb_role` VALUES (1,'admin','admin','admin','2021-09-08 17:09:15','2021-09-08 17:09:15');
/*!40000 ALTER TABLE `tb_role` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `tb_user`
--DROP TABLE IF EXISTS `tb_user`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user` (`id` int(11) NOT NULL AUTO_INCREMENT,`user_name` varchar(45) NOT NULL,`password` varchar(45) NOT NULL,`email` varchar(45) DEFAULT NULL,`phone_number` int(11) DEFAULT NULL,`description` varchar(255) DEFAULT NULL,`create_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_user`
--LOCK TABLES `tb_user` WRITE;
/*!40000 ALTER TABLE `tb_user` DISABLE KEYS */;
INSERT INTO `tb_user` VALUES (1,'qiwenjie','123456','1172814226@qq.com',1212121213,'afsdfsaf','2021-09-08 17:09:15','2021-09-08 17:09:15');
/*!40000 ALTER TABLE `tb_user` ENABLE KEYS */;
UNLOCK TABLES;--
-- Table structure for table `tb_user_role`
--DROP TABLE IF EXISTS `tb_user_role`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tb_user_role` (`user_id` int(11) NOT NULL,`role_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;--
-- Dumping data for table `tb_user_role`
--LOCK TABLES `tb_user_role` WRITE;
/*!40000 ALTER TABLE `tb_user_role` DISABLE KEYS */;
INSERT INTO `tb_user_role` VALUES (1,1);
/*!40000 ALTER TABLE `tb_user_role` ENABLE KEYS */;
UNLOCK TABLES;

引入maven依赖

<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version>
</dependency>
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version>
</dependency>

增加yml配置

spring:datasource:url: jdbc:mysql://localhost:3306/db_user?useSSL=false&autoReconnect=true&characterEncoding=utf8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: qwj930828mybatis-plus:configuration:# 是否开启二级缓存cache-enabled: trueuse-generated-keys: truedefault-executor-type: REUSEuse-actual-param-name: true

2.2、定义dao

RoleDao

package springboot.mysql.mybatisplus.anno.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import springboot.mysql.mybatisplus.anno.entity.Role;/*** @author qiwenjie*/
public interface IRoleDao extends BaseMapper<Role> {
}

UserDao

package springboot.mysql.mybatisplus.anno.dao;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import springboot.mysql.mybatisplus.anno.entity.User;
import springboot.mysql.mybatisplus.anno.entity.query.UserQueryBean;import java.util.List;/*** @author qiwenjie*/
public interface IUserDao extends BaseMapper<User> {List<User> findList(UserQueryBean userQueryBean);
}

这里你也同时可以支持 BaseMapper 方式和自己定义的xml的方法(比较适用于关联查询),比如 findList 是自定义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="springboot.mysql.mybatisplus.anno.dao.IUserDao"><resultMap type="springboot.mysql.mybatisplus.anno.entity.User" id="UserResult"><id     property="id"       	column="id"      		/><result property="userName"     column="user_name"    	/><result property="password"     column="password"    	/><result property="email"        column="email"        	/><result property="phoneNumber"  column="phone_number"  	/><result property="description"  column="description"  	/><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/><collection property="roles" ofType="springboot.mysql.mybatisplus.anno.entity.Role"><result property="id" column="id"  /><result property="name" column="name"  /><result property="roleKey" column="role_key"  /><result property="description" column="description"  /><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/></collection></resultMap><sql id="selectUserSql">select u.id, u.password, u.user_name, u.email, u.phone_number, u.description, u.create_time, u.update_time, r.name, r.role_key, r.description, r.create_time, r.update_timefrom tb_user uleft join tb_user_role ur on u.id=ur.user_idinner join tb_role r on ur.role_id=r.id</sql><select id="findList" parameterType="springboot.mysql.mybatisplus.anno.entity.query.UserQueryBean" resultMap="UserResult"><include refid="selectUserSql"/>where u.id != 0<if test="userName != null and userName != ''">AND u.user_name like concat('%', #{user_name}, '%')</if><if test="description != null and description != ''">AND u.description like concat('%', #{description}, '%')</if><if test="phoneNumber != null and phoneNumber != ''">AND u.phone_number like concat('%', #{phoneNumber}, '%')</if><if test="email != null and email != ''">AND u.email like concat('%', #{email}, '%')</if></select>
</mapper> 

2.3、定义Service接口和实现类

UserService接口

package springboot.mysql.mybatisplus.anno.service;import com.baomidou.mybatisplus.extension.service.IService;
import springboot.mysql.mybatisplus.anno.entity.User;
import springboot.mysql.mybatisplus.anno.entity.query.UserQueryBean;
import java.util.List;/*** @author qiwenjie*/
public interface IUserService extends IService<User> {List<User> findList(UserQueryBean userQueryBean);
}

User Service的实现类

package springboot.mysql.mybatisplus.anno.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import springboot.mysql.mybatisplus.anno.dao.IUserDao;
import springboot.mysql.mybatisplus.anno.entity.User;
import springboot.mysql.mybatisplus.anno.entity.query.UserQueryBean;
import springboot.mysql.mybatisplus.anno.service.IUserService;import java.util.List;@Service
public class UserDoServiceImpl extends ServiceImpl<IUserDao, User> implements IUserService {@Overridepublic List<User> findList(UserQueryBean userQueryBean) {return baseMapper.findList(userQueryBean);}
}

Role Service 接口

package springboot.mysql.mybatisplus.anno.service;import com.baomidou.mybatisplus.extension.service.IService;
import springboot.mysql.mybatisplus.anno.entity.Role;
import springboot.mysql.mybatisplus.anno.entity.query.RoleQueryBean;import java.util.List;public interface IRoleService extends IService<Role> {List<Role> findList(RoleQueryBean roleQueryBean);
}

Role Service 实现类

package springboot.mysql.mybatisplus.anno.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import springboot.mysql.mybatisplus.anno.dao.IRoleDao;
import springboot.mysql.mybatisplus.anno.entity.Role;
import springboot.mysql.mybatisplus.anno.entity.query.RoleQueryBean;
import springboot.mysql.mybatisplus.anno.service.IRoleService;
import java.util.List;@Service
public class RoleDoServiceImpl extends ServiceImpl<IRoleDao, Role> implements IRoleService {@Overridepublic List<Role> findList(RoleQueryBean roleQueryBean) {return lambdaQuery().like(StringUtils.isNotEmpty(roleQueryBean.getName()), Role::getName, roleQueryBean.getName()).like(StringUtils.isNotEmpty(roleQueryBean.getDescription()), Role::getDescription, roleQueryBean.getDescription()).like(StringUtils.isNotEmpty(roleQueryBean.getRoleKey()), Role::getRoleKey, roleQueryBean.getRoleKey()).list();}
}

2.4、controller

User Controller

package springboot.mysql.mybatisplus.anno.controller;import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springboot.mysql.mybatisplus.anno.entity.User;
import springboot.mysql.mybatisplus.anno.entity.query.UserQueryBean;
import springboot.mysql.mybatisplus.anno.entity.response.ResponseResult;
import springboot.mysql.mybatisplus.anno.service.IUserService;
import java.time.LocalDateTime;
import java.util.List;/*** @author qiwenjie*/
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate IUserService userService;/*** @param user user param* @return user*/@ApiOperation("Add/Edit User")@PostMapping("add")public ResponseResult<User> add(User user) {if (user.getId() == null) {user.setCreateTime(LocalDateTime.now());}user.setUpdateTime(LocalDateTime.now());userService.save(user);return ResponseResult.success(userService.getById(user.getId()));}/*** @return user list*/@ApiOperation("Query User One")@GetMapping("edit/{userId}")public ResponseResult<User> edit(@PathVariable("userId") Long userId) {return ResponseResult.success(userService.getById(userId));}/*** @return user list*/@ApiOperation("Query User List")@GetMapping("list")public ResponseResult<List<User>> list(UserQueryBean userQueryBean) {return ResponseResult.success(userService.findList(userQueryBean));}
}

Role Controller

package springboot.mysql.mybatisplus.anno.controller;import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springboot.mysql.mybatisplus.anno.entity.Role;
import springboot.mysql.mybatisplus.anno.entity.query.RoleQueryBean;
import springboot.mysql.mybatisplus.anno.entity.response.ResponseResult;
import springboot.mysql.mybatisplus.anno.service.IRoleService;
import java.util.List;/*** @author qiwenjie*/
@RestController
@RequestMapping("/role")
public class RoleController {@Autowiredprivate IRoleService roleService;/*** @return role list*/@ApiOperation("Query Role List")@GetMapping("list")public ResponseResult<List<Role>> list(RoleQueryBean roleQueryBean) {return ResponseResult.success(roleService.findList(roleQueryBean));}
}

2.5、分页配置

通过配置内置的MybatisPlusInterceptor拦截器。

package springboot.mysql.mybatisplus.anno.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** MyBatis-plus configuration, add pagination interceptor.** @author qiwenjie*/
@Configuration
public class MyBatisConfig {/*** inject pagination interceptor.** @return pagination*/@Beanpublic PaginationInnerInterceptor paginationInnerInterceptor() {return new PaginationInnerInterceptor();}/*** add pagination interceptor.** @return MybatisPlusInterceptor*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor());return mybatisPlusInterceptor;}
}

3、进一步理解

MyBatis-plus学习梳理

  • 官方文档
  • 官方案例
  • 官方源码仓库
  • Awesome Mybatis-Plus

3.1、比较好的实践

总结下开发的过程中比较好的实践

1、Mapper层:继承BaseMapper

public interface IRoleDao extends BaseMapper<Role> {
}

2、Service层:继承ServiceImpl并实现对应接口

public class RoleDoServiceImpl extends ServiceImpl<IRoleDao, Role> implements IRoleService {}

3、Lambda函数式查询

@Override
public List<Role> findList(RoleQueryBean roleQueryBean) {return lambdaQuery().like(StringUtils.isNotEmpty(roleQueryBean.getName()), Role::getName, roleQueryBean.getName()).like(StringUtils.isNotEmpty(roleQueryBean.getDescription()), Role::getDescription, roleQueryBean.getDescription()).like(StringUtils.isNotEmpty(roleQueryBean.getRoleKey()), Role::getRoleKey, roleQueryBean.getRoleKey()).list();
}

4、分页采用内置MybatisPlusInterceptor

/*** inject pagination interceptor.* @return pagination*/
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor() {return new PaginationInnerInterceptor();
}/*** add pagination interceptor.* @return MybatisPlusInterceptor*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor());return mybatisPlusInterceptor;
}

5、对于复杂的关联查询

可以配置原生xml方式, 在其中自定义ResultMap

<?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="springboot.mysql.mybatisplus.anno.dao.IUserDao"><resultMap type="springboot.mysql.mybatisplus.anno.entity.User" id="UserResult"><id     property="id"       	column="id"      		/><result property="userName"     column="user_name"    	/><result property="password"     column="password"    	/><result property="email"        column="email"        	/><result property="phoneNumber"  column="phone_number"  	/><result property="description"  column="description"  	/><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/><collection property="roles" ofType="springboot.mysql.mybatisplus.anno.entity.Role"><result property="id" column="id"  /><result property="name" column="name"  /><result property="roleKey" column="role_key"  /><result property="description" column="description"  /><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/></collection></resultMap><sql id="selectUserSql">select u.id, u.password, u.user_name, u.email, u.phone_number, u.description, u.create_time, u.update_time, r.name, r.role_key, r.description, r.create_time, r.update_timefrom tb_user uleft join tb_user_role ur on u.id=ur.user_idinner join tb_role r on ur.role_id=r.id</sql><select id="findList" parameterType="springboot.mysql.mybatisplus.anno.entity.query.UserQueryBean" resultMap="UserResult"><include refid="selectUserSql"/>where u.id != 0<if test="userName != null and userName != ''">AND u.user_name like concat('%', #{user_name}, '%')</if><if test="description != null and description != ''">AND u.description like concat('%', #{description}, '%')</if><if test="phoneNumber != null and phoneNumber != ''">AND u.phone_number like concat('%', #{phoneNumber}, '%')</if><if test="email != null and email != ''">AND u.email like concat('%', #{email}, '%')</if></select>
</mapper> 

3.2、除了分页插件之外还提供了哪些插件?

插件都是基于拦截器实现的,MyBatis-Plus提供了如下插件:

  • 自动分页: PaginationInnerInterceptor
  • 多租户: TenantLineInnerInterceptor
  • 动态表名: DynamicTableNameInnerInterceptor
  • 乐观锁: OptimisticLockerInnerInterceptor
  • sql 性能规范: IllegalSQLInnerInterceptor
  • 防止全表更新与删除: BlockAttackInnerInterceptor

4、示例源码

todo

http://www.lryc.cn/news/105686.html

相关文章:

  • AI 绘画Stable Diffusion 研究(三)sd模型种类介绍及安装使用详解
  • Docker 命令没有提示信息
  • springboot第33集:nacos图
  • 学习gRPC(一)
  • 【二进制安全】堆漏洞:Double Free原理
  • python之open,打开文件时,遇到解码错误处理方式
  • STM32 CAN通信-CubeMX环境下CAN通信程序的编程与调试经验
  • windows创建不同大小的文件命令
  • Attention Is All You Need
  • 手写线程池 - C++版 - 笔记总结
  • PHP 容器化引发线上 502 错误状态码的修复
  • QT中UDP之UDPsocket通讯
  • 【C语言】10-三大结构之循环结构-1
  • Windows下RocketMQ的启动
  • linux内核升级 docker+k8s更新显卡驱动
  • express学习笔记2 - 三大件概念
  • Steam搬砖蓝海项目
  • 就业并想要长期发展选数字后端还是ic验证?
  • 当服务器域名出现解析错误的问题该怎么办?
  • 面试必考精华版Leetcode2095. 删除链表的中间节点
  • 对 Redis 实现分布式事务的探索与实现
  • Matlab实现Spectral Clustering算法
  • Android 测试
  • 全面解析大语言模型的工作原理
  • cmake+pybind11打包c++库成python wheel安装包
  • 史上最细,接口自动化测试框架-Pytest+Allure+Excel整理(代码)
  • 【计算机视觉中的 GAN 】 - 条件图像合成和 3D 对象生成(2)
  • 智安网络|常见的网络安全陷阱:你是否掉入了其中?
  • 亚马逊云科技HPC解决方案,帮助浙江大学实现成本和科研任务的双丰收
  • 【Docker】Docker中安装MySQL数据库