# MyBatisPlus
Mybatis 的升级,节省我们大量的工作时间,所有 CRUD 代码它都可以自动化
# 官方文档 (opens new window)
简介
是什么? MyBatis 是简化 JDBC 操作,它是简化 Mybatis 的操作
特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
# 快速入门
- 创建数据库,导入数据
- IDEA 创建 Springboot 项目
- 导入依赖
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
<!--Mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
4.配置文件连接数据库
spring:
datasource:
username: 用户名
password: "密码"
#数据库 8.0及以上的链接方式
url: jdbc:mysql://127.0.0.1:3306/数据库名?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
#数据库8.0及以上驱动
driver-class-name: com.mysql.cj.jdbc.Driver
5.mybatis-plus 的步骤:
- 创建实体类
- 创建 Mapper 接口
- 继承 BaseMapper 接口
//实体类
public class User {
}
//mapper接口
//在对应的Mapper接口上面继承基本的类 BaseMapper<T>
@Mapper //能够让Mybatis找到该接口
@Repository//创建一个该接口的实现类并交给springboot管理 可有可无
public interface UserMapper extends BaseMapper<User> {
}
@SpringBootTest
class MybatisPlusApplicationTests {
@Resource
UserMapper userMapper;
@Test
void contextLoads() {
//参数是一个wrapper.条件构造器,可以传null
//查询全部用户
List<User> users = userMapper.selectList(null);
for (User user : users) {
System.out.println(user);
}
}
}
# 配置日志
看 sql 执行流程
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# CRUD
# 插入
@Test
public void testInsert(){
User user = new User(null,"QZS",18,"22222@qq.com");
int re = userMapper.insert(user);
System.out.println(re); //受影响行数 1
System.out.println(user);//发现Id 自动回填
}
结果:
sql语句:
Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
参数值:
1324912175405109250(Long), QZS(String), 18(Integer), 22222@qq.com(String)
re:
1
user:
User{id=1324912175405109250, name='QZS', age=18, email='22222@qq.com'}
数据库插入的 id 的默认值为: 全局的唯一 id
# 主键生成策略
默认 ID_WORKER 全局唯一 id
分布式系统唯一 id 生成
雪花算法:
snowflake 是 Twitter 开源的分布式 ID 生成算法,结果是一个 long 型的 ID。其核心思想是:使用 41bit 作为毫秒数,10bit 作为机器的 ID(5 个 bit 是数据中心,5 个 bit 的机器 ID),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是 0。

主键自增
我们需要配置主键自增
1.实体类字段上加入@TableId(type = IdType.AUTO )
2.数据库主键字段一定要是自增
其他的生成策略
public enum IdType { AUTO(0), //数据库id自增 NONE(1), //未设置 INPUT(2), //手动输入 需要自己配置id ID_WORKER(3),//默认的全局唯一id UUID(4), //全局唯一id uuid ID_WORKER_STR(5);//ID_WORKER 字符串表示法
# 更新操作
//第一次
public void testUpdate(){
User user = new User(1324912175405109250L,"QZS11",20,"22222@qq.com");
int re = userMapper.updateById(user);
System.out.println(re);
}
//第二次
public void testUpdate(){
User user = new User();
user.setId(1324912175405109250L);
user.setName("1111");
int re = userMapper.updateById(user);
System.out.println(re);
}
结果:
//第一次
UPDATE user SET name=?, age=?, email=? WHERE id=?
//第二次
UPDATE user SET name=? WHERE id=?
发现:所有的 sql 都是自动帮你动态配置的!
# 自动填充
创建时间、修改时间 这些个操作一遍都是自动化完成,不希望手动完成
方式一: 数据库级别
- 在表中新增字段 create_time,update_time
- 设置默认时间戳 和 更新时间戳
- 更新实体类
- 测试
方式二: 代码级别
删除设置的默认时间戳 和 更新时间戳
在实体类上加上注解
@TableField(fill = FieldFill.INSERT) //执行更新操作时 private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) //执行 更新和修改操作时 private Date updateTime;编写处理器来处理这个注解即可!
@Component //将处理器加入到IOC容器中 public class MyMetaObjectHandler implements MetaObjectHandler { //插入是的填充策略 @Override public void insertFill(MetaObject metaObject) { System.out.println("inset ....."); //setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) //字段名, 字段值,要给哪个数据处理 this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } //更新时的填充策略 @Override public void updateFill(MetaObject metaObject) { System.out.println("update ....."); this.setFieldValByName("updateTime",new Date(),metaObject); } }
# 乐观锁
乐观锁 : 总是认为不会出现问题,无论干什么都不会上锁,一旦出现问题,就再次更新值测试
悲观锁: 总认为会出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
- 数据库增加字段 version 默认值为 1
- 实体类增加属性 version 并加上乐观锁注解@Version
- 注册组件
3.0.5 版本
//mybatis-plus 3.0.5 的方式
@Configuration //配置类
public class MybatisPlusConfig{
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
3.4.0 版本
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 乐观锁配置
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
# 查询
@Test
public void testQuery(){
User user = userMapper.selectById(1L); //id查询
System.out.println(user);
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));//多用户id查询
for (User user1 : users) {
System.out.println(user1);
}
HashMap<String,Object> map = new HashMap<String,Object>();
map.put("name","1213123");
List<User> users1 = userMapper.selectByMap(map); //map查询
System.out.println(users1);
}
# 分页查询
1.配置拦截器组件
3.0.5 版本
public class MybatisPlusConfig{
//注册分页插件 3.0.5
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
3.4.0 版本
@Configuration
public class MybatisPlusConfig {
/**
* 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
return interceptor;
}
@Bean
public ConfigurationCustomizer configurationCustomizer() {
return configuration -> configuration.setUseDeprecatedExecutor(false);
}
}
# 删除
和查询基本相同
# 逻辑删除
物理删除: 从数据库中直接移除
逻辑删除: 在数据库中没有删除,而是通过一个变量来让他失效
管理员可以查看被删除的记录!防止数据的丢失类似回收站!
增加一个字段 deleted 默认值为 0 不要和数据库关键字 delete 冲突
实体类中增加属性并加上逻辑删除注解@TableLogic
@TableLogic //逻辑删除 private Integer deleted;配置逻辑删除组件
3.0.5 版本
@Bean public ISqlInjector sqlInjector(){ return new LogicSqlInjector(); }在配置文件中配置一下
mybatis-plus: global-config: db-config: logic-delete-value: 1 #删除 logic-not-delete-value: 0 #未删除3.4.0 版本
步骤 3 不需要
测试
@Test public void testDelete(){ userMapper.deleteById(1324912175405109250L); } 结果: sql语句: UPDATE user SET deleted=1 WHERE id=? AND deleted=0 参数:1324912175405109250(Long) 返回值:1 一条数据被影响 再查询改条记录: sql语句: SELECT id,name,age,email,create_time,update_time,version,deleted FROM user WHERE id=? AND deleted=0 参数:1324912175405109250(Long) 总数: 0 没有查找到结论:
逻辑删除走的是更新操作而不是删除操作
该插件查询的时候会自动过滤被逻辑删除的字段
# 性能分析插件
3.0.5 版本
导入插件
@Bean @Profile({"dev","test"})//选择设置的项目环境 基本上都是 开发dev 和 测试test 环境 public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor per = new PerformanceInterceptor(); per.setMaxTime(100); //sql执行的最大时间 per.setFormat(true); //sql 是否格式化输出 return per; }
3.4.0 版本
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 条件构造器
十分重要 Wapper 作用类似动态 sql
不用自己手写 如 like is between 这种
wapper 这个类封装这些 sql 关键字
# 代码生成器
导入依赖
<!--Mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>版本</version>
</dependency>
<!--如果上面这个版本是3.0.5之后的就必须导入下面这个-->
<!--建议导入上面jar包时查看有没有包含下面这个没有就导入-->
<!--代码生成器依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.0</version>
</dependency>
<!-- 模板引擎 依赖-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>版本</version>
</dependency>
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;
//代码自动生成器
public class AutoCode {
public static void main(String[] args) {
//自动生成器对象
AutoGenerator mpg = new AutoGenerator();
//1.全局配置
GlobalConfig gc = new GlobalConfig();
//获取当前系统目录
String project = System.getProperty("user.dir");
//设置输出目录
gc.setOutputDir(project+"/src/main/java");
//设置作者名字
gc.setAuthor("qzs");
//是否打开资源管理器
gc.setOpen(false);
//是否覆盖原来生成的文件
gc.setFileOverride(false);
//设置服务名字
gc.setServiceName("%sService");//去Service的I前缀
//设置生成策略
gc.setIdType(IdType.ID_WORKER);
//设置日期类型
gc.setDateType(DateType.ONLY_DATE);
//是否配置swagger
gc.setSwagger2(true);
//将 全局配置 配置到自动生成器对象中
mpg.setGlobalConfig(gc);
//2.配置数据源
DataSourceConfig dsc = new DataSourceConfig();
//url
dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mybatis_plus?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8");
//用户名
dsc.setUsername("root");
//密码
dsc.setPassword("991106");
//驱动
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
//数据库类型
dsc.setDbType(DbType.MYSQL);
//将 数据源 配置到自动生成器对象中
mpg.setDataSource(dsc);
//3.包配置
PackageConfig pc = new PackageConfig();
//模块名
pc.setModuleName("blog");
//设置包
pc.setParent("com.qu");
//pojo
pc.setEntity("pojo");
//mapper
pc.setMapper("mapper");
//controller
pc.setController("controller");
//service
pc.setService("service");
//将 包配置 配置到自动生成器对象中
mpg.setPackageInfo(pc);
//4.策略配置
StrategyConfig strategy = new StrategyConfig();
//设置数据库 到文件 命名规则
strategy.setNaming(NamingStrategy.underline_to_camel);
//这是列的命名规则
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//设置要映射的表名
strategy.setInclude("user");
strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
//设置lombok风格
strategy.setEntityLombokModel(true);
//设置逻辑删除
strategy.setLogicDeleteFieldName("deleted");
//设置自动填充
TableFill gmtCreat = new TableFill("gmt_creat", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreat);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
//乐观锁
strategy.setVersionFieldName("version");
//驼峰命名格式
strategy.setRestControllerStyle(true);
//将 策略配置 配置到自动生成器对象中
mpg.setStrategy(strategy);
mpg.execute();
}
}
前提: 把你需要用到底 jar 包提前导入进去 避免生成完成后,代码报错
Mybatis →