MyBatisPlus快速入门

需要的基础:

  • MyBatis
  • Spring
  • SpringMVC
  • 是什么?

    • MyBatis 本来就是简化 JDBC 操作的!
    • 官网:https://baomidou.com/,简化 MyBatis

1.MyBatisPlus概述

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

愿景

  • 是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P、2P,基友搭配,效率翻倍。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

框架结构

  • 总结:扫描实体类型,分析数据库的表和字段直接把sql注入到mybatis的容器中不用写sql

    (不用写mapper.xml 秀儿)),简化了mybatis的开发。

代码托管

  • Gitee| Github

相关链接

  • 文档
  • 代码生成
  • 功能示例
  • 展示
  • 企业版 Mybatis-Mate 高级特性

教程

  • MyBatis-Plus 入门 - 视频教程 - 慕课网
  • MyBatis-Plus 进阶 - 视频教程 - 慕课网
  • MyBatis-Plus + SpringBoot实现简单权限管理 - 视频教程 - 慕课网

原理

  • Mybatis-Plus 实践及架构原理

2.快速入门

  • 教程地址:https://mp.baomidou.com/guide/quick-start.html
  • 以下将通过一个简单的 Demo 来阐述 MyBatis-Plus 的强大功能,在此之前,我们假设您已经:
    • 拥有 Java 开发环境以及相应 IDE
    • 熟悉 Spring Boot
    • 熟悉 Maven

  1. 创建一个数据库mybatis_plus

  1. 操作如下语句,创建数据表,插入数据。
DROP TABLE IF EXISTS USER;CREATE TABLE USER
(id BIGINT(20) NOT NULL COMMENT '主键ID',NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',age INT(11) NULL DEFAULT NULL COMMENT '年龄',email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',PRIMARY KEY (id)
);DELETE FROM USER;INSERT INTO USER (id, NAME, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');-- 真实开发中,version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_modified

如果从零开始用 MyBatis-Plus 来实现该表的增删改查我们需要做什么呢?

  • 导入对应的依赖

  • 研究依赖如何配置

  • 代码如何编写

  • 提高扩展技术能力!


  1. 创建一个空的 Spring Boot 工程(工程将以 H2 作为默认数据库进行演示)

  1. 导入依赖,引入 spring-boot-starterspring-boot-starter-testmybatis-plus-boot-starterh2 依赖:
    <dependencies><!--    数据库驱动    --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--    lombok    --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--    springboot    --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--    mybatis-plus  版本很重要3.0.5    --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.0.5</version></dependency><!--    h2    --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency></dependencies>
  • 说明:我们使用 mybatis-plus 可以节省我们大量的代码,尽量不要同时导入 mybatis 和 mybatis plus!版本的差异!
  1. 连接数据库!这一步和 mybatis 相同!
# mysql 5 驱动不同 com.mysql.jdbc.Driver# mysql 8 驱动不同com.mysql.cj.jdbc.Driver、需要增加时区的配置
serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  1. 传统方式pojo-dao(连接mybatis,配置mapper.xml文件)-service-controller,使用了mybatis-plus 之后:
  • pojo
package com.github.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private Long id;private String name;private String email;private Integer age;
}
  • mapper接口
package com.github.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.github.pojo.User;
import org.springframework.stereotype.Repository;@Repository // 持久层
public interface UserMapper extends BaseMapper<User> {// 无需添加CRUD操作
}
  • 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描Mapper包下的所有接口:
@SpringBootApplication
@MapperScan("com.github.mapper")
public class Mybatisplus01Application {public static void main(String[] args) {SpringApplication.run(Mybatisplus01Application.class, args);}}
  • 测试类中测试:
@SpringBootTest
class Mybatisplus01ApplicationTests {//  继承了 BaseMapper ,所有的方法都来自己父类@Autowiredprivate UserMapper userMapper;@Testvoid contextLoads() {// 参数是一个wrapper,条件是构造器,先使用null// 查询全部用户List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}}

提示:UserMapper 中的 selectList() 方法的参数为 MP 内置的条件封装器 Wrapper,所以不填写就是无任何条件。

  • 控制台输出:

小结一下:

  • 通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能,甚至连 XML 文件都不用编写!
  • 从以上步骤中,我们可以看到集成MyBatis-Plus非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可。

思考问题:

  1. sql谁帮我们写的?—mybatis-plus
  2. 方法谁帮我们写的?—mybatis-plus

3.配置日志

  • 所有的sql现在是不可见的,如果我想知道它是怎么执行的,所以我必须要看日志!
# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

  • 配置完毕日志之后,后面的学习就需要注意这个自动生成的SQL,我们就会喜欢上 MyBatis-Plus!

4.CRUD

1.插入操作

    // 测试插入@Testpublic void insertTest(){User user = new User();user.setName("哇哈哈");user.setAge(22);user.setEmail("2589654784@qq.com");// 自动生成idInteger insert = userMapper.insert(user);// 受影响的行数System.out.println(insert);// 通过日志发现id会自动回填System.out.println(user);}
  • 输出测试:

  • 数据库插入的id的默认值为:全局的唯—id

2.主键生成策略

默认 ID_WORKER 全局唯一id

  • 分布式系统唯一id生成:查看博客园
  • 分布式id生成算法的有很多种,Twitter的SnowFlake就是其中经典的一种。

雪花算法

  • snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。SnowFlake算法生成id的结果是一个64bit大小的整数。
  • 其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!

算法实现

  • Twitter官方给出的算法实现 是用Scala写的,这里不做分析,可自行查看。
/** Copyright 2010-2012 Twitter, Inc.*/
package com.twitter.service.snowflakeimport com.twitter.ostrich.stats.Stats
import com.twitter.service.snowflake.gen._
import java.util.Random
import com.twitter.logging.Logger/*** An object that generates IDs.* This is broken into a separate class in case* we ever want to support multiple worker threads* per process*/
class IdWorker(val workerId: Long, val datacenterId: Long, private val reporter: Reporter, var sequence: Long = 0L)
extends Snowflake.Iface {private[this] def genCounter(agent: String) = {Stats.incr("ids_generated")Stats.incr("ids_generated_%s".format(agent))}private[this] val exceptionCounter = Stats.getCounter("exceptions")private[this] val log = Logger.getprivate[this] val rand = new Randomval twepoch = 1288834974657Lprivate[this] val workerIdBits = 5Lprivate[this] val datacenterIdBits = 5Lprivate[this] val maxWorkerId = -1L ^ (-1L << workerIdBits)private[this] val maxDatacenterId = -1L ^ (-1L << datacenterIdBits)private[this] val sequenceBits = 12Lprivate[this] val workerIdShift = sequenceBitsprivate[this] val datacenterIdShift = sequenceBits + workerIdBitsprivate[this] val timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBitsprivate[this] val sequenceMask = -1L ^ (-1L << sequenceBits)private[this] var lastTimestamp = -1L// sanity check for workerIdif (workerId > maxWorkerId || workerId < 0) {exceptionCounter.incr(1)throw new IllegalArgumentException("worker Id can't be greater than %d or less than 0".format(maxWorkerId))}if (datacenterId > maxDatacenterId || datacenterId < 0) {exceptionCounter.incr(1)throw new IllegalArgumentException("datacenter Id can't be greater than %d or less than 0".format(maxDatacenterId))}log.info("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d",timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId)def get_id(useragent: String): Long = {if (!validUseragent(useragent)) {exceptionCounter.incr(1)throw new InvalidUserAgentError}val id = nextId()genCounter(useragent)reporter.report(new AuditLogEntry(id, useragent, rand.nextLong))id}def get_worker_id(): Long = workerIddef get_datacenter_id(): Long = datacenterIddef get_timestamp() = System.currentTimeMillisprotected[snowflake] def nextId(): Long = synchronized {var timestamp = timeGen()if (timestamp < lastTimestamp) {exceptionCounter.incr(1)log.error("clock is moving backwards.  Rejecting requests until %d.", lastTimestamp);throw new InvalidSystemClock("Clock moved backwards.  Refusing to generate id for %d milliseconds".format(lastTimestamp - timestamp))}if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMaskif (sequence == 0) {timestamp = tilNextMillis(lastTimestamp)}} else {sequence = 0}lastTimestamp = timestamp((timestamp - twepoch) << timestampLeftShift) |(datacenterId << datacenterIdShift) |(workerId << workerIdShift) | sequence}protected def tilNextMillis(lastTimestamp: Long): Long = {var timestamp = timeGen()while (timestamp <= lastTimestamp) {timestamp = timeGen()}timestamp}protected def timeGen(): Long = System.currentTimeMillis()val AgentParser = """([a-zA-Z][a-zA-Z\-0-9]*)""".rdef validUseragent(useragent: String): Boolean = useragent match {case AgentParser(_) => truecase _ => false}
}
  • Java版算法实现:搬运自犀牛饲养员
public class SnowflakeIdWorker {/** 开始时间截 (这个用自己业务系统上线的时间) */private final long twepoch = 1575365018000L;/** 机器id所占的位数 */private final long workerIdBits = 10L;/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */private final long maxWorkerId = -1L ^ (-1L << workerIdBits);/** 序列在id中占的位数 */private final long sequenceBits = 12L;/** 机器ID向左移12位 */private final long workerIdShift = sequenceBits;/** 时间截向左移22位(10+12) */private final long timestampLeftShift = sequenceBits + workerIdBits;/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */private final long sequenceMask = -1L ^ (-1L << sequenceBits);/** 工作机器ID(0~1024) */private long workerId;/** 毫秒内序列(0~4095) */private long sequence = 0L;/** 上次生成ID的时间截 */private long lastTimestamp = -1L;//==============================Constructors=====================================/*** 构造函数* @param workerId 工作ID (0~1024)*/public SnowflakeIdWorker(long workerId) {if (workerId > maxWorkerId || workerId < 0) {throw new IllegalArgumentException(String.format("workerId can't be greater than %d or less than 0", maxWorkerId));}this.workerId = workerId;}// ==============================Methods==========================================/*** 获得下一个ID (该方法是线程安全的)* @return SnowflakeId*/public synchronized long nextId() {long timestamp = timeGen();//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常if (timestamp < lastTimestamp) {throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));}//如果是同一时间生成的,则进行毫秒内序列if (lastTimestamp == timestamp) {sequence = (sequence + 1) & sequenceMask;//毫秒内序列溢出if (sequence == 0) {//阻塞到下一个毫秒,获得新的时间戳timestamp = tilNextMillis(lastTimestamp);}}//时间戳改变,毫秒内序列重置else {sequence = 0L;}//上次生成ID的时间截lastTimestamp = timestamp;//移位并通过或运算拼到一起组成64位的IDreturn ((timestamp - twepoch) << timestampLeftShift) //| (workerId << workerIdShift) //| sequence;}/*** 阻塞到下一个毫秒,直到获得新的时间戳* @param lastTimestamp 上次生成ID的时间截* @return 当前时间戳*/protected long tilNextMillis(long lastTimestamp) {long timestamp = timeGen();while (timestamp <= lastTimestamp) {timestamp = timeGen();}return timestamp;}/*** 返回以毫秒为单位的当前时间* @return 当前时间(毫秒)*/protected long timeGen() {return System.currentTimeMillis();}
}

主键自增

  • 需要配置主键自增:
  1. 实体类字段上 @TableId(type = IdType.AUTO)

  1. 数据库字段一定要是自增!

  1. 再次测试插入!

相关源码解释:

public enum IdType {AUTO(0), // 数据库id自增NONE(1),  // 未设置主键INPUT(2),   // 手动输入ID_WORKER(3),    // 默认的全局唯一idUUID(4),    // 全局唯一id uuidID_WORKER_STR(5); // ID_WORKER 字符串表示法
}

3.更新操作

    // 更新操作@Testpublic void UpdateTest(){User user = new User();// 通过条件自动拼接SQLuser.setId(7L);user.setName("KYDH,开源导航");user.setAge(26);// 注意:updateById的参数是一个对象!Integer i = userMapper.updateById(user);System.out.println(i);}

  • 所有的sql都是自动帮我们动态配置的!

4.自动填充

创建时间、更改时间! 这些操作一般都是自动化完成,我们不希望手动更新。

阿里巴巴开发手册︰几乎所有的表都要配置 gmt_create、gmt_modified !而且需要自动化。

方式一:数据库级别(工作中不允许修改数据库级别)

  1. 在表中增加字段:create_time,update_time

  1. 再次测试插入或更新方法,需要在实体类中同步!
private Date createTime; // 驼峰命名
private Date updateTime;
  1. 查看结果

方式二:代码级别

  1. 删除数据库的默认值,更新操作!

  1. 实体类字段属性上需要增加注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;   // 驼峰命名
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
  1. 编写处理器来处理这个注解即可!
package com.github.handler;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;/*** @author subeiLY* @create 2022-03-04 11:05*/
@Slf4j  // 日志
@Component  // 不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {// 插入时的填充策略@Overridepublic void insertFill(MetaObject metaObject) {log.info("start insert fill......");
//         setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)this.setFieldValByName("createTime",new Date(),metaObject);this.setFieldValByName("updateTime",new Date(),metaObject);}// 更新时的填充策略@Overridepublic void updateFill(MetaObject metaObject) {log.info("start update fill……");this.setFieldValByName("updateTime",new Date(),metaObject);}
}
  1. 测试插入/更新,观察时间

5.乐观锁和悲观锁

乐观锁:顾名思义十分乐观,他总是认为不会出现问题,无论干什么都不上锁!如果出现了问题,再次更新值测试。

悲观锁:顾名思义十分悲观,他总是认为出现问题,无论干什么都会上锁!再去操作!

这里主要讲解:乐观锁机制!

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时,set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
乐观锁:1、先查询,获得版本号 version = 1
-- A
update user set name = "哇哈哈", version = version + 1
where id = 2 and version = 1
-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update user set name = "哇哈哈", version = version + 1
where id = 2 and version = 1

测试一下Mybatis-Plus乐观锁插件

  1. 给数据库中增加version字段

  1. 实体类加对应的字段
    @Version // 乐观锁Version注解private Integer version;
  1. 注册组件
package com.github.config;import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;// 扫描 mapper 文件夹
@MapperScan("com.github.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {// 注册乐观锁插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}
}
  1. 测试一下:
// 测试乐观锁
@Test
public void testOptimisticLocker(){// 1.查询用户信息User user = userMapper.selectById(1L);// 2.修改用户信息user.setName("金顶");user.setEmail("2451367@qq.com");// 3.执行更新操作userMapper.updateById(user);
}// 测试乐观锁失败!多线程下
@Test
public void testOptimisticLocker2(){// 线程 1User user = userMapper.selectById(1L);user.setName("夸父1");user.setEmail("2451367@qq.com");// 模拟另外一个线程执行了插队操作User user2 = userMapper.selectById(1L);user2.setName("夸父2");user2.setEmail("2451367@qq.com");userMapper.updateById(user2);// 自旋锁来多次尝试提交!userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值!
}

6.查询操作

    // 查询测试@Testpublic void SelectByIdTest(){User user = userMapper.selectById(1L);System.out.println(user);}// 批量查询@Testpublic void SelectByBatchIdTest(){List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));users.forEach(System.out::println);}// 按条件查询之一使用map操作@Testpublic void SelectByBatchIds(){HashMap<String, Object> map = new HashMap<>();// 自定义查询map.put("name","哇哈哈");map.put("age",22);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println);}

7.分页查询

分页在网站使用的十分之多!

  1. 原始的 limit 进行分页
  2. pageHelper 第三方插件
  3. MP 其实也内置了分页插件!

具体使用:

  1. 配置拦截器组件即可!
// 扫描 mapper 文件夹
@MapperScan("com.github.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {// 注册乐观锁插件@Beanpublic OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor();}// 分页插件@Beanpublic PaginationInterceptor paginationInterceptor(){return new PaginationInterceptor();}}
  1. 直接使用Page对象即可!
    // 分页查询@Testpublic void testPage(){// 参数一 current:当前页   // 参数二 size:页面大小// 使用了分页插件之后,所有的分页操作都变得简单了Page<User> page = new Page<>(2,5);userMapper.selectPage(page,null);page.getRecords().forEach(System.out::println);System.out.println("总页数==>"+page.getTotal());}

8.删除操作

根据 id 删除记录

    // 基本删除操作@Testpublic void DeleteTest(){userMapper.deleteById(14993819200198L);}// 通过id批量删除@Testpublic void DeleteByIdTest(){userMapper.deleteBatchIds(Arrays.asList(14993819200199L,6));}

通过map删除

    // 通过Map删除@Testpublic void DeleteMapTest(){HashMap<String, Object> map = new HashMap<>();map.put("name","KYDH,开源导航");userMapper.deleteByMap(map);}

9.逻辑删除

物理删除 :从数据库中直接移除;

逻辑删除 :再数据库中没有被移除,而是通过一个变量来让他失效! deleted = 0 => deleted = 1;

  • 管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!

测试一下

  1. 在数据表中增加一个 deleted 字段

  1. 实体类中增加属性
    @TableLogic // 逻辑删除private Integer deleted;
  1. 配置
    // 逻辑删除组件@Beanpublic ISqlInjector sqlInjector(){return new LogicSqlInjector();}
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

4.测试!

  • 走的是更新,不是删除操作!记录依旧在数据库,但是值确已经变化了!

  • 以上的所有CRUD操作及其扩展操作,都必须精通掌握!会大大提高你的工作和写项目的效率!

5.性能分析插件

  • 在平时的开发中,会遇到一些慢sql。测试! druid,
  • 作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间
  • MP也提供性能分析插件,如果超过这个时间就停止运行!
  1. 导入插件
    // SQL执行效率插件@Bean@Profile({"dev","test"})// 设置 dev test 环境开启,保证我们的效率public PerformanceInterceptor performanceInterceptor() {PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();// ms设置sql执行的最大时间,如果超过了则不执行performanceInterceptor.setMaxTime(100);// 是否格式化代码performanceInterceptor.setFormat(true);return performanceInterceptor;}
  • 注意:要在SpringBoot中配置环境为dev或者 test 环境!
# 设置开发环境
spring.profiles.active=dev
  1. 测试一下!
    @Testvoid contextLoads() {// 参数是一个wrapper,条件是构造器,先使用null// 查询全部用户List<User> users = userMapper.selectList(null);users.forEach(System.out::println);}

  • 使用性能分析插件,可以帮助我们提高效率!

6.条件构造器Wrapper

测试一

    @Testvoid contextLoads2() {// 查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.isNotNull("name").isNotNull("email").ge("age",12);userMapper.selectList(wrapper).forEach(System.out::println); // 与map对比一下}

测试二

    @Testvoid test2(){// 查询名字JackQueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("name","Jack");User user = userMapper.selectOne(wrapper); // 查询一个数据,出现多个结果使用List或者MapSystem.out.println(user);}

测试三

@Test
void test3(){// 查询年龄在 20 ~ 30 岁之间的用户QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.between("age",20,30); // 区间Integer count = userMapper.selectCount(wrapper); // 查询结果数System.out.println(count);
}

测试四

// 模糊查询
@Test
void test4(){// 查询年龄在 20 ~ 30 岁之间的用户QueryWrapper<User> wrapper = new QueryWrapper<>();// 左和右 t%wrapper.notLike("name","e").likeRight("email","t");List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);maps.forEach(System.out::println);
}

测试五()

    @Testpublic void testWrapper5() {//模糊查询// SELECT id,name,age,email,version,deleted,create_time,update_time// FROM user// WHERE deleted=0 AND id IN// (select id from user where id<5)QueryWrapper<User> wrapper = new QueryWrapper<>();// id 在子查询中查出来wrapper.inSql("id","select id from user where id<5");List<Object> objects = userMapper.selectObjs(wrapper);objects.forEach(System.out::println);}

测试六

@Test
public void testWrapper6() {QueryWrapper<User> wrapper = new QueryWrapper<>();// 通过id进行降序排序wrapper.orderByDesc("id");List<User> userList = userMapper.selectList(wrapper);userList.forEach(System.out::println);
}

7.代码自动生成器

  • AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller等各个模块的代码,极大的提升了开发效率。

旧版测试:

package com.github;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;import java.util.ArrayList;/*** 代码自动生成器* @author subeiLY*/
public class WskCode {public static void main(String[] args) {// 构建一个代码生成器对象AutoGenerator mpg = new AutoGenerator();// 如何去执行,配置策略// 1、全局配置GlobalConfig gc = new GlobalConfig();// 获取当前目录String projectPath = System.getProperty("user.dir");// 输出到哪个目录gc.setOutputDir(projectPath+"/src/main/java");gc.setAuthor("github");gc.setOpen(false);// 是否覆盖gc.setFileOverride(false);// 去Service的I前缀gc.setServiceName("%sService");gc.setIdType(IdType.ID_WORKER);gc.setDateType(DateType.ONLY_DATE);gc.setSwagger2(true);mpg.setGlobalConfig(gc);// 2、设置数据源DataSourceConfig dsc = new DataSourceConfig();dsc.setUsername("root");dsc.setPassword("root");dsc.setUrl("jdbc:mysql://localhost:3306/github?useSSL=false&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8");dsc.setDriverName("com.mysql.cj.jdbc.Driver");dsc.setDbType(DbType.MYSQL);mpg.setDataSource(dsc);// 3、包的配置PackageConfig pc = new PackageConfig();pc.setModuleName("study");pc.setParent("com.github");pc.setEntity("pojo");pc.setMapper("mapper");pc.setService("service");pc.setController("controller");mpg.setPackageInfo(pc);// 4、策略配置StrategyConfig strategy = new StrategyConfig();// 设置要映射的表名,只需改这里即可strategy.setInclude("admin","Banyan","building","room");strategy.setNaming(NamingStrategy.underline_to_camel);strategy.setColumnNaming(NamingStrategy.underline_to_camel);// 是否使用lombok开启注解strategy.setEntityLombokModel(true);strategy.setLogicDeleteFieldName("deleted");// 自动填充配置TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);TableFill gmtUpdate = new TableFill("gmt_update", FieldFill.INSERT_UPDATE);ArrayList<TableFill> tableFills = new ArrayList<>();tableFills.add(gmtCreate);tableFills.add(gmtUpdate);strategy.setTableFillList(tableFills);// 乐观锁配置strategy.setVersionFieldName("version");// 开启驼峰命名strategy.setRestControllerStyle(true);// localhost:8080/hello_id_2strategy.setControllerMappingHyphenStyle(true);mpg.setStrategy(strategy);mpg.execute(); // 执行}
}

新版测试

  • 导入依赖
        <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>
  • java
package com.github;import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;import java.util.Collections;// 代码生成器(新版)
public class QuaryCode {public static void main(String[] args) {FastAutoGenerator.create("url", "username", "password").globalConfig(builder -> {builder.author("subei") // 设置作者.enableSwagger() // 开启 swagger 模式.fileOverride() // 覆盖已生成文件.outputDir("D://"); // 指定输出目录}).packageConfig(builder -> {builder.parent("com.github.mybatisplus.samples.generator") // 设置父包名.moduleName("system") // 设置父包模块名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "D://")); // 设置mapperXml生成路径}).strategyConfig(builder -> {builder.addInclude("t_simple") // 设置需要生成的表名.addTablePrefix("t_", "c_"); // 设置过滤表前缀}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板.execute();}
}

8.多数据源

  • 适用于多种场景:纯粹多库、 读写分离、 一主多从、混合模式等。
  • 目前我们就来模拟一个纯粹多库的一个场景,其他场景类似。
  • 场景说明:
    • 创建两个库,分别为:mybatis_plus(以前的库不动)与mybatis_plus_1(新建);
    • 将mybatis_plus库的product表移动到mybatis_plus_1库,这样每个库一张表;
    • 通过一个测试用例分别获取用户数据与商品数据,如果获取到说明多库模拟成功。

创建数据库mybatis_plus_1和表product

CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
use `mybatis_plus`;
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT '主键ID',
`name` varchar(30) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
CREATE DATABASE `mybatis_plus_1` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;
use `mybatis_plus_1`;
CREATE TABLE product
(id BIGINT(20) NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',price INT(11) DEFAULT 0 COMMENT '价格',version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',PRIMARY KEY (id)
);# 添加测试数据
INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);# 删除mybatis_plus库product表
use mybatis_plus;
DROP TABLE IF EXISTS product;

新建一个spring boot项目,引入依赖:

<dependencies><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.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

配置多数据源

spring:# 配置数据源信息datasource:dynamic:# 设置默认的数据源或者数据源组,默认值即为masterprimary: master# 严格匹配数据源,默认false.true未匹配到指定数据源时抛异常,false使用默认数据源strict: falsedatasource:master:url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rootslave_1:url: jdbc:mysql://localhost:3306/mybatis_plus_1?characterEncoding=utf-8&useSSL=falsedriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: root

创建实体类

@Data // lombok注解
@TableName("user")
public class User {@TableFieldprivate Long id;private String name;private Integer age;private String email;
}
@Data
public class Product {private Integer id;private String name;private Integer price;private Integer version;
}

创建mapper

@Repository
public interface UserMapper extends BaseMapper<User> {}
@Repository
public interface ProductMapper extends BaseMapper<Product> {}

启动类

@SpringBootApplication
@MapperScan("com.github.mapper")
public class MybatisPlusDatasourceApplication {public static void main(String[] args) {SpringApplication.run(MybatisPlusDatasourceApplication.class, args);}}

创建用户service

public interface UserService extends IService<User> {}
@DS("master") //指定所操作的数据源
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

创建商品service

public interface ProductService extends IService<Product> {}
@DS("slave_1")
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {}

测试

@SpringBootTest
class MybatisPlusDatasourceApplicationTests {@Autowiredprivate UserService userService;@Autowiredprivate ProductService productService;@Testpublic void testDynamicDataSource(){System.out.println(userService.getById(1L));System.out.println(productService.getById(1L));}}

9.MyBatisX插件

MyBatis-Plus为我们提供了强大的mapper和service模板,能够大大的提高开发效率。但是在真正开发过程中,MyBatis-Plus并不能为我们解决所有问题,例如一些复杂的SQL,多表联查,我们就需要自己去编写代码和SQL语句,我们该如何快速的解决这个问题呢,这个时候可以使用MyBatisX插件MyBatisX一款基于 IDEA 的快速开发插件,为效率而生。

  • MyBatisX插件用法:https://baomidou.com/pages/ba5b24

安装方法:打开 IDEA,进入 File -> Settings -> Plugins -> Browse Repositories,输入 mybatisx 搜索并安装。

功能

  • XML 跳转

  • 生成代码(需先在 idea 配置 Database 配置数据源)

  • 重置模板

JPA 提示

  • 生成新增

  • 生成查询

  • 生成修改

  • 生成删除

狂神说笔记——MyBatisPlus快速入门24相关推荐

  1. mybatis学习笔记——mybatis-plus快速入门

    一.快速入门 MyBatis-plus (简称mp)是一款 Mybatis 增强工具,用来简化开发.增强效率.本文结合Spring Boot来实现mp的快速入门. 注:本文演示mp版本为当前最新的3. ...

  2. 狂神说笔记——SpringCloud快速入门23

    1.前言 学习前提 熟练使用SpringBoot 微服务快速开发框架 了解过Dubbo + Zookeeper 分布式基础 电脑配置内存不低于8G(个人是16G) SpringCloud五大组件 参考 ...

  3. 第 1 章 MybatisPlus 快速入门

    第 1 章 MybatisPlus 快速入门 1.MybatisPlus 概述 MybatisPlus:一款 Mybatis 的增强工具包 MybatisPlus 官网:https://mybatis ...

  4. Kubernetes CKA认证运维工程师笔记-Docker快速入门

    Kubernetes CKA认证运维工程师笔记-Docker快速入门 1. Docker 概念与安装 1.1 Docker 是什么 1.2 Docker 基本组成 1.3 版本与支持平台 1.4 Do ...

  5. 史上最简单的mybatis-plus快速入门

    mybatis-plus快速入门 介绍: Mybatis-Plus(简称MP)是一个Mybatis的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发,提高效率而生. 数据库表: -- 创 ...

  6. MyBatis-Plus快速入门-(干货满满+超详细)

    文章目录 一.MyBatis VS JPA 二.MyBatis-Plus简介 三.MyBatis-Plus快速入门 1.lombok简介及安装 2.入门小案例 四.基本使用 1.通用传统模式简介及通用 ...

  7. GEE(Google Earth Engine) 代码学习笔记一 快速入门

    GEE 代码学习笔记一 (GEE 基于JavaScript语言和python语言,我记录的是JavaScript语言) 1.GEE 快速入门 quick start. 2.基本语句 - 简单输出 pr ...

  8. 学习笔记:快速入门ZooKeeper技术

    学习视频:黑马程序员 ZooKeeper 视频教程,快速入门 ZooKeeper 技术 学习资料:黑马程序员 公众号提供的文档资料链接 | 提取码:dor4) 本文最后更新于 2022-04-25,若 ...

  9. 阿里开放搜索opensearch+java+mybatis-plus快速入门

    目录 介绍 快速入门 接口文档 1.添加依赖(一般都用这个方法进行opensearch SDK的添加) 2.1.推送数据 2.2.查看数据是否推送成功 2.3控制台测试搜索 3.搜索 进阶 前置说明 ...

最新文章

  1. WM8962 HPOUT 信号强度 时间周期
  2. Python处理千万级数据
  3. html自动图片尺寸,关于html:CSS背景图像适合宽度,高度应按比例自动缩放
  4. HTTP协议扫盲(一)HTTP协议的基本概念和通讯原理
  5. python 实现的键盘记录器 小功能
  6. mysql连接自己的ip地址_mysql 连接字符串 远程连接用IP地址 而非只是localhost时
  7. 8岁小学生表白遭拒:被一部iPhone打败
  8. 前端宽度一至显示宽度不一致_便利店装修注意事项,你确定不看看?
  9. Java高级程序员面试大纲——备战金三银四跳槽季
  10. IDEA 如何根据代码自动生成类图
  11. 2022 XbotPark(冬季)科创训练营重庆明月湖站总结
  12. android应用程序在哪找,找不到应用程序的错误android
  13. java计算工作日(包含法定节假日和调休)
  14. 【程序员读论文】题外篇:怎么读论文
  15. 英语四级——常考语法【不断更新中】
  16. 聚观早报 | 百度文心一言被用户挤爆;贝莱德准备竞购瑞信
  17. 【华为OD机试真题 python】连续出牌数量【2022 Q4 | 200分】
  18. 日语口语1.13 ジェトロの山本さんから部長のことをお伺いまして
  19. 16*32点阵c语言,16*32点阵的原理
  20. 人工智能——归结推理

热门文章

  1. Greenplum性能调试记录
  2. encodeURI和 encodeURIComponent 的作用及应用
  3. 小巧实用的音视频剪辑软件合集
  4. 德国奔驰将自主研发车载系统MB.OS,对抗Tesla
  5. Drupal主题开发指南(5.x)
  6. 车道线检测:ultra fast lane detection + 车道保持
  7. 零基础学c语言职坐标,C语言自学入门|最全基础知识总结!
  8. R语言循环、连续检验
  9. UiUPay三方支付 对接彩虹易支付插件
  10. (读书笔记)《玩着玩着就能成为ppt高手》——怎样才是一个“精彩的ppt”