一、初识
注:
1、此文基于springboot2.2.5版本,使用Mybatis-Plus3.0.5
2、使用该版本的原因是可以感受Mybatis-Plus的原理,再高版本由注解即可完成,不宜与学习。
1、简洁
MyBatis-Plus(点击进官网)(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
1、特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
二、使用步骤
1、创建一个springboot项目




2、添加mybatis-plus依赖
<!-- 导入mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
3、添加配置文件配置数据源
注:
1、官网推荐使用yml配置文件,创建application.yml,添加数据源配置
2、通过源码分析springboot2.xx以上的版本默认mysql为8.xx版本,8.xx以上的版本url需要加上时区serverTimezone
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnincode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: root
password: 123456
4、application.properties配置日志
用来打印sql执行情况
#配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
5、创建数据库
1、创建数据库mybtis_plus
2、根据官网给出的样例创建User表,插入数据
6、编写pojo
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private int age;
private String email;
}
7、编写dao
1、创建UserMapper 继承BaseMapper
@Repository
public interface UserMapper extends BaseMapper<User> {
}
2、通过源码分析BaseMapper提供了一系列简化的操作,直接调用即可
8、启动类添加扫描dao
@SpringBootApplication
@MapperScan("com.yyrifle.springbootmp.dao")
public class SpringbootMpApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootMpApplication.class, args);
}
}
9、测试
@SpringBootTest
class SpringbootMpApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
}
结果:
完成!!
三、插入策略
1、源码分析主键生成策列
2、源码刨析主键生成策列
1、源码刨析
public enum IdType {
// 自增 (需要保证数据库是自增的,IdType设置为AUTO)
AUTO(0),
// 手动输入
NONE(1),
INPUT(2),
// 唯一id生成器 雪花算法,默认为此算法
ID_WORKER(3),
// uuid
UUID(4),
// 唯一id生成器(字符串类型) 雪花算法,转为字符串
ID_WORKER_STR(5);
}
2、默认
3、使用方法:添加 @TableId注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
//默认为雪花算法
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private int age;
private String email;
}
4、什么是雪花算法
四、更新策略
说明:
1、两种级别:数据库级别,代码级别
2、阿里巴巴规范中,表结构必备三个字段 id、gmt_create、gmt_update 。
1、数据库级别(不推荐 影响效率)
1、新增两个时间字段
2、更新
3、注:高版本的sqlyong表结构里有个“更新”列,如果有则给update_time勾选,代表更新操作的时候自动更新时间为当前时间,如果低版本的没有使用语句更新
ALTER TABLE USER MODIFY update_time TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间';
2、代码级别(建议,项目统一处理时间)
1、删除表结构默认值
2、编写实体类对应的注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private int age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
3、编写注意的处理器
public class MyMetaObjectHandler implements MetaObjectHandler{
//表示插入的时候自动更新字段为当前时间
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("creatTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
//表示更新的时候自动更新更新时间为当前时间
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
4、执行测试

四、乐观锁
1、什么是乐观锁,悲观锁
1、乐观锁:非常乐观,无论什么操作都不加锁。(思考:分布式下如何处理冲突问题呢?)
2、悲观锁:非常悲观,无论什么操作都加索。
思考解答:
分布式下解决冲突的方式就是增加一个乐观锁字段即可(version)
目的是为了确保当要更新一条记录的时候,希望这条记录没有被其他线程更新。
2、乐观锁实现方式
- 查询记录时,获取当前版本(version)
- 更新时带上当前版本(version)
# 线程一:
# 获取当前version , select version = 1
# 被线程2插队
# 线程一:
# 获取 version select version = 1
# 更新 version update set version = 2 wehre version = 1
# 线程一更新 version失败 update set version = 2 wehre version = 1
- 执行更新时,set version = newVersion where version = oldVersion
- 如果version 不对 ,就更新失败
3、MP支持乐观锁
1、添加version
2、添加@version注解到字段上
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private int age;
private String email;
//乐观锁直接 必须要
@Version
private int version;
private Date createTime;
private Date updateTime;
}
3、添加乐观锁插件 ,注入别人写好的bean即可
package com.yyrifle.springbootmp.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MPconfig {
//根据官网 注入别人写好的插件处理器即可
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
4、测试
成功:
失败:

五、查询策略
1、条件查询
//查询
@Test
void testSelectById() {
User user = userMapper.selectById(1266999282910642178L);
System.out.println(user);
}
@Test
void testSelectList() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
@Test
void testSelectBatchIds() {
List<User> users = userMapper.selectBatchIds(Arrays.asList(1,2,3));
users.forEach(System.out::println);
}
@Test
void testSelectCount() {
Integer integer = userMapper.selectCount(null);
System.out.println(integer);
}
@Test
void testSelectByMap() {
HashMap<String,Object> map = new HashMap<>();
map.put("name","Y总");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
2、分页查询 MP内置分页插件 需要先引入插件
@Configuration
public class MPconfig {
//根据官网 注入别人写好的插件处理器即可
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
//引入分页查询
@EnableTransactionManagement
@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
return paginationInterceptor;
}
}
}
3、编写测试
//分页查询 MP内置分页插件 以后做分页使用Page对象即可
@Test
void testSelectMapsPage() {
Page page = new Page(0,2);
userMapper.selectMapsPage(page, null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getCurrent());//当前第几页
System.out.println(page.getSize());//一页多少条
System.out.println(page.getTotal());//总条数
System.out.println(page.hasNext());//是否有下页
System.out.println(page.hasPrevious());//是否有上页
}
4、结果
六、删除策略
1、物理删除

2、逻辑删除
1、添加删除字段
2、实体类字段上加上@TableLogic注解
@TableLogic
private int deleted;
3、加入配置(如果你的默认值和mp默认的一样,该配置可无):
# 配置删除 删除为1 没有删除为0
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4、引入删除插件(3.1.1以上不再需要这一步)
//逻辑删除插件
@Bean
public ISqlInjector iSqlInjector() {
return new LogicSqlInjector();
}
5、测试
六、性能分析
1、目的:在开发的时候排除慢sql!
2、引入插件性能分析插件
//性能分析插件
/**
* SQL执行效率插件
*/
@Bean
@Profile({"dev","test"})// 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
//设置最大sql执行时间
performanceInterceptor.setMaxTime(200);
//format SQL SQL是否格式化,默认false
//performanceInterceptor.setFormat(true);
return performanceInterceptor;
}
3、配置多环境,激活开发环境
4、测试
5、注意!参数说明:
参数:maxTime SQL 执行最大时长,超过自动停止运行,有助于发现问题。
参数:format SQL SQL是否格式化,默认false。
该插件只用于开发环境,不建议生产环境使用。
