MyBatis-plus

▼魔方 西西 提交于 2020-04-07 04:17:59

本篇基于MP 3.3.0 版本 ,spring boot 方式。

MyBatis-plus 简介:

  MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

  支持数据库

  • mysql 、 mariadb 、 oracle 、 db2 、 h2 、 hsql 、 sqlite 、 postgresql 、 sqlserver

  • 达梦数据库 、 虚谷数据库 、 人大金仓数据库

  快速开始

  1. 建立数据库,导入数据
  2. 导入对应的依赖
  3. 编写项目
    1. 配置数据库连接
    2. 编写实体类
    3. 编写Mapper接口继承BaseMapper<T> 即可!至此所有CRUD都已完成
  4. 测试使用

  详细看官网:https://mybatis.plus

 

插入策略

  • 用户ID自动回填
  • 主键生成策略
    • 自增
    • 手动输入
    • UUID
    • 雪花算法
    • 唯一ID生成器
    • 唯一ID生成器(字符串类型)
  • 关于id生成的一些策略:https://www.cnblogs.com/haoxinyue/p/5208136.html

 

  

 

 

 

 1 public enum IdType {
 2    // 自增 
 3    AUTO(0),
 4    NONE(1),
 5    // 手动输入 
 6    INPUT(2), 
 7    // 唯一id生成器,默认策略
 8    ID_WORKER(3),
 9    // uuid
10    UUID(4), 
11    // 唯一id生成器(字符串类型)
12    ID_WORKER_STR(5); }

 

更新策略

  阿里巴巴规范中,id、gmt_create、gmr_update !

 

 

 给数据库表增加两个字段测试

  1. 自动更新策略两种级别
    1. 数据库级别(不建议)
      1. 设置默认值
      2. 插入、更新测试
    2. 代码级别(建议)
      1. 删除更新默认值
      2. 编写实体类对应注解
      3. 编写注解的处理器

  数据库级别

 

 

 

  代码级别

 

 

 

1     @TableField(fill = FieldFill.INSERT)
2     private Date insertTime; // 创建时间
3     @TableField(fill = FieldFill.INSERT_UPDATE)
4     private Date updateTime; // 更新时间

 

 1 package com.coding.handler;
 2 
 3 import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
 4 import org.apache.ibatis.reflection.MetaObject;
 5 import org.springframework.stereotype.Component;
 6 
 7 import java.util.Date;
 8 
 9 @Component
10 public class MyMetaObjectHandler implements MetaObjectHandler {
11     /*
12     * default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) {
13         if (Objects.nonNull(fieldVal) && metaObject.hasSetter(fieldName)) {
14             metaObject.setValue(fieldName, fieldVal);
15         }
16         return this;
17     }*/
18     @Override
19     public void insertFill(MetaObject metaObject) {
20         this.setFieldValByName("insertTime",new Date(),metaObject);
21         this.setFieldValByName("updateTime",new Date(),metaObject);
22     }
23 
24     @Override
25     public void updateFill(MetaObject metaObject) {
26         this.setFieldValByName("updateTime",new Date(),metaObject);
27     }
28 }

 

乐观锁

  • 乐观锁:非常乐观,无论什么操作都不加锁!(思考:分布式环境下怎么解决冲突问题?)
  • 悲观锁:非常悲观,无论什么操作都加锁!默认情况下都是悲观锁!

解决问题

  通常方式就是增加一个乐观锁字段(version)

  当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁实现方式:

  1. 取出记录时,获取当前version (查询)old version = 1
  2. 更新时,带上这个version (更新)
  3. 执行更新时,set version = newVersion where version = old version
    1. 如果version不对应,就更新失败
    2. 对应,就更新成功

MP对乐观锁也进行了支持

  1. 添加version注解到字段上面
  2. 添加乐观锁插件即可
  3. 测试就自动带上了版本号

  详细见:https://mp.baomidou.com/guide/optimistic-locker-plugin.html#%E4%B8%BB%E8%A6%81%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF

 

查询策略

  注:分页查询需要添加以下插件:

 1 //Spring boot方式
 2 @EnableTransactionManagement
 3 @Configuration
 4 @MapperScan("com.baomidou.cloud.service.*.mapper*")
 5 public class MybatisPlusConfig {
 6 
 7     @Bean
 8     public PaginationInterceptor paginationInterceptor() {
 9         PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
10         // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
11         // paginationInterceptor.setOverflow(false);
12         // 设置最大单页限制数量,默认 500 条,-1 不受限制
13         // paginationInterceptor.setLimit(500);
14         // 开启 count 的 join 优化,只针对部分 left join
15         paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
16         return paginationInterceptor;
17     }
18 }

 

 1     // 查询单个
 2     @Test
 3     void testSelectById(){
 4         User user = userMapper.selectById(1L);
 5         System.out.println(user);
 6     }
 7 
 8     // 查询多个
 9     @Test
10     void testSelectBatchIds(){
11         List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
12         users.forEach(System.out::println);
13     }
14 
15     // 查询数量
16     @Test
17     void testSelectCount(){
18         Integer count = userMapper.selectCount(null);
19         System.out.println(count);
20     }
21 
22     // 简单条件查询
23     @Test
24     void testSelectByMap(){
25         Map<String, Object> map = new HashMap<>();
26         map.put("name","zhangsan");
27         map.put("age",18);
28         List<User> users = userMapper.selectByMap(map);
29         users.forEach(System.out::println);
30     }
31 
32     // 分页查询
33     @Test
34     void testSelectPage(){
35         Page<User> page = new Page<>();
36         Page<User> userPage = userMapper.selectPage(page, null);
37         List<User> users = userPage.getRecords();
38         users.forEach(System.out::println);
39         System.out.println(userPage.getSize());
40         System.out.println(userPage.getTotal());
41         System.out.println(userPage.getPages());
42     }

 

删除策略

 1     // 删除一个
 2     @Test
 3     void testDeleteById(){
 4         userMapper.deleteById(1L);
 5     }
 6 
 7     // 删除多个
 8     @Test
 9     void testDeleteBatchIds(){
10         userMapper.deleteBatchIds(Arrays.asList(2L,6L));
11     }
12 
13     // 根据条件删除
14     @Test
15     void testDeleteByMap(){
16         HashMap<String, Object> map = new HashMap<>();
17         map.put("name","Tom");
18         userMapper.deleteByMap(map);
19     }

 

拓展

  • 逻辑删除:并不是真的从数据库中删掉了,只是增加了一个判断而已
    • 业务场景:管理员在后台可以看到被删除的记录,使用逻辑删除可以保证项目的安全和健壮性
  • 物理删除:直接从数据库中删除

逻辑删除使用测试

  1. 添加逻辑删除字段
  2. 在实体类添加注解
  3. 在配置文件进行配置
  4. 注册Bean

 

1     @TableLogic  // 逻辑删除字段注解
2     private Integer deleted;

 

1 # application.yml 加入配置(如果你的默认值和mp默认的一样,该配置可无)
2 mybatis-plus:
3   global-config:
4     db-config:
5       logic-delete-field: flag  #全局逻辑删除字段值 3.3.0开始支持,详情看下面。
6       logic-delete-value: 1 # 逻辑已删除值(默认为 1)
7       logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

 

 1 // 注册 Bean(3.1.1开始不再需要这一步)
 2 
 3 import com.baomidou.mybatisplus.core.injector.ISqlInjector;
 4 import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
 5 import org.springframework.context.annotation.Bean;
 6 import org.springframework.context.annotation.Configuration;
 7 
 8 @Configuration
 9 public class MyBatisPlusConfiguration {
10 
11     @Bean
12     public ISqlInjector sqlInjector() {
13         return new LogicSqlInjector();
14     }
15 }
1     // 逻辑删除,删除一个
2     @Test
3     void testLogicDeleteById(){
4         userMapper.deleteById(1L);
5     }

 

性能分析

  在开发的时候排除慢sql! 

  3.2.0版本以上参考:https://mp.baomidou.com/guide/p6spy.html

  1. 导入p6spy的maven依赖
  2. 在dev环境下配置文件进行配置
  3. spy.properties配置

  3.2.0版本以下参考:https://mp.baomidou.com/guide/performance-analysis-plugin.html

 

条件构造器

  我们平时写的sql,一般使用的最多的是一些条件,这些东西MP也帮助我们提供了

  更多条件查询见官网:https://mp.baomidou.com/guide/wrapper.html#abstractwrapper

 1 package com.coding;
 2 
 3 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 4 import com.coding.mapper.UserMapper;
 5 import com.coding.pojo.User;
 6 import org.junit.jupiter.api.Test;
 7 import org.springframework.beans.factory.annotation.Autowired;
 8 import org.springframework.boot.test.context.SpringBootTest;
 9 
10 @SpringBootTest
11 public class WrapperTest {
12     @Autowired
13     private UserMapper userMapper;
14   // 仅举一例,更多条件查询见官网
15     @Test
16     void testConditionSelect(){
17         QueryWrapper<User> wrapper = new QueryWrapper<>();
18         wrapper.eq("name","zhangsan") // 姓名 = zhangsan
19                 .gt("age",18); // 年龄 > 18
20         userMapper.selectList(wrapper);
21     }
22 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!